CLI Reference
axm-config command
The axm-config console script (registered under [project.scripts]) is the
shell front end to the resolution layer. It owns the process lifecycle only —
every command body delegates to the same central function used programmatically
and over MCP, so the behavior is identical across surfaces.
| Command | Delegates to | Effect |
|---|---|---|
axm-config get <ns> <key> |
get |
Prints the resolved value (env > file > default). |
axm-config set <ns> <key> <value> |
set_ |
Persists key = value in the [ns] section of ~/.axm/config.toml (atomic, 0600, other sections preserved). |
axm-config delete <ns> <key> |
delete |
Removes key from the [ns] section of ~/.axm/config.toml (silent no-op if absent). |
axm-config path |
axm_home |
Prints the resolved ~/.axm home (created 0700 if absent). |
axm-config doctor [<ns>] |
config_doctor_data |
Prints per-key provenance (<ns>.<key>: <layer>); all known namespaces if <ns> is omitted. |
axm-config set research.fred api_key abc123
axm-config get research.fred api_key # -> abc123
axm-config delete research.fred api_key # remove the key (no-op if absent)
axm-config path # -> /Users/you/.axm
axm-config doctor research.fred # -> research.fred.api_key: file
Tools
config_doctor
Report config-key provenance for a namespace, read-only. For every visible
key (the union of the namespace's [ns] section in ~/.axm/config.toml and
any AXM_<NS>_* environment variables) it reports which layer would win under
the env > file > default precedence — it never reads a value into a
consumer and never mutates any layer.
The result is a mapping {"<ns>.<key>": {"layer": env|file|default, "present": bool}}.
Omit --namespace to report every namespace present as a section of
~/.axm/config.toml (plus any not-yet-folded legacy per-namespace file).
Programmatic access shares the exact same central function:
from axm_config.doctor import config_doctor_data
report = config_doctor_data("research.fred")
# {"research.fred.api_key": {"layer": "env", "present": True}, ...}
Validation
Every public surface (get / set_ / delete / load, and their CLI
counterparts) validates the namespace and key against safe-segment
patterns before touching disk. Both are lowercase-only: a namespace
is lowercase-alphanumeric segments joined by dots
(^[a-z0-9]+(\.[a-z0-9]+)*$) — uppercase, _, and - in a namespace are
rejected; a key is lowercase-alphanumeric segments joined by single _
(^[a-z0-9]+(_[a-z0-9]+)*$) — uppercase, dots/dashes, and leading/trailing
or doubled _ in a key are rejected. A path separator, .. traversal, the
empty string, or a NUL byte raises ConfigError — so a config file can never
escape the resolved ~/.axm home. A HOME that itself resolves inside a git
checkout is refused as well.
The per-key env name is derived as AXM_<NS>_<KEY> upper-cased, with each
namespace dot folded to a double underscore (a.b → AXM_A__B_*). The
mapping is provably injective and always POSIX-valid: lowercase-only
segments make the upper-casing a bijection (so Demo cannot collide with
demo), a namespace carries no _ of its own and no -, and a key can
never forge a __ (single-_-joined, no edge/doubled _) — so a __ only
ever comes from a namespace dot and the lone single _ marks the
namespace/key boundary. doctor's reverse enumeration recovers a namespace's
keys from the environment by the same rule; because the AXM_A_ prefix is also
a prefix of a child namespace's variables (AXM_A__B_C belongs to a.b),
each recovered suffix is validated against the key pattern so a child's
variable is never surfaced as a phantom key of the parent.
Python API
Auto-generated API reference is available under Python API.