Safety
Every model-generated tool call is classified, then decided by ApprovalPolicy (Crystal.Tools.ToolInvocationPolicy). Side effects are not invoked by bypassing that executor.
Risk is read, write, privileged, or forbidden. Authority is workspace, outside_workspace, network, or privileged_escalation.
What can pass without a prompt
Section titled “What can pass without a prompt”A call passes without review only when all of these hold:
- The classification does not require a prompt.
- Risk is not Forbidden or Privileged.
- Authority is Workspace.
- The tool is in the automatic-tool set, or risk is Read, or risk is Write and the approval mode allows that write.
| Mode | What auto-passes |
|---|---|
| Full | Any Workspace write that cleared the checks above, including an external tool that stays Write + Workspace. Bash, bash_start, and bash_stop only when they classified as Workspace write |
| Edit, Review | Built-in write and edit only |
| Default | No writes |
A network, privileged, or forbidden command does not auto-pass. Forbidden, Privileged, outside-workspace, and network authority never fully auto-pass. A reusable grant is skipped when the classification does not allow one.
Review can allow a call. A Forbidden classification or a required prompt still falls back to you. A reviewer Allow of Forbidden does not execute.
An unknown tool name, including one no plugin classifier claims, is Privileged with PrivilegedEscalation and the summary Unknown tool.
Credential paths
Section titled “Credential paths”A path is a credential path when any segment is .ssh or .gnupg (case-insensitive), or a .crystal segment is immediately followed by credentials.json. ~ is expanded first. The check runs on the argument and again on the resolved full path.
Those paths are Forbidden / PrivilegedEscalation for read, list, tree, glob, grep, search, describe_image, view_image, write, and edit. Directory walks skip a file whose resolved target is a credential path. Session directory rules cannot grant one. Export refuses one.
A missing or unparsable path does not become Forbidden. A required path that cannot be read is a workspace read. A write or edit whose path cannot be parsed, or that the workspace cannot normalize, is a workspace write. A path that normalizes outside the accessible session directories is Read or Write with OutsideWorkspace. That does not auto-pass.
Shell commands
Section titled “Shell commands”bash and bash_start use the same classifier. Matching is case-insensitive. A match that takes more than one second is treated as a hit, so a timeout fails closed.
| Class | Pattern | Risk | Authority |
|---|---|---|---|
| Forbidden | \bsudo\b |
forbidden | privileged_escalation |
| Forbidden | rm with both recursive and force flags, aimed at /, ~, $HOME, or ${HOME} |
forbidden | privileged_escalation |
| Forbidden | curl or wget piped to sh or bash |
forbidden | privileged_escalation |
| Forbidden | git push with -f or --force |
forbidden | privileged_escalation |
| Forbidden | a .ssh, .gnupg, or .crystal/credentials.json path in the command text |
forbidden | privileged_escalation |
| Privileged | chmod 777, chown, mkfs, dd , kill -9, shutdown, reboot |
privileged | privileged_escalation |
| Network | curl, wget, ssh, scp, nc, nmap when not already forbidden |
write | network |
| Other | any other non-empty command | write | workspace |
Forbidden is tested first, then privileged, then network. A command that matches nothing, or that cannot be read from the arguments, is a workspace write named Workspace shell command.
bash_status and bash_logs are workspace reads (Read background shell task). bash_stop is a workspace write (Stop background shell task) and is not re-classified from the command string.
Other fences
Section titled “Other fences”- A workspace tool that may not leave the root rejects a path that leaves it. A readable tool may resolve an outside path, then classify it as OutsideWorkspace.
- A write or edit into a read-only session directory is rejected before classification:
Writing to a read-only session directory is not allowed. Change its access with /access. - In Plan,
edit,write,bash,bash_start, andbash_stopare rejected before classification:Plan mode does not allow <name>. - Plugin hooks may raise approval risk. They cannot lower it. A raw hook is not held to that limit and is named at load. See Plugins.
- Runtime text is plain English. No emoji in exceptions, logs, or UI chrome.
- Secrets must not appear in source, logs, diagnostics, or commits.
credentials.jsonis owner read/write on Unix (0600). Windows leaves the file ACL unchanged.