Status: procedure and history reference. The surface-agnostic contract lives in AGENTS.md §17 and stays always-on. This file holds the guard implementations, the BI trail, and the full §7 decision text. Single source of truth for the decisions themselves remains the unified-delivery-surfaces spec. Relocated from §17 by BI-0020D511 Phase 1; no rule was dropped.
→ Spec (single source of truth): docs/superpowers/specs/2026-06-05-unified-delivery-surfaces-execution-alignment-design.md. This section is the operational pointer; the §7 decisions are WWMD-ratified and final.
- Four peer surfaces, one process. DPF delivers through Claude Code, Codex CLI, Grok, and the embedded Build Studio — peers, not a hierarchy. None is privileged; work never depends on any one being healthy. All four advance the one common evidence-gated lifecycle (
ideate → plan → build → review → ship), right-sized by(type × size); each transition runs the gate check and nothing is rubber-stamped. (Grok joined as a first-class external coding surface per2026-05-31-grok-first-class-support-design.md; the three external CLIs — Claude Code, Codex, Grok — are the host-worktree surfaces, Build Studio is the embedded surface.) → kernel principle - No surface is mandatory — choose by fit; “Build Studio for all development” is retired. Any earlier guidance that all development must go through the embedded Build Studio (it predated this section) is retired by founder directive (2026-06-26). The peer principle above is operational, not aspirational: pick the surface that fits the work and the available tooling. An external Claude Code / Codex / Grok build — implement in a host-worktree, claim a workroom, record evidence, ship the PR — is fully equal to an embedded Build Studio build and must never be force-routed through the embedded pipeline. Embedded BS is the right tool when its in-portal codegen/review fits; it is not a gate every change must pass, and delivery must never block on it being healthy (e.g. when the embedded pipeline is degraded or its reviewer is the bottleneck, do the work as an external build). → kernel principle
- Large/complex work may run externally even when centrally tracked. The desire for central tracking is satisfied by the MCP/capsule/evidence plane, not by forcing work into the embedded BS executor. Build Studio is intentionally narrower than the host CLI surfaces today; when a task is too large, subtle, cross-cutting, tool-sensitive, or long-running for BS to handle well, choose an external host-worktree surface and keep it centrally visible through a Workroom, backlog links, evidence records, and PR health. Do not tell the operator “this must go to Build Studio” merely because it is feature work.
- MCP is the coordination plane. Work tracking, claims, and gate evidence live in the DPF MCP substrate (backlog/
FeatureBuild/WorkCapsule, workroom + lease claims, evidence tools), regardless of Build Studio. If it isn’t in the MCP plane, it didn’t happen — a surface that works without claiming a workroom and recording evidence is invisible to coordination and cannot advance a gate. → kernel principle - Claim a workroom before you work — every surface, including the external CLIs. Because the MCP plane is the coordination substrate, an external agent (Claude Code, Codex, Grok) opens a Workroom at the start of an effort —
create_work_capsulefor new work, oradopt_worktreeto attach an existing branch/worktree — then records evidence at phase boundaries (record_external_development_evidence,record_capsule_evidence) and releases on exit, so the work shows up in the same progress/evidence/document tracking as an in-portal build. Build Studio auto-attaches its workroom; external surfaces must claim theirs. As of 2026-08-28 that claim is automatic and enforced. both worktree-creation paths claim before they hand the tree over — the Claude Code hook (worktree-create.mjs) and the shell script the rest of this runbook uses (scripts/new-dev-worktree.sh, viascripts/bind-worktree-cli.mjs) — so a worktree is born bound whichever way it was made, andpackages/dpf-skill-pack/hooks/workroom-claim-guard.mjsrefuses an edit or a commit on a feature branch that no live claim covers (DPF_WORKROOM_CLAIM_ENFORCE=0downgrades it to advisory for an install where binding genuinely cannot run;DPF_ALLOW_UNCLAIMED_WORK=1is the recorded per-command bypass). Until then the rule was prose and behaved like it: 31 of 91 live branches carried no binding at all, a 35% miss rate unchanged since the rule was written. Runnode scripts/reconcile-workroom-bindings.mjs(dry run;--applyto bind) to reconcile branches created before this, or after any period where MCP was unreachable — bind-at-birth only ever governs the future. Both paths are named deliberately: binding shipped on the hook path alone first, and coverage measured 95% right after reconciliation then fell back to 82% within a day as new branches arrived through the shell path. Automating one of two entry points relocates the leak rather than closing it. Ifadopt_worktreerefuses withbranch_occupiedagainst a complete capsule, that branch’s work is finished and the worktree is a leftover: reap it or start a new branch rather than reopening closed work. Degrade gracefully: if the MCP plane is unreachable, do the work and reconcile the workroom afterward — never block local editing on workroom availability (work never depends on any one surface being healthy). Resuming another agent’s in-flight effort — start-by-one/finish-by-another — is the workroom-handoff path being built under EP-UNIFIED-TRACKING (BI-51787ECD); until it lands,adopt_worktreethe in-flight branch and continue from the workroom’s recorded evidence. → spec2026-06-19-unified-build-studio-tracking-all-surfaces-design.md - Central WIP via the workroom plane — the unit of WIP is the Workroom, not the Build Studio build (founder-directed 2026-06-26). Sandboxes and shared singleton leases are finite, so the platform must see total WIP across all four surfaces. Every surface registers its workroom centrally (Build Studio auto-attaches; the external CLIs
create_work_capsule/adopt_worktree), and the WIP count and any capacity limit derive from active workrooms across all surfaces, gated by the real scarce resources — the shared Build Studio sandbox and the shared:3001/singleton leases — not a Build-Studio-only build count. The BS cap (apps/web/lib/build/wip-cap.ts) gates only BS-sandbox contention; external Claude Code / Codex / Grok work runs in its own host worktree, is never blocked by the BS cap, yet its active workrooms still COUNT in the unified WIP (apps/web/lib/build/unified-wip.ts). Funneling work through Build Studio to gain central tracking is retired and futile — external code work is first-class, made visible by workroom registration, not by funneling. → kernel principle - Governance approves evidence, not provenance — the keystone. A gate reads only its required evidence fields and never branches on which surface produced them; that is exactly what makes the surfaces interchangeable. → kernel principle
- Thin adapters behind a stable contract. Claude Code, Codex, and Grok ship updates frequently; the surfaces are swappable adapters behind the gate/evidence + MCP + lease/worktree/sidecar contract. No surface-version-specific mechanics in the doctrine — if a rule would break when Claude, Codex, or Grok bumps next week, it belongs in a thin adapter, not the contract.
- Hide complexity from layman users. The coordination plane is backstage. Non-technical users see work + status + outcomes (progressive disclosure via the AI Coworker panel, §7 Q3), never worktree names, container ids, evidence JSON, or gate predicates; operator-grade plumbing stays admin-only.
§7 decisions — hard rules (WWMD-ratified 2026-06-05):
- Worktree canonical location = dedicated sibling
D:/DPF-worktrees/<topic>⟦runtime: install-local path — Windows shape; §4 gives the macOS/Linux equivalent⟧ for all three host CLI surfaces (Claude Code, Codex, Grok). The tool-native.claude/worktrees/<name>nesting inside the root clone is not the convention — treat it as a hard error to migrate. Every worktree is born governed (topic branch offorigin/main, MCP + toolchain seeded,COMPOSE_PROJECT_NAMEisolated, workroom claimed) and is reaped whenidle/done(janitor BI-DBF3F426). → kernel principle - Tooling-upgrade = operator-triggered quiesce-reap-upgrade. Session = claimed workroom; session end reaps its sidecars (
app-server,node_repl, npx MCP children). Upgrading Claude Code / Codex (incl. the WindowsApps Store package) runs a first-class operator-triggered quiesce → reap → upgrade → resume routine; orphaned sidecars must never pin a tool against update. → kernel principle :3001and every shared singleton are lease-gated. Runtime-bound gates run only throughclaim_nonprod_environment_lease(environmentKey="local-integration-ci"); the:3001Contributor preview folds into that lease (§7 Q5). ⟦runtime: install-local port — the lease rule is doctrine, the number is not⟧ No per-branch CI images, no silent re-bind of a held shared singleton, no ad-hocdocker run/compose upfrom a surface, and never reachable from outside the host — no tunnel, public URL, or non-loopback bind, because the preview writes to the live database and holding the lease permits use, never exposure. Deterministic preview claim keys preserve FIFO while active or queued; released, cancelled, or expired history advances through bounded monotonic attempt keys without changing the owning session or target-worktree branch identity. → kernel principle- Admission reserves the work the claimant declares. Exact gates request the canonical slot-manifest capability and therefore reserve the builder and host-stage envelopes before admission. Contributor previews request no runner slot, so they remain in the same FIFO/provider-exclusion pool but use the ordinary host-safety floor; reserving an unused build stage can deadlock the preview that owns stale-runtime cleanup.
- Contributor preview authority is live, not ceremonial.
scripts/dev-portal-lease.sh refreshsamples host pressure through the samelocal-ci-host-pressureprimitive as the gate before admission, then remains in the foreground as the preview’s lease keeper. Keep that process running for the whole UX exercise. It renews below the registry heartbeat cap; a renewal/admission failure or process stop shuts downdev-portalbefore releasing its lease. A detached container with no keeper is not a governed preview, even if an earlier command printed a lease id. - Enforced, not just documented. A
PreToolUseguard (lease-guard.mjs, in the pluginhooks/hooks.json) refuses ungoverned dev-server launches (pnpm/npm/yarn dev,next dev,turbo dev,dev-portal-start). Governed path:claim_nonprod_environment_lease→ run on the leased runtime, heartbeat withrenew_nonprod_environment_lease, release on exit (theSessionEndreaper also releases). Emergency bypass: prefixDPF_ALLOW_UNGATED_SERVER=1. Codex and Grok inherit the same guard (BI-CA0ED781); functional confirmation there is pending, so comply by construction (claim before you launch). Leases are TTL-capped (MAX_LEASE_TTL_MS) and reaped if heartbeating stops. - Root-clone protection — enforced. A
PreToolUseBash guard (root-clone-guard.mjs) refuses a recursive-force delete (rm -rf,Remove-Item -Recurse,git clean -fdx) that would follow a junction into — or target — the shared root clone, and raw root-clone git state movement (git switch/checkout/reset/pull/merge/rebase) that strands new sessions on a dirty tree. Junction-safe removals stay allowed (non-recursivermdir,git worktree removewithout--force).git worktree remove --forceis NOT junction-safe on Windows — it follows anode_modulesjunction into the root (see below, BI-F6AC1A56). Emergency bypass: prefixDPF_ALLOW_ROOT_CLONE_MUTATION=1. Structural fix: the canonical sibling baseD:/DPF-worktrees/<topic>via aWorktreeCreatehook (BI-6B02FEE5) + the worktree janitor (BI-DBF3F426). - Root-project data-volume protection — enforced. A
PreToolUseBash guard (compose-guard.mjs) refuses a rawdocker compose up/create/restart/runthat would (re)create PostgreSQL on the rootdpfproject, plusdown --volumeson it — the path that once silently swapped the live DB onto a stale volume. Governed update path:/ops/self-upgrade;scripts/redeploy-portal.*andpromote.shuse--no-deps portaland stay allowed, as do any isolated project (COMPOSE_PROJECT_NAME=dpf-<topic>/-p),build, and plaindown.scripts/lib/compose-safety.mjscarries the same rule for harness callers. Bypass:DPF_ALLOW_ROOT_COMPOSE_UP=1orDPF_ALLOW_DESTRUCTIVE_COMPOSE=1. Backstop: a boot-time DB-continuity check (apps/web/lib/operate/db-continuity.ts) fails loud on a reverted volume. - Auto-worktree placement — enforced for Claude Code (BI-6B02FEE5). A
WorktreeCreatehook (packages/dpf-skill-pack/hooks/worktree-create.mjs, same pluginhooks/hooks.json) replaces Claude Code’s defaultgit worktree addso an auto-created worktree (the--worktreeflag / subagentisolation: "worktree") lands at the canonical sibling base<dirname(root)>/<basename(root)>-worktrees/<name>(e.g.D:/DPF-worktrees/<name>,~/dpf-worktrees/<name>) offorigin/main— never nested inside the root clone at.claude/worktrees/. This is the full-enforcement, auto-create form of the contractscripts/new-dev-worktree.shalready applies to the MANUAL path. It fails safe: on any error it falls back to the default nested location (still protected by the root-clone guard above), so worktree creation is never broken. Codex/Grok have noWorktreeCreateevent — they get the canonical base viascripts/new-dev-worktree.sh(adpf worktreeCLI wrapper is the follow-up). Live-tested on this host; functional confirmation of Claude’s consumption of the hook output is pending, like the lease-guard. - Worktree removal is junction-safe (BI-F6AC1A56). ⟦runtime: Windows-only hazard — junction-follow does not occur on macOS/Linux; still route removals through the janitor⟧ Never
git worktree remove --forceby hand on Windows (junctions follow into the root clone). Route removals throughscripts/lib/junction-safe-worktree-remove.mjs/ the janitor. Hygiene: session reaper is primary; fleet soak is flag-gated; dry-run free; live Tier-A only with operator go — skilldpf-worktree-hygiene(BI-413FD81C).
- The live install advances only via the self-upgrade pipeline, and a built image carries the identity of its bytes — stamp == built HEAD == target, asserted pre-swap,
DEPLOYED_SHApopulated, fail loud on divergence (BI-5B6C1C35). No surface hand-advances the root clone HEAD or rebuilds the portal to “update”; never trust a version label over the bytes. → kernel principle - A Workroom for a backlog item must be BOUND to it, not merely anchored at it.
Workroom.backlogItemIdis the column every subject lookup keys on — reviewer recovery ingoverned-work-claim.ts, andsubjectWhereinbacklog/initiative-readiness/repository-artifact.ts, which sits behind plan coverage and canonical-design resolution. AnoutcomeAnchornaming the item is invisible to all of them.create_workroom,adopt_worktreeandclaim_backlog_item_for_workall resolve a suppliedbacklogItemId— or abacklog-itemoutcome anchor — onto that column, refuse an id that does not resolve rather than creating an unbound room, and verify the stored row carries the binding before reporting success (a report of the request is not a report of the result). Historic rooms created before this may be anchor-only and therefore unreachable from the completion gate’s “no live Workroom is bound to this item” recovery;node scripts/reconcile-workroom-bindings.mjsis the reconciliation path. Fixed for adoption and for the argument name in earlier passes (see the comments inadopt-backlog-binding.ts), and for creation in a later pass.