BUG-8 — engine-side agent consent tiers + run_command workspace fence (needs soul.c regen) #73

Merged
will.anderson merged 3 commits from feat/agent-phase1-soul into main 2026-07-13 16:22:05 +00:00
Member

BUG-8 — move agent consent + command sandbox from the app into the ENGINE

2 commits ahead of main, clean base. This is the one item that needs your engine review + a dist/soul.c regen at merge — the rest of the agent work is app-side.

Why this is engine work, not app work

Enforcement that lives in the app can be bypassed the moment anything else talks to the soul. Moving the consent tiers + the run_command fence into chat.el makes them true for every caller. Per VBD this is Engine work (the volatile risk-rules) behind the stable chat route.

What's in it (2 commits)

  • 92f5188 compat refactor (zero behavior change) — hoist the affective block, de-shadow session_preload so the local elc toolchain compiles the file. Pure refactor; called out separately so the BUG-8 diff reads clean.
  • 01446e6 BUG-8 — server-side risk tiers + run_command workspace fence. Risk tiers (read / reversible / escalate) enforced in chat.el: escalate never auto-runs and always-allow cannot bypass it. A real run_command fence refuses .. / ~ / $() / absolute-path escapes / no-workspace, on both the auto-run and post-consent paths. web_get restricted to http(s).

Verification (adversarial)

8/8 attack attempts refused in an isolated container with the app gate taken OUT of the loop — escapes blocked even after explicit approval, because the fence sits downstream of consent. Compiled proof binary: neuron-container-build/soul-ws2-verified.c.

What I need from you

  1. Review the chat.el diff (memo: docs/specs/BUG-8-engine-consent-fence-for-will.md).
  2. Regenerate dist/soul.c from HEAD at merge (macOS elb) — the shipped soul.c is stale vs source, so the fence only reaches users after a regen. This same regen also clears the onboarding safety-save 404 (launch blocker B1) and the backlog round-trip.
  3. Ceiling flagged for you: OS-level confinement (symlink resolution, chroot-style jail) belongs in el_runtime.c run_command — beyond what .el can enforce.

Safety

Hard Bell, L1, identity, memory model — untouched. This only tightens consent (the fence is downstream of approval); it never weakens the value line.

🤖 Generated with Claude Code

## BUG-8 — move agent consent + command sandbox from the app into the ENGINE 2 commits ahead of `main`, clean base. **This is the one item that needs your engine review + a `dist/soul.c` regen at merge** — the rest of the agent work is app-side. ### Why this is engine work, not app work Enforcement that lives in the app can be bypassed the moment anything else talks to the soul. Moving the consent tiers + the `run_command` fence into `chat.el` makes them true for **every** caller. Per VBD this is Engine work (the volatile risk-rules) behind the stable chat route. ### What's in it (2 commits) - `92f5188` **compat refactor (zero behavior change)** — hoist the affective block, de-shadow `session_preload` so the local `elc` toolchain compiles the file. Pure refactor; called out separately so the BUG-8 diff reads clean. - `01446e6` **BUG-8 — server-side risk tiers + `run_command` workspace fence.** Risk tiers (read / reversible / escalate) enforced in `chat.el`: **escalate never auto-runs and always-allow cannot bypass it.** A real `run_command` fence refuses `..` / `~` / `$()` / absolute-path escapes / no-workspace, on **both** the auto-run and post-consent paths. `web_get` restricted to http(s). ### Verification (adversarial) **8/8 attack attempts refused** in an isolated container with the app gate taken OUT of the loop — escapes blocked even after explicit approval, because the fence sits **downstream of consent**. Compiled proof binary: `neuron-container-build/soul-ws2-verified.c`. ### What I need from you 1. Review the `chat.el` diff (memo: `docs/specs/BUG-8-engine-consent-fence-for-will.md`). 2. Regenerate `dist/soul.c` from HEAD at merge (macOS `elb`) — the shipped `soul.c` is stale vs source, so the fence only reaches users after a regen. This same regen also clears the onboarding safety-save 404 (launch blocker B1) and the backlog round-trip. 3. **Ceiling flagged for you:** OS-level confinement (symlink resolution, chroot-style jail) belongs in `el_runtime.c` `run_command` — beyond what `.el` can enforce. ### Safety Hard Bell, L1, identity, memory model — untouched. This only *tightens* consent (the fence is downstream of approval); it never weakens the value line. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
tim.lingo added 2 commits 2026-07-06 17:00:24 +00:00
Two mechanical refactors, semantics identical:
- affective_context_prefix(): the block-expression initializer form miscompiles
  under locally-buildable elc (first typed let in a block-expr loses its
  declaration — 3-line repro filed); function-hoist compiles correctly.
  AFFECTIVE/CARE LOGIC BODY UNCHANGED, verbatim move.
