The quarantine digest
Why grith routes ambiguous calls to a human review queue instead of guessing.
The digest is grith's queue for calls that scored ambiguously. Auto-allow is for calls that are obviously fine. Auto-deny is for calls that are obviously not. The digest is for everything else — and "everything else" is where most of the actual security decisions get made.
The shape of the problem
If you could write a function is_this_safe(call) → bool that was always right,
grith wouldn't need a digest. You can't. Nobody can. Real agent workloads have:
- Calls that are obviously safe (
ls,cat README.md,git status). The filters handle these — auto-allow. - Calls that are obviously not (
curl | shfrom an unknown host, reading~/.aws/credentialsfrom a session that's about to network out, anything that trips canary detection). Auto-deny. - Calls that could be fine in this context but suspicious in another (
cat ~/.ssh/config— fine if you asked the agent to fix a typo there, very not fine if you asked it to summarise a README). The filters can't know which context applies.
That last category is what the digest is for. Rather than guess, grith freezes the calling process and asks.
Process freezing
When a call lands in the queue, grith uses ptrace(PTRACE_INTERRUPT) to stop the
calling thread before the syscall is committed. The thread sits there, frozen, with
the syscall args staged in registers. It cannot proceed, but it also cannot fail —
it's just paused.
That matters because:
- The agent doesn't see a permission error and decide to retry the call a different way. It just hangs.
- The OS doesn't see a partial syscall and roll back state. The syscall has not started yet.
- A human (or webhook) can take as long as they want to decide. Up to
proxy.review_timeout_seconds(default 300s = 5min), after which grith auto-denies.
When a decision is made, the thread either runs the original syscall (approve) or returns it with EACCES / equivalent failure (deny).
What the reviewer sees
A digest item carries every piece of context the filters had plus a few they didn't:
- The call itself: operation type, target, args, originating PID and command line.
- The composite score and which threshold zone it crossed.
- Per-filter contributions: each filter's emitted score and any annotations (matched patterns, denied paths, taint sources).
- Session history: the last N calls in the same session, for behavioural context.
- Reputation snapshot: what the trust table says about the destination today.
- Profile: which supervisor profile is active, and which entries got exercised.
This is enough to make a yes/no decision in roughly the time it takes to read the filter list. If it isn't, something's off — usually that means the score is in the queue zone but the filters have nothing alarming to say. That's usually a threshold mis-tuning. See Tuning scoring thresholds.
The actions available
The reviewer can:
- Approve — let this call run.
- Approve + learn — let it run, and teach the reputation system that this shape is okay. Similar future calls will auto-allow.
- Approve + unlock egress — for network calls. Allows this destination for the rest of the session.
- Allow always (Pro) — adds the call to a permanent allowlist. Sparingly.
- Deny — block this call; the syscall returns EACCES.
- Deny + terminate — block + kill the process tree. For confirmed exfil.
- Escalate (Pro) — route to a teammate or channel for second opinion.
- Skip — leave it queued. Useful for "I'll come back to this".
Each decision is recorded in the audit log with the user who made it (in multi-user team setups) and the rationale annotations from the filters.
Why batching matters
In a session of any length, multiple calls will land in the digest. Most agents do roughly the same kinds of things, which means the digest items cluster: "this agent is reading config files all over my home dir." Reviewing them one by one is exhausting.
The CLI and dashboard both let you batch-decide on related items:
grith digest list --filter session=abc12345
grith digest approve --filter session=abc12345 --target '~/.config/grith/**'
Or in the dashboard: select a group, click approve. The reputation system records this as a batch approval, which is stronger evidence than the same approvals one at a time.
Channels (Pro)
A Pro license unlocks notification channels. The digest item gets posted to Slack / Discord / Telegram / Teams / email / PagerDuty / Opsgenie / a webhook. The reviewer clicks an approve button (or replies in a thread), and the decision flows back via an HMAC-signed callback. See Notification security model for the threat model around remote approvals.
When the queue is empty
A grith deployment with the queue mostly empty is normal — that's the goal. Most calls auto-allow because the filters cleared them or because reputation absorbed them. A queue that's never empty after a few weeks of use means either:
- The agent is genuinely doing wild stuff, and you should look at it more closely.
- The scoring thresholds are too tight; relax them via
proxy.auto_allow_threshold.
A queue that's too empty under attack is the failure mode that matters more. That's what the canary and DLP filters guard against: they're hard gates, not contributors, so they will deny exfil regardless of whether anyone reads the digest.
See also
- Reviewing the digest — workflow walkthrough
- grith digest — CLI reference
- Digest API — REST routes