docs · guides

Config, secrets and memory#

Each agent has its own settings, which you set with hekma agent config set and read back with config get. API keys go in as secret:NAME references, so Hekma passes the real key to the agent and shows only a mask everywhere else. A memory backing gives an agent a folder that Hekma keeps across restarts and moves with the agent.

Set and read config#

hekma agent config set NAME KEY VALUE sets one key on one agent:

$ hekma agent config set worker model gpt-4o-mini
✓ Set model = gpt-4o-mini on Agent Instance worker (instance layer)
$ hekma agent config set worker budget.tokens.cumulative 500000
✓ Set budget.tokens.cumulative = 500000 on Agent Instance worker (instance layer)

The key must be one Hekma knows (listed on Config keys) or start with agent.. Hekma checks the key, and the value for budget and price keys, before writing anything; a mistake changes nothing. A typo gets a suggestion:

$ hekma agent config set worker modle gpt-4o-mini
✗ unknown config key 'modle'; did you mean 'model'?. Set a known unified key, or use the agent.* pass-through namespace for agent-native extras (e.g. hekma agent config set <name> agent.<key> <value>).

Keys under agent. go to the agent as environment variables named by the rest of the key, with no checking. Use them for anything the agent reads from its environment:

hekma agent config set worker agent.LOG_LEVEL debug

When the agent next starts, it gets LOG_LEVEL=debug. Most keys take effect at the next start; budget, breach action and rate keys apply at the next usage event, even on a running agent.

To read config back, use hekma agent config get NAME for everything, or add a key for one value. The single-key form prints just the value, which suits scripts:

$ hekma agent config get worker model
gpt-4o-mini

You can set config while the agent runs; the running process is not touched. There is no command to unset a key in 0.11.0: edit config.toml in the agent's Agent Home and delete the line.

Values that start with a dash#

A value may start with -, and Hekma takes it as the value, not as an option. Both forms work:

hekma agent config set worker agent.EXTRA_FLAGS -x
hekma agent config set worker agent.EXTRA_FLAGS -- -x

Layers and where a value came from#

A value can come from four config layers: engine defaults, kind defaults, the agent's own instance layer, and per-call overrides from a program that embeds the engine. A stronger layer's value replaces a weaker one. config set always writes the instance layer, and in 0.11.0 the two default layers are empty, so from the CLI every value you see is one you set.

config get names the source of each value, and marks agent.* keys as unvalidated:

$ hekma agent config get worker
▸ Effective config for worker (3 rows)
Key                       Value         Validated    Source
─────────────────────────────────────────────────────────────────
agent.LOG_LEVEL           debug         unvalidated  instance
budget.tokens.cumulative  500000        validated    instance
model                     gpt-4o-mini   validated    instance

--json gives the same with a source field per entry; see JSON output. At each start Hekma also writes what it used to effective-config.json in the Agent Home, with secrets masked, so you can see after the fact what an agent started with. Layers and provenance has the full table.

Secrets#

Never put an API key in config as plain text. Store a reference instead:

hekma agent config set worker agent.OPENAI_API_KEY secret:OPENAI_API_KEY

Hekma stores the text secret:OPENAI_API_KEY. At each start it looks up OPENAI_API_KEY, replaces the reference with the real key, and passes that to the agent, here as the OPENAI_API_KEY environment variable. The real key never appears in Hekma's output.

Where Hekma looks#

Hekma resolves secret:NAME in this order:

  1. The environment variable NAME in the environment of the command that starts the agent.
  2. The entry NAME in secrets.toml in the state directory.

The file holds one NAME = "value" line per secret:

OPENAI_API_KEY = "sk-..."
ANTHROPIC_API_KEY = "sk-ant-..."

On macOS and Linux the file must be readable only by you. Hekma refuses to read it otherwise, and the start fails:

chmod 600 "$HOME/Library/Application Support/ktesio/secrets.toml"

On Windows the check is skipped; the file relies on your user profile's permissions.

If neither place has the secret, the start fails with exit code 1, names the secret, and changes nothing:

✗ Agent Instance 'worker' could not start: secret 'WORKER_KEY' could not be resolved (tried: environment, secrets file); set the environment variable WORKER_KEY, or add WORKER_KEY to the engine secrets file (mode 0600). Nothing was changed; set the secret and start it again.

