Repository navigation
Command Line Reference
uv run keryx --help lists the commands, and keryx <command> --help lists a command's
flags. uv run keryx --version prints the installed version.
Read-only commands read the stored data directly, so they work even when the server is
stopped. These are tasks, memory, doctor, approvals, restart --status,
config list|get, plugins list|hosts, and tools. They hide INFO logs but still show
warnings. To see every log line, set LOG_LEVEL=DEBUG.
Exit codes are 0 for success, 1 for a failure or a refusal, and 2 for invalid usage.
uv run keryx setup # walk only what is still missing
uv run keryx setup --all # walk every section, and ask again about what is set
uv run keryx setup --agent-instructions # the command-line path, for a coding agentkeryx setup needs a terminal. It reads doctor's checks to decide what's left, saves
each answer as it goes, and remembers which optional sections you've completed. Before it
updates the Twilio webhooks, it shows you both addresses and asks you to confirm. A coding
agent can handle the command-line steps, but you still need to do the browser sign-ins,
the PIN, and the webhook approval yourself.
uv run keryx config list [--json] [--group phone] # every setting, where it comes from
uv run keryx config get PUBLIC_HOST [--shell] # never prints a secret
uv run keryx config set OWNER_NAME "Sam" SMS_ENABLED false
uv run keryx config set TWILIO_AUTH_TOKEN --stdin # a secret: from stdin…
uv run keryx config set OPENAI_API_KEY --from-env OPENAI_API_KEY # …or a variable
uv run keryx config unset KEY… # back to the default
uv run keryx config path [--shell] # every directory; --shell for eval
uv run keryx config import-env [PATH] # move one old .env into the store
uv run keryx config lock KEY | unlock KEY # what the running service may change
uv run keryx migrate [--dry-run] [--yes] # move a Jarvis install (or ~/.jarvis) to KeryxPlain settings go to KERYX_HOME/config.toml, and every secret goes to secrets.toml
beside it. Both are readable only by you. KERYX_HOME is ~/.config/keryx unless you set
the KERYX_HOME environment variable. A secret is refused as a command-line value,
because ps and your shell history would keep it. The process environment wins over both
files, and nothing is read from the working directory. The
settings reference
lists every setting. The PIN isn't a setting: keryx setup or the first call sets it (see
Security Model).
Inside a Keryx task, config set acts as the running service, and may change only the
settings the service is allowed to write. These commands refuse to run inside a task at
all: import-env, migrate, lock, unlock, auth login, memory seed,
plugins install|remove, and setup.
uv run keryx auth status [--json] [--smoke] # every sign-in; --smoke runs one real task per agent
uv run keryx auth login claude # or codex; --headless on a machine with no browser
uv run keryx auth login gmail --client-file ~/Downloads/client_secret.json
uv run keryx auth login gmail --callback-url 'http://localhost:1/?…'
uv run keryx auth login google-workspaceauth status shows a coding agent that isn't in AGENTS_ENABLED as off, not as
missing. With --json, it keeps the agent's state and says enabled: false.
gmail takes two steps. The first prints a link to open on any device, and the second
takes the address the browser landed on. The Gmail sign-in is for the check_email
plugin, which you turn on separately (keryx plugins install check_email). See
Google Workspace MCP for what each Google sign-in is for.
uv run keryx plugins [--json] # the four: on, off or refused, and why; same as `plugins list`
uv run keryx plugins install check_email # turn one on, from its settings file or the defaults
uv run keryx plugins install send_to_slack --set channel_id=D0123456789
uv run keryx plugins install cluster_stats --cluster mycluster=gpu [--guard PATH]
uv run keryx plugins install check_billing --template # write its files to edit; leave it off
uv run keryx plugins install --from-settings # move the settings they replaced; turn on what was offered
uv run keryx plugins remove check_billing [--yes] # off; its settings are kept aside
uv run keryx plugins hosts [--json] # ssh hosts cluster_stats could ask, and whose master is upThe optional voice tools are plugins: send_to_slack, check_email, check_billing,
and cluster_stats. Each is a one-line <name>.py and a commented <name>.toml of its
settings in DATA_DIR/tools/. None is offered until you turn it on. A change doesn't need
a restart; it takes effect from the next call. keryx setup → Plugins does the same
thing by asking you questions.
-
--set KEY=VALUEsets one of a plugin's settings. Repeat it for more. -
--cluster ALIAS=PARTITIONsets the whole[clusters]table forcluster_stats. - A secret is never taken here. Use
keryx config set KEY --stdin, orkeryx auth login gmail. -
installexits 1 if the plugin it turned on would be refused. -
removeasks first, unless you pass--yes. It sets the settings aside as<name>.toml.off, so they're remembered when you turn the plugin on again. -
hostsreads~/.ssh/configand offers only hosts with a ControlMaster. Nothing it does reaches the network.
uv run keryx tools [--json] # what DATA_DIR/tools defines, and what the next call would refusekeryx tools loads the directory the same way a call does, checking against every
built-in tool's name. It lists each tool, whether it needs the PIN, and its file. A file
it refuses is listed with the reason, and the command exits 1 while any file is refused.
The plugins are listed here too, because they're tools of the same kind. See
Custom Tools.
uv run keryx serve # the phone server
uv run keryx serve --demo # try the phone before an agent is set up: tasks get a sample answer
uv run keryx serve --host 0.0.0.0 --port 9000 # override HOST and PORTIf DEBUG_SKIP_TWILIO_VALIDATION is on while PUBLIC_HOST is set, keryx serve
refuses to start the phone channel. See Security Model.
scripts/dev.sh runs the Cloudflare tunnel and keryx serve together. It logs the tunnel
to STATE_DIR/logs/cloudflared.log, and passes any extra flags through to keryx serve.
For a machine that should stay up without a terminal, see Running as a Service.
uv run keryx tasks list # 20 most recent, newest first
uv run keryx tasks list --status running # queued|running|done|failed|cancelled|all
uv run keryx tasks list --limit 50
uv run keryx tasks list --internal # also show Keryx's own housekeeping
uv run keryx tasks show 12 # every field, plus the written reportThe TOLD column stays NO until Keryx has told you the result. Results you haven't
heard come first in the next call, and retention never prunes them. --internal shows
Keryx's own housekeeping tasks, such as the memory update after each call. These tasks are
left out of spoken lists, the start-of-call summary, searches of past calls, the daily
cap, and notifications.
uv run keryx memory # print what Keryx carries between calls
uv run keryx memory --path # just say where the file is
uv run keryx memory seed --file facts.txt # one standing fact per line
printf '%s\n' "…" "…" | uv run keryx memory seed --file - --json
uv run keryx memory seed --file facts.txt --force # replace a memory that has something in itA new install knows nothing about you until an authorized call finishes and updates the
memory. To add that context now, use memory seed or the About you section of
keryx setup. Either writes facts under Standing facts in DATA_DIR/memory.md, and
reports the memory, project briefs, and skills that calls will receive.
memory seed exits 1 without changing the file in two cases:
- a memory already exists, unless you pass
--force; - the result would be longer than the 4,000 characters a call reads.
Set OWNER_NAME with keryx config set OWNER_NAME … or keryx setup. The default is
"the owner".
After each call authorized with the PIN, a subagent updates the memory for the next call. The file is plain Markdown, and you can edit it by hand. Later updates keep your edits.
uv run keryx restart --reason "picked up new code"
uv run keryx restart --status # how the last one went, including what the logs said
uv run keryx restart --force # even while a call is in progress
uv run keryx restart --no-callback # quietly, with no call afterwardskeryx restart restarts the installed unit, and refuses when there's none. See
Restarting Keryx for how Keryx reports on a restart that stops its own process.
uv run keryx approvals # the audit trail: what it escalated and what happened
uv run keryx approvals --limit 5
uv run keryx approvals --disable # kill switch, effective on the next prompt
uv run keryx approvals --enableSee The Approval Bridge.
uv run keryx forget --older-than 30 # asks first
uv run keryx forget --yes # everything eligible, no window
uv run keryx forget --transcripts-only --older-than 7
uv run keryx forget --tasks-only --older-than 90--older-than 0 means everything, and none of it can be undone. You can't combine
--transcripts-only and --tasks-only. A finished task you haven't been told about yet
is never deleted, by this command or by automatic pruning. See Data and Retention.
uv run keryx doctor # is this machine set up?
uv run keryx doctor --json # every check, with its section and state
uv run keryx doctor --fix # tighten secret files to owner-only, nothing else
uv run keryx loopback --wav sample.wav # one session from a WAV filedoctor exits non-zero only on a hard failure, so you can use it in a check script.
Each check carries the keryx setup section that would fix it, and a state:
-
ok; -
missing— nothing configured yet; -
failed— configured, but not working.
loopback is the development harness for the realtime provider. It plays a 16-bit WAV to
the model, and with --out it writes the reply audio to a file.
-
Troubleshooting — what
doctorchecks and where to look when something misbehaves.
User documentation for Keryx.
For the threat model, see SECURITY.md;
for settings, the coding agents, and the tools, see docs/.
Apache-2.0, Copyright 2026 William Koch.
Setting up
Running it
Security and data
Tools and advanced features