Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration Files

Heph reads two TOML files and merges them, project over user.

FileScope
~/.config/heph/config.tomlYou, on every project. $XDG_CONFIG_HOME/heph/config.toml if that variable is set.
.heph/config.tomlThis 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

SectionWhat it configuresChapter
[providers]How to reach a model endpointProviders
[profiles]Named sets of tiers: which model does which workTiers
[tiers]The profile default, written wholeTiers
[permissions]What runs without asking, what never runsPermissions
[permissions.repeat]Soft and hard repeated-call checkpointsPermissions
[locks]Exclusive named execution resourcesExecution Locks
[network]Which hosts web_fetch reaches without askingNetwork
[[gates]]Commands that must pass before reviewGates
[review]How you reviewReview
[worktree]What is copied into the worktree, what is linkedWorktree
[toolsets]Named read-only tool lists for plan turnsTool Sets
[design]Where design turns may writeDesign Turns
[notify]Which events leave the pane, and howNotifications
[input]Attachments, ! commands, the clipboardInput
[ui]Image displayUI
[context]What of the conversation each round carriesContext
[decisions]Decision and command-output policyTiers
[skills]Which discovered skills the model may seeSkills
[git]Which branch conversations start fromGit

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's extends and each tier field it writes replace yours, and the rest of yours is kept. default_profile is the project's when its file sets it.

  • [permissions]: the lists concatenate. Project deny patterns 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-commands replaces 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; defaults is 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]: the disabled lists concatenate, like [permissions], so a project can disable more skills, never fewer. project is 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] link lists 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.