Every setting Keryx reads, by the name you set it under. The usual way to set them is
keryx setup (a wizard that asks only for what is missing) or
keryx config set KEY VALUE; keryx config list shows each one with where
its value came from.
Where they live.KERYX_HOME (default $XDG_CONFIG_HOME/keryx, which is
~/.config/keryx, on Linux and macOS alike) holds config.toml for the plain settings and
secrets.toml for the credentials, both readable by you alone. A secret is never put on a
command line: keryx config set KEY --stdin reads it from standard input, and
--from-env VAR from a variable. The PIN is not in either file: it lives beside them in
KERYX_HOME/pin, written once (see SECURITY.md). Keep that directory out of a
dotfiles repository. What Keryx keeps is in DATA_DIR, STATE_DIR and CACHE_DIR, the
XDG data, state and cache directories below.
Which value wins, first to last: the process environment (a systemd Environment=,
say), secrets.toml, config.toml, and the default below. Nothing is read from the
working directory, so a .env there is ignored.
What the running service may change. Keryx can change some of its own settings — the
voice model's set_config tool, or a subagent running keryx config set in a task — and
only those marked yes below, until you say otherwise with keryx config unlock KEY or
keryx config lock KEY. The ones marked never are protected: every credential, and
every setting that is a line of defence (who may call, the approval allowlist, filing
issues in public, spending caps, deletion, the network, the debug switches). Nothing unlocks them.
OpenAI API key with Realtime access. The only setting Keryx cannot start without.
OPENAI_REALTIME_MODEL
gpt-realtime-2.1
no
The realtime speech-to-speech model a call runs on.
ASSISTANT_NAME
Lyra
yes
What the assistant on the phone is called: the name it answers to and introduces itself by. Lyra and Jarvis each bring a voice of their own; any other name — letters, spaces, apostrophes and hyphens, up to 32 — speaks in OPENAI_VOICE, or marin.
OPENAI_VOICE
``
yes
The Realtime voice the assistant speaks in. Empty is the assistant's own (ASSISTANT_NAME); a voice the key's organization may not use makes every call fail to open.
OPENAI_TRANSCRIPTION_MODEL
gpt-4o-mini-transcribe
no
Transcribes what the caller says, for the call log.
TRANSCRIPTION_LANGUAGE
``
yes
The language you speak on a call, as an ISO-639-1 code (en, de, fr), for the call log's transcription — which recall and the memory read. Empty lets the transcriber guess each turn. The voice model itself hears the audio either way.
CLOCK_FORMAT
24h
yes
How the voice prompt writes the time of day (14:05 or 2:05 PM), and so how the assistant tends to say it.
OPENAI_WEB_SEARCH_MODEL
gpt-6-luna
no
Answers the voice model's own web_search tool, through the Responses API (the Realtime API has no hosted search tool).
VAD_MODE
semantic
yes
How the assistant decides you have finished: semantic waits on whether the sentence sounds finished, so a pause to think does not cut you off; server is a plain silence timer of VAD_SILENCE_MS.
VAD_EAGERNESS
medium
yes
Semantic mode only: low waits longest, high jumps in soonest, auto is medium.
VAD_SILENCE_MS
1200
yes
Server mode only: the silence, in milliseconds, that ends a turn.
VAD_THRESHOLD
0.5
yes
Server mode only: how loud counts as speech (0 to 1).
VAD_PREFIX_MS
300
yes
Server mode only: audio kept from before speech was detected, so the first syllable is not clipped.
NOISE_REDUCTION
auto
yes
Background-noise suppression on what the model hears; auto picks near_field for a phone and far_field for a microphone across the room. Mostly about barge-in: noise mistaken for speech is noise that cuts the assistant off.
What the assistant calls you in the prompts it is handed; blank is "the owner". Only a name: the rest of what it knows about you is its memory.
ALLOWED_CALLERS
never
Your phone numbers in E.164 (+15551234567), comma-separated. Every other caller is refused. This is the handsets one person picks up, not a guest list: a call Keryx places to any of them reached you.
OWNER_NUMBER
never
Which of your numbers Keryx rings first; blank is the first of ALLOWED_CALLERS.
KERYX_PIN
(secret)
never
The phone PIN: 6 to 8 digits, asked for before anything is dispatched from a call. Not kept in the configuration files: it lives in KERYX_HOME/pin, written once by keryx setup or by the first call, and this variable, set in the environment, overrides that file. With no PIN anywhere nothing of yours is read out on the phone and every dispatch is refused.
PIN_FAILURE_LIMIT
10
never
Wrong PINs, counted across every call, before PIN entry locks for everyone — the right PIN included.
PIN_FAILURE_WINDOW_HOURS
24
never
How long a wrong PIN is remembered.
PIN_LOCKOUT_MINUTES
60
never
How long PIN entry stays locked once the limit is reached.
BRIEFING_BEFORE_PIN
true
never
Whether a call is handed its standing briefing — unreported results, the memory, project names, briefs, skills — before the PIN. The PIN is the line between reading and acting; off means nothing of yours is said until it is given. Does nothing until a PIN exists.
The Twilio number Keryx answers and calls from, in E.164.
SMS_ENABLED
false
never
Whether Keryx may text at all. Off: many Twilio accounts cannot send SMS in their region, and Slack is the written channel. Outbound calls are unaffected.
PUBLIC_HOST
never
The public hostname Twilio reaches this machine on, e.g. keryx.example.com: the name routed to your tunnel.
CLOUDFLARE_TUNNEL
keryx
never
The Cloudflare tunnel the service runs beside Keryx on Linux (keryx service install, and scripts/dev.sh in a clone).
The Google OAuth client id. Blank: read from GOOGLE_CLIENT_SECRETS_FILE.
GOOGLE_OAUTH_CLIENT_SECRET
(secret)
never
The Google OAuth client secret, with the id above.
GOOGLE_CLIENT_SECRETS_FILE
no
The OAuth client JSON the Google Cloud console downloads (desktop or web shape). Blank: KERYX_HOME/google_client_secret.json, where keryx setup puts it.
USER_GOOGLE_EMAIL
no
The Google account agents act as; keryx setup fills it in from the sign-in.
GOOGLE_WORKSPACE_MCP
false
no
Give every subagent the workspace-mcp server (send mail, manage the calendar). Needed for Codex, which has no claude.ai connectors; Claude already has them.
Spoken project names for repositories outside PROJECTS_ROOT, as {"name": "/path"}.
PROJECTS_ROOT
~/projects
no
Where a task with no project starts; each subdirectory is a project you can name. Never created: without it, such a task starts in DATA_DIR/workspace.
SKILLS_DIR
$CLAUDE_CONFIG_DIR/skills (~/.claude/skills)
never
Where the Claude CLI keeps its skills; listed in the voice prompt so the assistant knows what the subagents are good at.
KERYX_CHECKOUT
no
The Keryx repository on this machine, which a subagent reads when it reports a problem with Keryx. Unset: the checkout Keryx runs from, when it runs from one.
ISSUE_REPORTING
false
never
Whether a bug or a feature request for Keryx, said on a call, may be filed as a GitHub issue by a subagent, with gh. keryx setup asks; only you can turn it on.
ISSUE_REPO
wak31415/keryx
never
The GitHub repository (owner/name) those issues are filed on.
Whether a Claude Code prompt left unanswered on your screen may become a call. The hook is installed separately (keryx approvals --install-hook).
APPROVAL_ESCALATE_SECONDS
300
no
How long a prompt waits on screen before Keryx rings about it.
APPROVAL_CALL_WINDOW_SECONDS
240
no
How long the hook keeps waiting after that. The two together are the longest the hook blocks; its timeout in ~/.claude/settings.json must exceed their sum.
APPROVAL_MAX_PER_HOUR
4
no
Approval calls per hour, however many prompts pile up.
APPROVAL_QUIET_HOURS
yes
HH:MM-HH:MM in which it never rings (may cross midnight), in the host's time.
APPROVAL_BASH_ALLOW
git push,git commit
never
The only shell commands a keypad digit may ever run, matched word for word; only git push and git commit may carry arguments (keryx/approvals/policy.py). This allowlist is the primary control: widening it widens exactly what a phone keypad can execute.
APPROVAL_ROOTS
never
Where a file may be written by phone approval; blank is PROJECTS_ROOT plus every project in PROJECTS.
Skip Twilio's request signatures, for a machine nothing outside can reach. keryx serve refuses the phone with it on behind a PUBLIC_HOST.
DEMO_MODE
false
never
Try the phone before a coding agent is set up: calls, the PIN and call-backs are real, and every task comes back after a moment with a sample answer that says it was a demo. No agent runs and no agent tokens are spent. keryx serve --demo turns it on for one run.