Default deny
Steerholm uses an allowlist permission model. An agent with no policy gets zero tools — Steerholm creates an empty policy that denies everything.How policy evaluation works
When an agent calls a tool, Steerholm checks three things in order:1
Tool lookup
Steerholm resolves which server owns the requested tool. If the tool doesn’t exist on any server the agent has access to →
AUTHORIZATION_DENIED.2
Tool check
Does any tool permission in the policy match the requested tool name? If not →
AUTHORIZATION_DENIED.3
Argument check
Each argument policy is checked only when the call actually includes that argument — a tool that doesn’t take the argument is unaffected. If a provided argument fails its policy →
AUTHORIZATION_DENIED. So --tool "*" --args "path=..." constrains the path argument wherever it appears, without rejecting tools that have no path.Tool filtering
list_tools only returns tools that match at least one entry in the policy. Agents never see tools they aren’t allowed to use.
Argument policies
Argument policies restrict the values of specific tool arguments. Two match types are supported:
A glob pattern without wildcards is an exact match —
mode=readonly matches only "readonly".
CLI examples
Agents
Agents are created withholm add agent <name>. Each gets:
- A name (stored in
config.json) - A key prefix for display (stored in
config.json) - A bcrypt-hashed access key (stored in system keyring — never in config files)
Authorization: Bearer <key> to the daemon’s Streamable HTTP MCP endpoint. The daemon resolves the agent by checking the access key against all stored hashes.