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
Two adapters now render four of Reef's node kinds and reject code_extension, each because the evolved code would run with more privilege than the agent it configures.
codex (#201): Codex's mechanism is lifecycle hooks, whose Command handlers are subprocesses spawned outside the workspace-write sandbox that contains the model's own commands. Hooks also need a persisted trust record a fresh CODEX_HOME never has.
terminus (#209): Terminus 2 is a Harbor agent class, and a Reef module would be loaded in the runner's own process — outside the task container entirely. That adapter also declares self_isolating, so Reef's bubblewrap jail is off: there is no boundary left to contain it.
The shape is the same in both: the vendor isolates the commands the model writes, not code supplied alongside the agent. pi, opencode, dsh, hermes, and native accept code_extension because their extension point runs inside the agent's own process, under whatever containment the episode already has.
This is not urgent. Meta-Harness, the method these adapters exist for (#42), searches over {agent_command, rules, skill} — recipes/meta_harness/.../composition.py sets ALLOWED_NODE_KINDS to exactly that — so nothing planned needs the kind on either adapter.
Concrete use cases
A method that evolves a PreToolUse guard and wants to measure it on Codex as it can on pi.
A Terminus context policy that rewrites the message list before each model call: its own compaction instead of enable_summarize, or notes carried between turns. This is the seam with the most headroom on the chronic clock-hit tasks in [Example] Add a Terminal-Bench harness self-evolution example #6, and the archived ReefTerminus prototype (archive/bo/reef-terminus) implemented exactly it.
A cross-adapter comparison where a tree must render identically everywhere, so a rejected kind does not silently change the instrument.
Proposed outcome
Reef owns the boundary for evolved code the vendor will not contain: the module or handler runs in a jail Reef controls, the way SandboxExecutor already jails the episode, and the adapter renders whatever entry point points at it. Until then, rejecting at render is the correct behaviour and both adapters should keep doing it.
Worth settling as part of the design: whether one mechanism serves both cases, given codex's is a subprocess Codex spawns and terminus's is an in-process module Reef loads. The terminus case may be the harder one, since assemble(state, request, files) has to return a message list into the calling process rather than just run to completion.
A smaller acceptable outcome is a decision to reject the kind permanently on both, recorded here, with each descriptor dropping its placeholder code_extension path so the adapters stop implying support they do not have.
Alternatives and workarounds
Express the behaviour as skill or rules. Works for guidance, not for mechanical enforcement or for context assembly, which is the point of the kind.
Enable it anyway. On codex that means --dangerously-bypass-hook-trust, whose own help says it is for automation that already vets its hook sources; on terminus it means exec in Reef's process with the jail off. Both run gate-promoted code above the model's own privilege.
Compatibility and maintenance
Additive: both rejections and their render tests stay until a boundary exists. Whoever builds it owns a second sandbox entry point distinct from the episode's, and it needs the same fail-fast treatment SandboxExecutor.preflight already gives, so a hosted deployment that cannot isolate refuses rather than degrades.
Submission checks
I searched open and closed issues, pull requests, and RFCs for related work.
I described the problem and use cases without assuming one implementation.
I have not started a large implementation that still needs project-direction approval.
Primary area
Harness, recipes, or surfaces
Problem
Two adapters now render four of Reef's node kinds and reject
code_extension, each because the evolved code would run with more privilege than the agent it configures.codex (#201): Codex's mechanism is lifecycle hooks, whose
Commandhandlers are subprocesses spawned outside theworkspace-writesandbox that contains the model's own commands. Hooks also need a persisted trust record a freshCODEX_HOMEnever has.terminus (#209): Terminus 2 is a Harbor agent class, and a Reef module would be loaded in the runner's own process — outside the task container entirely. That adapter also declares
self_isolating, so Reef's bubblewrap jail is off: there is no boundary left to contain it.The shape is the same in both: the vendor isolates the commands the model writes, not code supplied alongside the agent.
pi,opencode,dsh,hermes, andnativeacceptcode_extensionbecause their extension point runs inside the agent's own process, under whatever containment the episode already has.This is not urgent. Meta-Harness, the method these adapters exist for (#42), searches over
{agent_command, rules, skill}—recipes/meta_harness/.../composition.pysetsALLOWED_NODE_KINDSto exactly that — so nothing planned needs the kind on either adapter.Concrete use cases
PreToolUseguard and wants to measure it on Codex as it can onpi.enable_summarize, or notes carried between turns. This is the seam with the most headroom on the chronic clock-hit tasks in [Example] Add a Terminal-Bench harness self-evolution example #6, and the archived ReefTerminus prototype (archive/bo/reef-terminus) implemented exactly it.Proposed outcome
Reef owns the boundary for evolved code the vendor will not contain: the module or handler runs in a jail Reef controls, the way
SandboxExecutoralready jails the episode, and the adapter renders whatever entry point points at it. Until then, rejecting at render is the correct behaviour and both adapters should keep doing it.Worth settling as part of the design: whether one mechanism serves both cases, given codex's is a subprocess Codex spawns and terminus's is an in-process module Reef loads. The terminus case may be the harder one, since
assemble(state, request, files)has to return a message list into the calling process rather than just run to completion.A smaller acceptable outcome is a decision to reject the kind permanently on both, recorded here, with each descriptor dropping its placeholder
code_extensionpath so the adapters stop implying support they do not have.Alternatives and workarounds
skillorrules. Works for guidance, not for mechanical enforcement or for context assembly, which is the point of the kind.--dangerously-bypass-hook-trust, whose own help says it is for automation that already vets its hook sources; on terminus it meansexecin Reef's process with the jail off. Both run gate-promoted code above the model's own privilege.Compatibility and maintenance
Additive: both rejections and their render tests stay until a boundary exists. Whoever builds it owns a second sandbox entry point distinct from the episode's, and it needs the same fail-fast treatment
SandboxExecutor.preflightalready gives, so a hosted deployment that cannot isolate refuses rather than degrades.Submission checks