grith.aidocs

6. Capability enforcement

Hard gate. Profile capabilities determine what an agent is allowed to do at all.

PhaseStatic
Score range0 or DENY
Modulecrates/grith-proxy/src/filters/capability.rs
Config fileconfig/filters/capabilities.toml

A hard gate. The active supervisor profile declares which capability classes it holds; calls that need a missing capability are denied outright. No score, no queue — DENY.

Capability classes

CapabilityScope
read_projectFile reads inside ${PROJECT_DIR}
write_projectFile writes inside ${PROJECT_DIR}
read_homeFile reads inside ${HOME} outside project
write_homeFile writes inside ${HOME} outside project
read_systemFile reads in /etc, /usr, /opt, etc.
write_systemFile writes in system paths (rare; usually denied)
shellSpawning shell processes (sh, bash, zsh, ...)
networkOutbound network sockets
bindListening sockets
execSpawning arbitrary processes
signalSending signals to processes

Where capabilities are declared

# config/supervisor/profiles.toml
[profiles.minimal]
extends = "generic"
capabilities = ["read_project", "write_project"]

A profile with no capabilities key inherits from extends, which defaults via the generic baseline to ["read_project", "write_project"] — read-write inside the project, nothing else.

The built-in claude-code profile, by contrast, declares:

capabilities = [
    "read_project", "write_project",
    "read_home", "write_home",
    "read_system",
    "shell", "network", "exec",
]

— because Claude Code legitimately needs all of those.

Why DENY and not score

The composite scoring system is for ambiguous cases. Capability denial is not ambiguous: the profile said "this agent doesn't do network", and now the agent opened a socket. There is no score that makes that OK.

Returning DENY also bypasses every later filter, every reputation discount, and the auto-allow threshold. This is intentional. Capability denial is the strongest guarantee grith makes.

When a capability deny fires

The audit log gets a decision: deny, reason: capability record. The originating process gets EACCES on the syscall. If notifications are configured, the capability deny is one of the events that escapes default rate-limiting (canaries are the other).

Tuning

The two knobs:

  1. Edit the profile. Grant a capability that's missing. Be deliberate — adding network to a profile that didn't have it should be a considered choice, not a reflex to silence a deny.
  2. Use a different profile. Switch to one that already declares the capability.

For one-off overrides ("just this once, let it network out"), the digest's "approve

  • unlock-egress" action is the right tool — it bypasses the capability check for that single call without changing the profile.

See also

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