grith.aidocs

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 | sh from an unknown host, reading ~/.aws/credentials from 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:

  1. The agent is genuinely doing wild stuff, and you should look at it more closely.
  2. 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

Last updated: 2026-05-14Edit this page on GitHub →
© 2026 grith. All rights reserved.