You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Inspired by opencode's agent frontmatter (per-bash-command glob permissions, permission.task subagent control), Roo Code's mode tool-groups with file-path write regexes, Copilot CLI's /sandbox policy UI, and opcode's OS-level sandboxing (Seatbelt/seccomp).
Beyond #190 (profiles as presets): a declarative per-agent/per-profile matrix of allowed tools, bash command globs, file-write path scopes, and network policy, enforced via OS sandbox where possible (macOS Seatbelt), with every allowed/denied action written to an audit log. gh-aw's safe-outputs pattern (agent is read-only; mutations pass through a declared, capped proxy) is the stretch goal.
Research notes to fold into the design: (1) Kiro blocking hooks: PreToolUse/UserPromptSubmit hooks that can veto execution, with a confirmCommand whose stdout dynamically decides what to ask. (2) Coder's Agent Firewall, local edition: per-worktree network egress allowlist so agents cannot exfiltrate via curl. (3) Continue's Checks: PR policies as plain-Markdown rules enforced by headless agents in CI. (4) Goose's continuous adversary reviewer watching agent actions for unsafe behavior, not just gating permission prompts.
Research note (OpenClaw failure postmortems, worth encoding as invariants): (1) context compaction must never drop standing approvals/safety directives — an agent bulk-deleted 200+ emails after compaction dropped the directive; (2) hard per-task budget caps, see the budget-caps issue; (3) any community skills/plugins surface needs a vetting story — ClawHub shipped 1,184 malicious skills.
Research note (Governance Decay paper, arXiv 2606.22528): compaction silently drops in-context policy constraints — violation rate 0% to 30%+ after compaction, and adversarial compaction-eviction defeats all tested models. Mitigation is constraint pinning: enforce policy in the harness (tool-call interception), never in prompts, and re-inject a pinned policy block verbatim at every turn boundary. Also from Snyk Evo's Policy Agent: natural-language policy compiled to executable gates ('never push to main, require approval above ') as the authoring UX for this layer.
Deep-dive (Zed tool-permission engine): the precedence stack to adopt — built-in security rules > always_deny > always_confirm > always_allow > tool default > global default, with per-tool regex patterns (command/path/URL/query), case-insensitive by default, chained-command parsing across all shells (echo x && rm y checked per subcommand), non-overridable rm -rf / ~ /Users/willem rules, and a UI that writes config from the prompt ('Always for tool' vs 'Always for pattern'). Sandbox notes: .git never writable, create_directory cleaned up on deny, and the symlink-swap TOCTOU — resolve paths and fail closed between approval and sandbox invocation. Their explicit lesson: rules-based filtering is useless against a motivated agent; sandbox is not rules.
Round 18 intel from Devin Local (changelog 2026-07-29), their permission model matured in ways that map directly onto this governance layer:
Layered rules compose predictably: enterprise, mode, user, project, and subagent levels all contribute rules; an explicit deny: always wins regardless of level.
Denial attribution: a denied action says which layer denied it. Without this, layered policy is undebuggable.
Grant visibility: "always allow" options only appear when the grant would actually take effect (i.e. no higher layer denies it). Prevents users collecting useless grants.
Session-wide subagent grants: a permission answered on a subagent's prompt applies to the whole session, so the root agent and sibling subagents do not re-prompt for an already-granted scope.
Tool-level symlink refusal: their edit/write/apply_patch tools refuse to write through symlinks, so an approved edit cannot be redirected to an unexpected file (fixed 2026-08-01). Worth checking each Solenta adapter's behavior here.
Also filed this round: #509 (edit command before approve, interacts with allow-always keying) and #510 (CI/workflow diffs need hard human sign-off; Wiz/Snowflake incident).
Team MCP distribution (2026-06-30): admins configure MCP servers once and fan them out to cloud agents, the agents window, IDE, and CLI through team marketplaces; marketplace access restrictable by org groups. This is the distribution half of the governance layer: policy decides what is allowed, marketplace decides what is present.
Unified Customize page (2026-06-22): plugins, skills, MCPs, subagents, rules, commands, and hooks managed in one surface at user/team/workspace levels. The scoping model (three levels, explicit precedence) is the same shape as Devin's layered permissions (see earlier comment): the industry has converged on user < team < workspace layering with deny-wins.
CVE-2026-50548 / CVE-2026-50549 (Cursor <3.0, CVSS 9.8): sandbox write confinement escaped because path canonicalization failed open; when canonicalization errored, the write went through outside the workspace. Rule for every Solenta sandbox/adapter path check: canonicalization failure must deny, never fall through. Worth an audit line in this issue's checklist.
Round 22, three governance principles from Claude Code's latest hardening (v2.1.220-224):
Checked-in config can restrict but never expand privilege: a repository's checked-in settings can no longer turn ON Remote Control auto-connect; only user or managed settings can enable it, and project/local settings can only turn it OFF. Any repo-controlled knob (CLAUDE.md, .solenta/, WORKFLOW.md) must be unable to grant itself powers the user did not personally approve. This belongs in the audit checklist next to Install-time scanning for MCP servers, skills, and agent-added dependencies #305.
Internal side tasks do not inherit user bypasses: PreToolUse auto-allow hooks no longer apply to Claude Code's internal side tasks (summaries, compaction). If Solenta ever runs background summarization/title-generation/labeling with tool access, those runs get a fresh minimal permission scope, not the session's grants.
Normalize before matching: see the Allow-always is a command prefix, not the whole tool #479 comment on invisible-Unicode padding; the governance layer should centralize command normalization so every matcher (prefix lists, deny rules, audit log) sees the same canonical form.
Round 23 intel: Factory Droid's commandBlocklist setting (v0.147.0) fills the missing layer in the permission stack: commands that can never run, even under full autonomy or skipped approvals. This is distinct from deny rules (which live inside the review/approve flow) and from sandboxing (which contains, not forbids). The blocklist is the absolute floor an org or user sets once: think rm -rf /, git push --force to protected branches, kubectl delete against prod contexts. For Solenta's matrix: three enforcement tiers make sense: blocklist (never, not reviewable), deny (visible rejection with reason), ask (default). Also from Droid: per-MCP-server risk levels and a quick mcp off shortcut (v0.138.0), and org-central governance of MCP/marketplace access (v0.152.0).
Round 29 intel: bernstein (bernstein.run) ships an HMAC-signed, chained audit log for orchestration events, so the audit trail is tamper-evident rather than just append-only text. That is the right integrity bar for this issue's audit trail: each event references the previous event's hash, and verification is a local offline check. Also from bernstein: their scheduler is deterministic plain Python by design ("just don't put the LLM in the scheduler tick") with LLM-assisted parts (routing, best-of-N judge) explicitly opt-in and pluggable. A clean separation worth copying: deterministic core loop that is replayable and auditable, LLM judgment only at declared decision points.
Mirroring opencode, Roo and Copilot CLI is a solid baseline, but an agent that already holds a permitted shell scope can emit a denial record that never blocked anything, so the audit log's credibility depends on enforcement being separable from reporting. Worth flagging: the Seatbelt profile and the declared permission matrix are two sources of truth that can diverge, and the audit entry should record which one made the call when they disagree, otherwise you cannot debug a pass that the sandbox vetoed. For the proxy stretch goal, do you plan to capture the agent's declared intent from the pre-approval step alongside the actual executed arguments, so the trail can prove what was promised matched what ran? I work on a control-and-evidence layer, and that declared-versus-executed seam is the exact gap I care about.
Good questions, and they land on seams the design notes already worry about, so folding the answers in here.
On enforcement versus reporting: agreed, and that separation is a hard requirement, not a nice-to-have. The audit writer must live in the enforcing component, not in anything the agent can influence. Today Solenta only reports what flags it passes (the sandbox badge in the UI is pure reporting, which is exactly the credibility gap you describe). The plan is harness-level interception for tool calls plus OS sandbox for confinement, with the log appended by that layer, chained and tamper-evident per the bernstein pattern noted above. A denial record is written only by the thing that actually denied.
On the two sources of truth: yes, and this is already captured as the attribution requirement (a denied action must say which layer denied it, per the Devin note earlier in this thread). Your version is the sharper framing though: attribution has to cover disagreements in both directions, including a pass the matrix granted that Seatbelt then vetoed. Adding "record the deciding layer on every entry, allow and deny alike" to the checklist.
On declared versus executed for the proxy: yes, both sides go in the log. Declared intent is captured at the approval step (the exact command or mutation as presented and approved), executed arguments at dispatch, and the entry links the two. This is what makes the TOCTOU rules auditable after the fact: symlink-swap and edit-before-approve (#509) only stay honest if you can diff what was promised against what ran. Approval covers a specific declared action hash, not a scope; anything that deviates is a fresh decision, fail closed.
Seatbelt OS sandbox and gh-aw safe-outputs stay follow-ups. Enforcement will extend the existing #409classifyTool seam on Claude can_use_tool (electron/guardrails.js + electron/runner.js). electron/sandbox.js remains reporting-only in this slice.
Design in progress on thread 36cfee86-4dc4-4d12-8917-2c1f5568a4bc.
v1 implementation is up as PR #1655. It contains the matrix, the Claude gate with a re-check when the card is answered, the HMAC audit, and the profile UI. On a CI-like env, test:electron is 4825 pass / 0 fail and the renderer suite is 3103 / 0. Two deviations from the spec are listed in the PR body:
Bash rules match word prefixes per subcommand.
Governed threads don't send Claude session rules, which would bypass the matrix.
Activity
currentbits commentedon Aug 17, 2026
Research notes to fold into the design: (1) Kiro blocking hooks: PreToolUse/UserPromptSubmit hooks that can veto execution, with a confirmCommand whose stdout dynamically decides what to ask. (2) Coder's Agent Firewall, local edition: per-worktree network egress allowlist so agents cannot exfiltrate via curl. (3) Continue's Checks: PR policies as plain-Markdown rules enforced by headless agents in CI. (4) Goose's continuous adversary reviewer watching agent actions for unsafe behavior, not just gating permission prompts.
currentbits commentedon Aug 17, 2026
Research note (OpenClaw failure postmortems, worth encoding as invariants): (1) context compaction must never drop standing approvals/safety directives — an agent bulk-deleted 200+ emails after compaction dropped the directive; (2) hard per-task budget caps, see the budget-caps issue; (3) any community skills/plugins surface needs a vetting story — ClawHub shipped 1,184 malicious skills.
currentbits commentedon Aug 17, 2026
Research note (Governance Decay paper, arXiv 2606.22528): compaction silently drops in-context policy constraints — violation rate 0% to 30%+ after compaction, and adversarial compaction-eviction defeats all tested models. Mitigation is constraint pinning: enforce policy in the harness (tool-call interception), never in prompts, and re-inject a pinned policy block verbatim at every turn boundary. Also from Snyk Evo's Policy Agent: natural-language policy compiled to executable gates ('never push to main, require approval above ') as the authoring UX for this layer.
currentbits commentedon Aug 18, 2026
Deep-dive (Zed tool-permission engine): the precedence stack to adopt — built-in security rules > always_deny > always_confirm > always_allow > tool default > global default, with per-tool regex patterns (command/path/URL/query), case-insensitive by default, chained-command parsing across all shells (echo x && rm y checked per subcommand), non-overridable rm -rf / ~ /Users/willem rules, and a UI that writes config from the prompt ('Always for tool' vs 'Always for pattern'). Sandbox notes: .git never writable, create_directory cleaned up on deny, and the symlink-swap TOCTOU — resolve paths and fail closed between approval and sandbox invocation. Their explicit lesson: rules-based filtering is useless against a motivated agent; sandbox is not rules.
currentbits commentedon Aug 18, 2026
Round 18 intel from Devin Local (changelog 2026-07-29), their permission model matured in ways that map directly onto this governance layer:
deny:always wins regardless of level.Also filed this round: #509 (edit command before approve, interacts with allow-always keying) and #510 (CI/workflow diffs need hard human sign-off; Wiz/Snowflake incident).
currentbits commentedon Aug 18, 2026
Round 19 intel, three Cursor items plus a CVE:
currentbits commentedon Aug 18, 2026
Round 22, three governance principles from Claude Code's latest hardening (v2.1.220-224):
currentbits commentedon Aug 18, 2026
Round 23 intel: Factory Droid's
commandBlocklistsetting (v0.147.0) fills the missing layer in the permission stack: commands that can never run, even under full autonomy or skipped approvals. This is distinct from deny rules (which live inside the review/approve flow) and from sandboxing (which contains, not forbids). The blocklist is the absolute floor an org or user sets once: thinkrm -rf /,git push --forceto protected branches,kubectl deleteagainst prod contexts. For Solenta's matrix: three enforcement tiers make sense: blocklist (never, not reviewable), deny (visible rejection with reason), ask (default). Also from Droid: per-MCP-server risk levels and a quickmcp offshortcut (v0.138.0), and org-central governance of MCP/marketplace access (v0.152.0).currentbits commentedon Aug 18, 2026
Round 29 intel: bernstein (bernstein.run) ships an HMAC-signed, chained audit log for orchestration events, so the audit trail is tamper-evident rather than just append-only text. That is the right integrity bar for this issue's audit trail: each event references the previous event's hash, and verification is a local offline check. Also from bernstein: their scheduler is deterministic plain Python by design ("just don't put the LLM in the scheduler tick") with LLM-assisted parts (routing, best-of-N judge) explicitly opt-in and pluggable. A clean separation worth copying: deterministic core loop that is replayable and auditable, LLM judgment only at declared decision points.
currentbits commentedon Aug 30, 2026
Good questions, and they land on seams the design notes already worry about, so folding the answers in here.
On enforcement versus reporting: agreed, and that separation is a hard requirement, not a nice-to-have. The audit writer must live in the enforcing component, not in anything the agent can influence. Today Solenta only reports what flags it passes (the sandbox badge in the UI is pure reporting, which is exactly the credibility gap you describe). The plan is harness-level interception for tool calls plus OS sandbox for confinement, with the log appended by that layer, chained and tamper-evident per the bernstein pattern noted above. A denial record is written only by the thing that actually denied.
On the two sources of truth: yes, and this is already captured as the attribution requirement (a denied action must say which layer denied it, per the Devin note earlier in this thread). Your version is the sharper framing though: attribution has to cover disagreements in both directions, including a pass the matrix granted that Seatbelt then vetoed. Adding "record the deciding layer on every entry, allow and deny alike" to the checklist.
On declared versus executed for the proxy: yes, both sides go in the log. Declared intent is captured at the approval step (the exact command or mutation as presented and approved), executed arguments at dispatch, and the entry links the two. This is what makes the TOCTOU rules auditable after the fact: symlink-swap and edit-before-approve (#509) only stay honest if you can diff what was promised against what ran. Approval covers a specific declared action hash, not a scope; anything that deviates is a fresh decision, fail closed.
currentbits commentedon Sep 2, 2026
v1 slice (this thread): policy matrix + harness gate + HMAC audit + profile UI.
Seatbelt OS sandbox and gh-aw safe-outputs stay follow-ups. Enforcement will extend the existing #409
classifyToolseam on Claudecan_use_tool(electron/guardrails.js+electron/runner.js).electron/sandbox.jsremains reporting-only in this slice.Design in progress on thread
36cfee86-4dc4-4d12-8917-2c1f5568a4bc.11 remaining items
currentbits commentedon Oct 16, 2026
v1 implementation is up as PR #1655. It contains the matrix, the Claude gate with a re-check when the card is answered, the HMAC audit, and the profile UI. On a CI-like env, test:electron is 4825 pass / 0 fail and the renderer suite is 3103 / 0. Two deviations from the spec are listed in the PR body:
#803 (Seatbelt) is next, stacked on this branch.
Test applyAgentProfile snaps a mode the provider cannot honour (#262)
Merge origin/main into governance v1 (#262)
Governance layer v1: per-profile permission matrix, HMAC audit, Claud…
Governance v1 IPC contract: policy, agentProfileId, audit types (#262)
Governance v1 backend: matrix evaluator, HMAC audit, Claude gate (#262)
Governance v1 UI: profile rule editor, rule count, Advanced audit view (
Bind composer, Best of N and issue starts through threads.applyAgentP…
Dev fixture: applyAgentProfile applies the saved profile; manual pick…
Permission card: show governance layer, hide Accept all on profile.ask (
Governance UI copy: audit covers builtin decisions; modes that skip p…
Test applyAgentProfile snaps a mode the provider cannot honour (#262)
Merge origin/main into governance v1 (#262)