Feature: User-configurable shell guard rules via config.json + /guard menu command
Problem
When running atomic-agent via Telegram (or any non-interactive surface), every shell command that doesn't match a built-in guard rule triggers an approval prompt. This creates a painful experience for automated/remote workflows:
Approval requested
tool: os.shell.run
kind: shell command
reason: no shell guard rule matched; approval required
preview: cargo run -p quantumclaw-app --example logistics_dwave_shadow_compare > /tmp/router_benchmark.txt 2>&1
The only current options are:
- Press
s during TUI to grant the category for the session (not available on Telegram)
- Raise
approvalLevel to 5 (approves everything — too permissive)
- Edit source code to add custom rules (not practical for users)
Proposed Solution
Two complementary pieces:
1. Config-based rules (config.json)
Add a shell.guard section to config.json for persistent, version-controllable rules:
{
"shell": {
"guard": [
{
"pattern": "cargo run *",
"action": "allow"
},
{
"pattern": "cargo build *",
"action": "allow"
},
{
"pattern": "npm test *",
"action": "allow"
}
]
}
}
2. /guard menu command (TUI + Telegram)
For quick, interactive management without editing JSON:
| Command |
Description |
/guard |
Show current user-defined rules |
/guard add <pattern> [allow|block|ask] |
Add a new rule |
/guard remove <pattern> |
Remove a rule |
/guard clear |
Clear all user rules |
/guard on|off |
Temporarily enable/disable all user rules |
The menu entry fits naturally in the Setup group alongside /mouse, /theme, /analytics:
Setup
├── Theme…
├── Mouse…
├── Analytics
├── Guard… ← new
├── Enable or disable a skill…
└── Create, cancel or run a task…
Rule format
Each rule has:
pattern — glob-style pattern matching the full command string (e.g., cargo run *, git status)
action — one of "allow" | "block" | "approval_required"
cwd (optional) — restrict rule to a specific working directory
Matching behavior
User-defined rules are evaluated after built-in hardline/dangerous rules but before the default approval_required fallback:
hardline → dangerous → trusted → safe-allow → [user rules] → approval_required
This ensures:
- Catastrophic commands (
rm -rf /, mkfs, etc.) are always blocked regardless of user rules
- User rules cannot override safety hardlines
- Users can pre-allow patterns they trust without raising the global approval level
Implementation sketch
Config layer
- Add
shell.guard to UserConfigFile and AtomicAgentConfig interfaces in config-schema.ts
- Create
rules-user-config.ts in src/tools/os/shell-command-guard/ implementing the Rule interface
- Inject the user rule layer into
guard-engine.ts between safeAllowRule and the default fallback
- Bump
USER_CONFIG_VERSION to 43 and add migration in parseUserConfigFile
Menu command
- Add menu node in
menu-registry.ts under setup group with /guard slash
- Add dispatch handler in
slash-command-handler.ts for /guard subcommands
- Wire persistence through the orchestrator to read/write
shell.guard in config.json
Tests
- Pattern matching tests (glob, cwd scoping, metachar rejection)
- Pipeline placement tests (hardline override protection)
- Config round-trip tests (parse → serialize → parse)
- Slash command dispatch tests
Use cases
- Telegram automation: Pre-allow project-specific commands (
cargo run, npm test) without raising global approval level
- Quick toggles:
/guard off to temporarily disable all user rules during debugging
- CI/CD pipelines: Allow specific build/test commands in trusted directories
- Shared environments: Per-project guard rules that don't affect other projects
Security considerations
- User rules sit below hardline rules in the pipeline — they cannot unblock blocked commands
block action in user rules adds a deny layer before the default approval
- Optional
cwd scoping limits rules to specific directories
- No pattern can match shell metacharacters (same as
safeAllowRule)
/guard on|off is a session toggle only — config.json rules persist independently
Alternatives considered
- Per-project
.atomic-agent/guard.json: Could be a future extension, but config.json keeps it centralized
- Session-only grants: Already exist via
[s] key, but don't persist across restarts
- Raising approvalLevel: Too broad — the whole point is fine-grained control
Would love maintainer feedback on:
- Is
shell.guard the right config key name?
- Should
cwd scoping be in v1 or deferred?
- Any concerns about the rule pipeline placement?
- Preference for
/guard as a standalone command vs subcommand of /privacy?
Feature: User-configurable shell guard rules via config.json +
/guardmenu commandProblem
When running atomic-agent via Telegram (or any non-interactive surface), every shell command that doesn't match a built-in guard rule triggers an approval prompt. This creates a painful experience for automated/remote workflows:
The only current options are:
sduring TUI to grant the category for the session (not available on Telegram)approvalLevelto 5 (approves everything — too permissive)Proposed Solution
Two complementary pieces:
1. Config-based rules (
config.json)Add a
shell.guardsection toconfig.jsonfor persistent, version-controllable rules:{ "shell": { "guard": [ { "pattern": "cargo run *", "action": "allow" }, { "pattern": "cargo build *", "action": "allow" }, { "pattern": "npm test *", "action": "allow" } ] } }2.
/guardmenu command (TUI + Telegram)For quick, interactive management without editing JSON:
/guard/guard add <pattern> [allow|block|ask]/guard remove <pattern>/guard clear/guard on|offThe menu entry fits naturally in the Setup group alongside
/mouse,/theme,/analytics:Rule format
Each rule has:
pattern— glob-style pattern matching the full command string (e.g.,cargo run *,git status)action— one of"allow"|"block"|"approval_required"cwd(optional) — restrict rule to a specific working directoryMatching behavior
User-defined rules are evaluated after built-in hardline/dangerous rules but before the default
approval_requiredfallback:This ensures:
rm -rf /,mkfs, etc.) are always blocked regardless of user rulesImplementation sketch
Config layer
shell.guardtoUserConfigFileandAtomicAgentConfiginterfaces inconfig-schema.tsrules-user-config.tsinsrc/tools/os/shell-command-guard/implementing theRuleinterfaceguard-engine.tsbetweensafeAllowRuleand the default fallbackUSER_CONFIG_VERSIONto 43 and add migration inparseUserConfigFileMenu command
menu-registry.tsundersetupgroup with/guardslashslash-command-handler.tsfor/guardsubcommandsshell.guardin config.jsonTests
Use cases
cargo run,npm test) without raising global approval level/guard offto temporarily disable all user rules during debuggingSecurity considerations
blockaction in user rules adds a deny layer before the default approvalcwdscoping limits rules to specific directoriessafeAllowRule)/guard on|offis a session toggle only — config.json rules persist independentlyAlternatives considered
.atomic-agent/guard.json: Could be a future extension, but config.json keeps it centralized[s]key, but don't persist across restartsWould love maintainer feedback on:
shell.guardthe right config key name?cwdscoping be in v1 or deferred?/guardas a standalone command vs subcommand of/privacy?