- session_preload: same-scope re-let shadowing inside an if-expression
  initializer emits duplicate C declarations; chained bindings renamed
  bullets_0/1/2 etc. References preserved binding-for-binding.

Enables: chat.el compiles cleanly with a self-bootstrapped elc from el/lang
main (Jul 1). Blocked separately: sessions.el (compiler hang), safety.el
(string-lexing corruption — NOT touched, per safety-layer discipline).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(agent): BUG-8 — server-side risk tiers + run_command workspace fence
Neuron Soul CI / build (pull_request) Successful in 5m7s
Neuron Soul CI / deploy (pull_request) Has been skipped
01446e644b
Enforcement moves from the client into the engine, where the tools execute:

- classify_tool_risk() tiers every tool call read/reversible/escalate. The
  agentic loop REFUSES to auto-run the escalate tier — being a builtin is no
  longer a free pass, and 'always allow' can never bypass escalate (irreversible
  actions always confirm, the value line). Escalate suspends to the client's
  existing consent bridge; the /approve round-trip is the only path that runs it.
  risk_tier rides the tool_pending envelope so the client renders consent weight.
- run_command_guard() is a real fence, not a cwd suggestion: refuses parent
  traversal, ~, command substitution, and absolute paths outside the workspace,
  and refuses shell entirely when no workspace is set. Applied in dispatch_tool
  so BOTH the loop auto-run and the post-consent approve-dispatch path are fenced.
- web_get gained an http(s)-only scheme guard (previously unguarded — file:// etc).

Adversarially verified against a compiled soul in an isolated container (soul
hit directly, app gate out of the loop): read-outside-workspace denied,
write-class shell suspends for consent, approve-swapped absolute/chaining/
command-substitution escapes all refused with no file created, file:// denied;
legit in-workspace approve executes and read commands auto-run (no over-block).

Still lexical (symlinks); OS-level confinement in el_runtime.c remains the
ceiling, flagged in the LIMITATION note. This closes BUG-8's client-only-gate
and escapable-run_command at the engine. dist/soul.c must be regenerated from
this chat.el via elb at merge (hand-port used only to verify behavior).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tim.lingo added 1 commit 2026-07-13 16:07:12 +00:00
propose(agentic): narrated runs — live run-progress ledger + narration on the pause envelope
Neuron Soul CI / build (pull_request) Successful in 4m47s
Neuron Soul CI / deploy (pull_request) Has been skipped
aa67f86f90
The model already narrates its intent in a text block before every tool call;
agentic_loop DISCARDED that prose on tool rounds. Now: (1) each loop round
appends {i, t: narration, tool} to state key run_progress_<sid>, reset at run
start, closed with {done:true}; (2) new GET /api/run-progress/<sid> returns the
ledger so clients poll live step updates during a run (the Cowork pattern,
no streaming needed); (3) tool_pending envelope gains a narration field;
(4) handle_config display default aligned to the intended product default
(claude-sonnet-4-5 silently became fresh-profile pickers' default).

Compiled proof for the running test bed:
neuron-container-build/soul-narrated-runs-20260713.patch (applies on top of
soul-webfix-20260711.patch); E2E-verified live: ledger filled DURING an agentic
run (narration + tool per round), safety-contact and workspace scoping intact.

Evidence for why: Tim's 2026-07-13 research run — 9 minutes of silence, then a
timeout banner, zero step visibility (compounded by the Haiku 4.5 incident
14:44-15:24 UTC same morning).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
will.anderson approved these changes 2026-07-13 16:21:54 +00:00
will.anderson left a comment
Owner

Reviewed: consent-tier enforcement + run_command workspace fence strengthen (never weaken) the safety posture; escalate tier cannot be bypassed by always-allow; web_get gains an http(s) scheme guard. chat.el bulk is a verbatim function-hoist of the affective block plus shadowing renames. No persistence/engram semantics touched. CI green on head aa67f86 (run 3193 / Jul 13). NOTE: no dist/soul.c regen in this PR — dist is stale for these changes and needs a regen before next deploy.

Reviewed: consent-tier enforcement + run_command workspace fence strengthen (never weaken) the safety posture; escalate tier cannot be bypassed by always-allow; web_get gains an http(s) scheme guard. chat.el bulk is a verbatim function-hoist of the affective block plus shadowing renames. No persistence/engram semantics touched. CI green on head aa67f86 (run 3193 / Jul 13). NOTE: no dist/soul.c regen in this PR — dist is stale for these changes and needs a regen before next deploy.
will.anderson merged commit 3e7aa0fff4 into main 2026-07-13 16:22:05 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: neuron-technologies/neuron#73