Approval Modes · crystl Docs

When an agent needs to run a tool (editing a file, running a command, searching your codebase), it asks for permission. crystl intercepts that request and decides whether to auto-approve it or float it to you as a glass panel.

The setting is called auto-approval. It has three states.

The three modes

off

crystl auto-approves nothing. Every tool call waits for you. A floating approval card appears with allow and deny buttons.

Best for: unfamiliar code, sensitive operations, watching what an agent does step by step.

in gem

Reads anything. Makes changes only inside this gem. Runs git that cannot lose work. Asks before anything else.

That sentence is the whole contract. In detail:

Writes into .git/ still ask

.git/ sits inside the tree and is not workspace. A write to .git/config or .git/hooks/* installs something a later git run executes, often outside the run that wrote it, so it raises a panel even under in gem.

One plain invocation only

The safe-git list covers one plain git command and nothing else. A shell operator anywhere disqualifies the request whatever the subcommand: &, ||, ;, |, a backtick, $(, =(, >, <, or a newline.

all

Every tool call is approved. Nothing waits.

Best for: a task you defined tightly, in a gem you are happy to hand over.

The gem is the ceiling

A permission mode declared inside your project may narrow what crystl auto-approves. It may never widen it.

Agents read permission settings out of the repo: a .claude/agents/*.md file can declare permissionMode: bypassPermissions, and a CLI flag can ask for the same thing. Now your gem’s mode takes precedence:

You may notice this as “crystl started asking me things.” If a repo you work in declares a bypass mode, work that used to run unattended under in gem now raises panels.

Pause

pause auto-approvals in the crystl app menu is a global kill-switch. It overrides every mode: per-gem, per-shard, and global settings alike.

Use it when you want to take the wheel back for a minute without editing any gem’s setting.

Approval cards

Each approval card is a floating glass panel that shows:

Denial panels

When crystl denies a tool under in gem, an orange denial panel appears showing what was blocked. A retry button lets you override the auto-deny without switching modes, and dismiss clears the panel.

Per-gem auto-approval

You can override the global mode per gem. Open the gem menu and choose auto-approval › to set the mode directly.

Priority chain

crystl resolves the active mode in this order:

  1. pause auto-approvals: the app-menu kill-switch.
  2. Session override: a temporary override supplied programmatically for an individual shard.
  3. Per-project config: the nearest .crystl/project.json at or above the shard’s working directory.
  4. Crystl session default: the fallback a quest or fanout launch sets for its own shards.
  5. Global mode: the default set on the agents settings page.

When you set a per-gem mode, the terminal prints a confirmation.

Global default

Set the global default in settings, agents > defaults, under AUTO-APPROVAL (DEFAULT). This is the fallback used when a gem has no override of its own.

Upgrading from the old names

The modes used to be called Ask Every Time, Smart, and Auto. They are now off, in gem, and all. Same three modes, clearer names.

Which agents get cards

Agent Cards What is different
Claude Code yes the full behaviour this page describes
Codex yes option+deny denies the one call
opencode yes cards start from opencode’s own permission event
goose yes, in auto mode goose resolves approvals before the hook runs
Kimi yes allow releases the hold rather than pre-approving
GitHub Copilot CLI yes allow fully replaces Copilot’s own prompt.

A worker’s approval goes to its orchestrator first

When a shard you fanned out hits an approval, the card does not land on you straight away. crystl dispatches one line into the lead shard’s terminal instead, naming the request and the two commands that decide it.

From the CLI

Approvals are also reachable via the crystl CLI. This helps when you’re triaging from another terminal, scripting a workflow, or running an agent that needs to coordinate with whoever holds the approval seat.

crystl pending                       # list every pending request
crystl approve 3                     # approve request id 3
crystl deny 4                        # deny request id 4
crystl wait pending --timeout 60     # block until the next one appears, then exit
crystl events --type pending_changed # stream approval lifecycle as JSON lines

Switching modes

You can change the mode at any time from the gem menu’s auto-approval › shortcut or the Gem Settings panel. The change takes effect immediately for pending and future requests in that gem.