For a detached agent, the environment that counts is the shell where you ran hekma agent start --detach. secrets.toml is the safer choice for agents you start from scripts or other terminals.

Masking and --reveal#

Hekma masks a secret reference as secret:**** in config get (table and JSON), in effective-config.json, in its logs and in its events. To see the real value, add --reveal:

$ hekma agent config get worker agent.OPENAI_API_KEY --reveal
sk-file-456

--reveal resolves the secret again at that moment, from the current environment and secrets.toml, so it shows what the agent would get at its next start, which may differ from what a running agent got when it started. It does not unmask anything Hekma has written to disk.

What the agent does with the key is up to the agent: it may log it, and a config file Hekma writes for it holds the real value. Prefer environment variables over command-line flags for secrets. If an adapter maps a secret to a flag, other local users can read it with ps, and Hekma warns when you set it:

! config key 'model' holds a secret:NAME reference, but this adapter delivers it to a FLAG target: the resolved cleartext will be passed on the agent's command line, where argv is readable by other local users (ps, /proc/<pid>/cmdline). Prefer an env or file target for secret-carrying keys.

Memory backings#

A memory backing states who looks after an agent's long-term memory. There are two kinds:

KindWhat Hekma doesWhat Hekma guaranteesLeft to the agent
filesystemCreates memory/ in the Agent Home and passes its path to the agent at every start.The folder exists, its files survive stops, restarts and crashes unchanged, and it moves with the Agent Home. Hekma never reads, writes or cleans its contents.What it stores there and how.
nativeRecords that the agent keeps its own memory. Creates nothing and passes nothing.Only that the Agent Home is kept.Everything.

Attach a backing#

The agent must be registered, stopped or failed; you cannot change a running agent's memory.

$ hekma agent memory attach helper --kind filesystem
✓ Attached filesystem Memory Backing to Agent Instance helper
Ktesio guarantees the managed directory: it exists, survives restarts byte-identically, and travels with the Agent Home.
/Users/you/Library/Application Support/ktesio/agents/helper/memory

The last line is the folder path, for scripts. Attaching the same kind again is harmless. To switch kinds, detach first; attaching native over filesystem fails with exit code 4.

The agent learns the path only if its adapter maps the reserved memory.dir key. The acp and hermes kinds pass it as HERMES_HOME; a manifest adapter passes it however its [config."memory.dir"] section says. --json shows whether the path will be delivered, in declared:

{
  "schema_version": 1,
  "instance": "helper",
  "kind": "filesystem",
  "guarantee": "managed_dir_byte_durable",
  "dir": "/Users/you/Library/Application Support/ktesio/agents/helper/memory",
  "declared": true
}

If declared is false for a filesystem backing, the folder is still kept, and Hekma says on stderr at each start that the agent was not told about it.

Do not set memory.dir yourself with config set: Hekma ignores a hand-set value and passes the path only when a filesystem backing is attached.

Detach a backing#

$ hekma agent memory detach helper
✓ Detached the Memory Backing from Agent Instance helper (the managed directory and its contents remain on disk)

Detaching removes only the record. The memory/ folder and its files stay, and attaching filesystem again later picks them up as they are. Only hekma agent remove NAME --delete deletes the folder, along with the rest of the Agent Home.

Move an Agent Home to another machine#

An agent's registration, config, usage history and memory folder all live in the state directory, so moving agents means moving that directory:

  1. Stop every agent you are moving, so none is running or paused.
  2. Copy the whole state directory, keeping its layout: state.db, secrets.toml if you use it, and everything under agents/. Do not rename anything inside it.
  3. On the new machine, put it at the default location, or anywhere and set HEKMA_STATE_DIR to its absolute path.
  4. Install the agents' programs there too, and make sure any secrets the agents use from the environment are set.

filesystem memory arrives unchanged, and a native backing's record comes along. Agents start in their new Agent Home, and Hekma passes the new memory path. The agent_home field in list --json and show --json keeps the path from registration until you register the agent again, so do not rely on it after a move.

A state directory written by a newer Hekma refuses to open in an older one, with an error naming the schema versions. Upgrade Hekma on the new machine before you start agents there.