context/message previously defaulted to a <context source="…">…</context>
wrapper. No model is trained on a <context> tag either, and message
framing does not belong on the session surface: the surface projects the
durable log, and a caller that wants a frame formats its own content —
which the one heavy producer (workspace-context) already does with its own
<system-reminder> frame, opting out via 'raw'. The tag only added
machinery — ContextEnvelope plus an envelope field threaded through
InjectOptions, HookContext, the context/message event, and the agent-loop
inject/additionalContexts plumbing.
context/message now projects its content verbatim as a user-role message,
sharing one deriveEventMessage case with user/message and steering/message.
ContextEnvelope and every envelope field are removed; context/message.meta
still carries durable, model-hidden JSON state. Regenerated catalogs and
website API; refreshed the three affected keyless snapshots (envelope field
only; timestamps unchanged).
Broadens and renames the steering Agent Note to cover both envelope
removals as one decision.
Agent Note: .agents/notes/implemented/simplification/2026-07-20-unwrap-injected-content-envelopes.md
Review follow-up (tianyicui): plan mode and the sandbox are orthogonal
AXES, not just orthogonal state — entering plan must not change what the
sandbox enforces, matching Codex's separation of Plan/Default
collaboration presets from sandbox and approval settings.
ModeDefinition.access, the bash/resolve-mode clamp, and both cap-derived
guards are removed; a ModeDefinition is exactly { section }, and a mode
now carries only its guidance section plus the exit_plan_mode review.
The bash seam's resolveMode + waterfall go with their only listener:
dsh-bash and dsh-tool-bash revert to master byte-for-byte, and the
dsh-mode → dsh-bash dependency edge is gone. A deployment that wants
kernel-enforced read-only planning pairs the mode picker with the
independent sandbox-mode option, in either order.
The RFC archives this as the second removed enforcement shape (after
the interim allowlist) with the same restart trigger — effects
self-declaration; the orthogonality FAQ now answers with the two-axis
rule. The plan example demonstrates the axes side by side, and the
re-recorded fixtures pin the guidance-only section.
A subagent child's recursion depth lived only in runtime AgentOptions,
so a persisted child came back from resume counted as top-level and
maxDepth stopped binding after every restart. Add
SessionHeader.delegationDepth, round-trip it through the JSONL and
SQLite backends (SQLite schema v5), restore it on agent-loop resume,
and write it when the in-process backends create a child. The seam now
owns the shared depth vocabulary (delegationDepthOf): the persisted
header is authoritative and monotone — runtime options may deepen it
but never lower it.
Semantic resolutions beyond line merges:
- The bash seam keeps resolveMode + the bash/resolve-mode waterfall on
master's task-free BashExecutor (run/start/resolve only; BashProcess
handles); tool-bash consults it at its stamping site and escalation
baseline on master's render/background split, with a waterfall test on
the recording executor.
- dsh-mode's BASH_FAMILY narrows to ['bash']: bash_output/bash_kill are
replaced by the kind-generic task_output/task_kill, which span every
task kind and only observe or stop work, so the access cap withholds
only the starter it can reason about.
- The plan-mode snapshot suite adopts master's pin grammar (tool-schema
sidecars; the expectedHeaderSnapshots extension is gone — the exit
transition deltas, and entering-before-turn-1 needs no second
snapshot); modes-advertise joins the plan header class (no-model, so
membership is vacuous). Fixtures re-recorded on the acp-demo bin;
the replay overlay gains the passthrough sandbox runner.
- examples/plan-acp-agent rewires to @deepseek-ai/dsh-acp-demo and drops
its tool-bash entry (the spine bundle now composes it); dsh-stdio (the
renamed stdio-chat home) keeps its /mode command and gains the dsh-mode
peer edge; the acp bridge keeps the modes surface beside master's
permission presets.
- mode README gains the Model Experience / Known Limitations sections the
new README gates require; AGENTS.md ceiling 1370 → 1440 for the kept
mode/ layout line and Agent efficiency section.
Extend SandboxMode enforcement from bash to the filesystem tools, the sandbox
RFC's deferred cross-family phase.
- dsh-sandbox-policy (new, ctx.sandboxPolicy): the single home for the
deployment default mode + workspaceRoot and the per-session override event,
renamed bash/sandbox-mode -> sandbox/mode and moved here with its fold/setter.
Decouples the bash seam from dsh-session.
- dsh-fs-sandbox (new): SandboxedFileSystem extends LocalFileSystem and fences
write/edit by the per-call mode (read-only denies, workspace-write contains to
the workspace + temp roots via the shared writableRoots, danger passes
through); reads pass through. Structured FS_SANDBOX_DENIED; in-lock parent
re-canonicalization. A policy fence in trusted code, not a kernel boundary.
- dsh-sandbox: the shared escalation kit (writableRoots, the strictly-wider
ladder, denial/hint markers, approveEscalation) both tool families use;
approveEscalation takes a structural approver so dsh-sandbox gains no
approval/agent dependency, and both tools stay duplication-free.
- tool-fs: write/edit advertise sandbox_permissions/justification under a
confining ctx.fs, map FS_SANDBOX_DENIED to the shared [sandbox: ...] marker,
and resolve the same one-approved-wider retry.
- examples/acp-agent: composes sandbox-policy + fs-sandbox, drops the gating
that disabled the fs stack under confined modes.
RFC docs/rfc/implemented/feature/2026-07-14-cross-family-fs-sandbox.md; the old
sandbox RFC's In-process/deferred/FAQ sections updated to shipped fact.
Conflict resolution beyond line merges: the ACP bridge's mode/set
re-notify moved inside master's new containment finally (a throwing
presenter must not desync the picker), and session/new keeps the modes
advertisement beside master's plain object return. dsh-mode's boundary
flush moved off the session/event feed onto the loop's interception
seams (agent/prompt-submit / agent/turn-continuation): master's scoped
dispatch made post-commit session observers observe-only — an append
from one re-enters the publishing append — while the two waterfalls
fire outside any log emit and bracket the same boundaries; mode.spec's
boundary helper now dispatches those seams via agentEvents, and the
containment tests stub only the mode/set append. Catalogs, doc graphs,
and the module graph regenerated.
A preset names a bundle of the two mechanism knobs — request =
workspace-write + ask, yolo = danger-full-access + never — so the editor
shows ONE 'Permissions' select where the sandbox-mode and approval-policy
tiers stay orthogonal capabilities (the Codex /approvals shape: presets over
two dials). ctx.permission (dsh-permission) owns the config-defined table,
validates the default preset's bundle against the composed knob defaults at
load (fails loud), and writes a switch THROUGH: one log-only
permission/preset event (the audit fact reverse-mapping cannot recover —
the planned 'agent' preset shares request's knob values and differs only in
composed policy) plus each knob event via its own setter, deduped — a
net-zero switch appends nothing. Every knob consumer keeps reading its own
fold, untouched.
The current preset DERIVES from the effective knob values — the fold breaks
bundle ties, a knob state outside the table is the reserved 'custom' value
(a state, not an error: shown while it holds, switchable FROM, never a
target), and defaultPreset disappears (zero-event state reverse-maps from
the composition defaults).
The ACP bridge drops the two per-knob selects for the one preset select
(advertised only when ctx.permission is composed); pending/anchor/no-op
semantics carry over unchanged, with the no-op echo acknowledged before
vocabulary validation so a client re-pushing a derived 'custom' current
never errors. The sandbox variant example composes the
service with a workspace-write default; the permission-switching,
escalation-approved and escalation-rejected scenarios are re-recorded under
it (escalations now target an outside-workspace /tmp path under
danger-full-access, self-cleaning) and config-options is re-authored on the
single-select wire.
A ModeDefinition is now exactly { section, access? }; unknown keys (a
tools list included) fail loud at load. What plan mode still does: the
guidance section, the exit_plan_mode visibility rule (plan only, both
soft surfaces), the access cap's bash/resolve-mode clamp, and the two
cap-derived pre-execute guards (the bash trio is withheld when no
confining executor can honor the cap; sandbox escalation is denied
while it holds). The general deny-by-default gate and the assemble
allowlist filter are gone: which tools a mode admits is an effects
question, and a hand-maintained name list mislabels it — it must track
every composed tool and rots silently as tools arrive. The dimension
returns as a consumer of effects self-declaration on tool definitions
(MCP ToolAnnotations as the template) — rationale and restart trigger
archived in the RFC's Alternatives/Deferred; the interim guidance-only
non-shell restraint is priced in Consequences.
Exiting plan is now a pure removal (the exit tool + section), which the
delta encoding CAN express: the re-recorded plan-mode fixture pins one
plan-shaped initial header snapshot plus one header-delta instead of
two snapshots.
A ModeDefinition may declare access: the widest sandbox access shell
commands run under while the mode holds, on the SANDBOX_MODES ladder.
The bash seam gains the resolution point to hang it on: BashExecutor.
resolveMode(session) folds override ?? default and dispatches the new
bash/resolve-mode waterfall; dsh-tool-bash consults it at both the
stamping site and the escalation baseline; dsh-mode's clamp listener
takes the ladder minimum per call. Two independent log folds compose at
read time — the mode never writes the sandbox knob, so the two switch
in any order and the knob re-emerges intact on exit.
The built-in plan definition ships access: read-only with the bash trio
allowlisted CONDITIONALLY: both policy layers admit bash/bash_output/
bash_kill only while a confining executor is mounted (an unconfinable
shell cannot honor the cap), and a bash call carrying sandbox_permissions
under a cap is denied at the gate — no widening mid-mode; the widened
step belongs in the plan.
examples/plan-acp-agent swaps bash-local for sandbox-local +
bash-sandbox (workspace-write default, clamped read-only inside plan)
plus the approval seam; the re-recorded plan-mode arc runs a real cat
inside plan under the clamped sandbox, and modes-advertise now pins the
sandbox-mode and approval config options. RFC amended to the landed
shape (access cap section, orthogonality FAQ, deferred item resolved
into effects self-declaration).
The stack rebases onto a moved master through its base branch. Beyond
mechanical unions (both branches' demo scripts, example rows, service
roles, tool lists, acp deps, doc budgets — each side fit alone, the
union needs the higher ceilings), three semantic reconciliations:
- The ACP bridge now carries BOTH per-session surfaces: the sandbox
stack's config options + approval answerer and this branch's session
modes; session/new and session/load advertise modes AND configOptions
side by side.
- The feature matrix supersedes the sandbox stance per the RFC's
second-lander rule: session/set_mode and current_mode_update flip to
shipped-by-dsh-mode, config-option rows stay as #169 wrote them, and
§6 records both landed features under the picker-to-modes /
knobs-to-config-options division.
- The snapshot pin grammar (#254: one header snapshot + declared deltas
+ a Markdown prompt golden) gains a symmetric declaration for what a
delta cannot express: expectedHeaderSnapshots — a plan-mode flip
resorts the canonical tool list, so its widening lands as a second
full snapshot, now its own Markdown section. The pin-less-class and
model-turn-only-pin amendments carry over; new fixtures cover the
extended writer paths, and the plan-acp-agent scenarios re-recorded
under the merged composition (the app now bundles the skill tool)
with the suite's refresh mode wired through.