Agent Permissions
The CMDOP permission gate decides whether a remote agent’s tool call gets executed on your machine. This guide is the practical companion to Concepts: permissions — what to type, what to expect, what to fix.
The gate fires only on remote agent tool calls. Your own cmdop chat and SDK code on the same OAuth identity always run unsupervised. Same OAuth user → same machine = self-to-self bypass.
When the gate fires
A receiver’s gate inspects every tool call coming from a remote agent. The decision is one of three:
- Allow — execute the tool.
- Deny — return a structured deny to the caller.
- Ask — pause and wait for a human to decide via TUI / desktop modal.
If you start cmdop chat locally on the same machine, you are the operator — the gate stays out of the way.
Inspecting current rules
cmdop permissions listOutput table columns:
rule— the pattern, e.g.execute_command(git *).action—allow,deny, orask.scope—global(file-backed) orsession(in-memory for current daemon process).source—user,policy,floor(read-only),default-mode.reason— optional explanation set at creation.created— timestamp.
Adding rules
Three commands cover the common cases:
cmdop permissions allow 'execute_command(git *)'
cmdop permissions deny 'execute_command(rm *)'
cmdop permissions ask 'write_file(~/projects/**)'Glob hints:
*matches one path segment / one command word.**matches any depth.- Quote the rule — your shell will eat the parens otherwise.
- For dispatcher tools use
tool(operation:argGlob)— e.g.connect(exec:prod-*).
Setting the mode
cmdop permissions mode default # no rule → ask the user
cmdop permissions mode strict # no rule → deny
cmdop permissions mode bypass # no rule → allow (trusted env only)default is the safe pick. See Modes.
Debugging a denied call
Tail the audit log:
cmdop permissions audit --tail 20Find the JSON line, then read:
decision: "deny".source—floor(cannot override),rule(revoke or rewrite),mode(add a rule, or change the mode).rule_id— the matched rule (if any).reason— why the rule fired.
If source=floor, the floor protected the path / command. See Concepts: permissions for the floor list. If source=rule, you can revoke (cmdop permissions revoke <rule_id>). If source=mode, add a rule covering the case.
See Debugging denials for a longer playbook.
The ask modal flow
When a rule says ask, the daemon publishes the request via permissionsbus. TUI or desktop subscribers display a modal. First decision wins; 60-second timeout = deny.
If no UI is attached, the gate denies with reason ask_timeout: no UI wired.
Asking the agent to propose a rule
The agent can use the permissions_helper(operation=suggest_rule, ...) tool to route a proposal through the modal. Status codes:
accepted,denied— user decided.validated_no_ui— no subscriber; CLI command suggested.rejected_floor— floor blocked it; agent cannot override.rejected_action—denyproposals not allowed (onlyallow/ask).rejected_syntax— pattern did not parse.
Useful when the agent itself notices a deny pattern and wants to negotiate.
Per-environment patterns
Three sample policies:
Dev workstation:
cmdop permissions mode default
cmdop permissions allow 'execute_command(git *)'
cmdop permissions ask 'write_file(~/**)'Prod VPS receiving cross-machine asks:
cmdop permissions mode strict
cmdop permissions allow 'read_file(/var/log/**)'
cmdop permissions allow 'execute_command(systemctl status *)'Air-gapped sandbox (only if you fully trust callers):
cmdop permissions mode bypassbypass mode does not disable the floor. .env, .git, ~/.ssh, rm -rf /, fork bombs are blocked regardless.
session scope keeps a rule alive only for the current daemon process. Use it to grant one-off access without committing to YAML.
Related
- Concepts: permissions — the model.
- Rule grammar — full pattern language.
- Modes —
default,strict,bypass. - Audit log — read what happened.
- Debugging denials — playbook.
cmdop permissions