Configuration Files
Heph reads two TOML files and merges them, project over user.
| File | Scope |
|---|---|
~/.config/heph/config.toml | You, on every project. $XDG_CONFIG_HOME/heph/config.toml if that variable is set. |
.heph/config.toml | This project. Check it in if the team shares gates and permissions. |
Both are optional. With neither, heph finds a provider in the environment and
writes the user file on its first run
(The First Run). An explicit ollama/ model
instead discovers that server and bootstraps absent routing without writing
config; see Providers. --user-config FILE and
--project-config FILE select other read and write destinations. Overriding one
leaves the other layer at its default path.
The sections
| Section | What it configures | Chapter |
|---|---|---|
[providers] | How to reach a model endpoint | Providers |
[profiles] | Named sets of tiers: which model does which work | Tiers |
[tiers] | The profile default, written whole | Tiers |
[permissions] | What runs without asking, what never runs | Permissions |
[permissions.repeat] | Soft and hard repeated-call checkpoints | Permissions |
[locks] | Exclusive named execution resources | Execution Locks |
[network] | Which hosts web_fetch reaches without asking | Network |
[[gates]] | Commands that must pass before review | Gates |
[review] | How you review | Review |
[worktree] | What is copied into the worktree, what is linked | Worktree |
[toolsets] | Named read-only tool lists for plan turns | Tool Sets |
[design] | Where design turns may write | Design Turns |
[notify] | Which events leave the pane, and how | Notifications |
[input] | Attachments, ! commands, the clipboard | Input |
[ui] | Image display | UI |
[context] | What of the conversation each round carries | Context |
[decisions] | Decision and command-output policy | Tiers |
[skills] | Which discovered skills the model may see | Skills |
[git] | Which branch conversations start from | Git |
A section heph does not know is accepted and ignored, so a file written for a later heph still loads. A key it does not know inside a section it does know is an error, so a typo is caught rather than silently ignored.
[locks] configures exclusive execution resources, separately from
permissions.
How the two files merge
Merging is by section, and each section merges the way that makes sense for it:
-
[providers]and[tiers]: by name. A tier named in both files is the project's whole entry. A provider named in both files is also replaced whole, including Ollama settings and model overrides. -
[profiles]: by name, then field by field: a project profile'sextendsand each tier field it writes replace yours, and the rest of yours is kept.default_profileis the project's when its file sets it. -
[permissions]: the lists concatenate. Projectdenypatterns are added to yours, never replace them. A project[permissions.repeat]table replaces the user's limit pair as a unit; omitted keys in that table use defaults. -
[locks]: by name, appending project patterns to user patterns and deduplicating identical entries. An empty project array cannot remove a user requirement. This policy is a startup snapshot; restart to change it. -
[decisions]: field by field. Each project key overrides the user key; omitted keys retain user policy values.command-output-commandsreplaces the whole user argv-contract list, including with an empty list. Native progress is experimental; command-output visibility is opt-in. Other decision hooks remain unavailable. -
[network]: the host lists concatenate;defaultsis the project's when its file sets it. -
[[gates]]: concatenate, user gates first. -
[toolsets]: by name; a project set replaces a user set of the same name. -
[design]: whole. A project file's[design]replaces yours. -
[skills]: thedisabledlists concatenate, like[permissions], so a project can disable more skills, never fewer.projectis read only from the user file; a project file that sets it fails to load. -
[review],[worktree],[notify],[input],[ui],[context],[git]: field by field. A key the project file sets wins; a key it leaves out keeps your value. Since TOML cannot say "unset", a project file cannot remove a key you set, only give it another value.[worktree] linklists concatenate.
A complete example
The user file, for someone with both an API key and Bedrock:
[providers.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
[providers.bedrock]
region = "us-west-2"
[tiers.frontier]
models = ["bedrock/us.anthropic.claude-opus-5", "anthropic/claude-opus-5"]
roles = ["coding", "review"]
[tiers.workhorse]
models = ["anthropic/claude-sonnet-4-6"]
roles = ["research", "summarize"]
[tiers.fast]
models = ["anthropic/claude-haiku-4-5-20251001"]
roles = ["quick", "commit-message", "title", "progress-check"]
max_tokens = 2048
[review]
interactive = "lazygit"
[notify]
command = "notify-send 'heph {project}/{ref}' '{message}'"
A project file, checked in:
[permissions]
approve = ["exec(cargo) args(*)"]
deny = ["edit(Cargo.lock)", "exec(git) args(push *)"]
[[gates]]
name = "check"
paths = ["**/*.rs", "Cargo.toml"]
command = "cargo check --all-targets 2>&1"
[[gates]]
name = "test"
paths = ["**/*.rs"]
command = "cargo test 2>&1"
retry_limit = 2
[worktree]
link = ["node_modules"]
Editing live configuration
Native Ollama edits reuse startup discovery only for the same provider ID and normalized endpoint. Permission edits need no network discovery; model limits and capability restrictions are validated anew. A different server or an undiscovered model cannot borrow that snapshot. Configure those outside the live editor and restart to discover them before using live edits.
Config is live project or user state, not conversation source state. Reads and
writes use the original files, even from a shadow worktree and even if .heph/
is ignored by Git. If the config is tracked, saving leaves an ordinary
uncommitted change in the original checkout; it does not publish a commit.
A on an ordinary permission prompt appends the edited pattern or host to
[permissions] promoted or [network] promoted in the effective project
config. The heading names the destination, including --project-config.
Comments and unrelated formatting survive. If saving fails, the approval is
explicitly session-only.
For other changes, ask the agent to use config_view, then config_edit. Both
accept target = "project" (the default) or "user". The edit supplies the
complete current file as old and the complete proposed file as new. Its
once-only permission prompt shows the actual path and before/after text. It
always asks, including with --yes, --yes-really, remembered patterns, or
--accept-edits. Generic edit, create, and search_replace cannot edit
heph config in the shadow. Plan and design turns cannot call config_edit.
Writes validate TOML, config types, project trust, and merged model settings,
then atomically replace the file. Concurrent heph writes serialize; a stale
old refuses the edit instead of overwriting another change. The writer keeps
sidecar .toml.lock files beside the destinations. Leave these in place while
heph sessions run; ignore them in Git if you track your config.
Permission and network policy refresh before the next tool decision in every
session using these paths. Unreadable or invalid config pauses all tools,
including config tools, at a heph-owned error. Edit the authoritative file
externally, then press r to retry the pending call under the repaired policy.
Press s or Esc to stop. Retrying a still-broken file shows the error again.
Ordinary policy denials still go to the working model as tool results.
Alongside the error, heph requests advisory guidance from the selected profile's
quick role (normally the fast tier), using the last successfully loaded
provider settings. This separate, tool-free request sends the running version's
embedded config docs, the error, and both authoritative config files to that
provider. It does not send conversation history or add messages to the working
model's context, and cannot edit files or approve a call. Usage is recorded as
config-help. Advice has a 20-second deadline and a 1024-token output ceiling;
files over 64 KiB or packets exceeding the helper model's context window skip
advice. Retry and Stop work immediately, even if advice is unavailable. Closing
the prompt cancels pending guidance.
Startup config errors remain ordinary heph errors; no helper runs before a
usable provider configuration exists. Non-interactive runs fail with the config
diagnostic rather than asking the working model to fix it. Other settings
require restarting heph. /skills --reload refreshes skills without restart; a
running turn keeps its skill snapshot.