Yoke documentation
Worktree lanes, path claims, and scoping
The rules file every session loads carries the short normative form of each rule. This document is the deep home the rules file points at: the same rules with the reasoning, the worked failure modes, the flag matrices, and the edge cases that decide close calls. Read the section you need before the action it governs — nothing here is optional background, it is simply longer than a startup channel can carry.
Execution levels and worktree lanes
An execution level is an ordered capability band whose options are exact launchable selections; a registering session is labeled with the level whose option matches its harness, model, and effort (universe levels, or a project's session-routing override — see execution levels). Its name and glyph identify the group on the board and dashboard; it carries no skill permissions. Workflow bindings select stage skills, and explicit staffing assigns work.
A worktree lane is a registered code checkout protected by the item work claim. Its branch, path claims, verification, and merge contracts isolate implementation work. An execution-level label never grants checkout authority.
Worktree discipline
- NEVER use
--no-worktreeunless the user explicitly asks. NEVER write implementation code on main. - When the pinned definition selects
implementwithworktrees=single_implementation_lane, the same session that ran preflight and acquired the claim continues through that bound implementation/review segment. When it selectsconductwith generated tasks and worker/integration lanes, each dispatched lane acquires its own work claim. Authority over every lane is the work claim (validated per call bylint_session_cwd); launchercdbehavior is only convenience. - Do not jump across a binding or invent a destination stage. The active skill advances only inside its pinned half-open segment; the next skill starts at
through_stage_idas a fresh command entrypoint. Delivery stages and no-run shortcuts apply only when the pinned delivery policy and skill binding declare them. - Pre-implementation authoring activities run on main unless their pinned policy explicitly provisions a lane. Every development-entry skill — Dash, Issue implementation entry, Epic task activation, Blitz — creates or reuses the item's registered worktree immediately after the claim, read, and minimal survey its own preparation requires, and before any deeper investigation or edit; Issue implementation entry and Epic task activation already provision that worktree atomically before any code is read, so Dash and Blitz carry the explicit ordering in their own skill steps. Preparation starts from verified-current upstream, whatever the workflow. One shared step in worktree preparation (
repo_upstream_freshness, reached throughworktree_preflight.run_preflightandcreate_worktree) fetches the branch the item's project declares as its default from the remote git records as tracking it — neither name assumed, and neither the checked-out branch nor the checkout the caller happens to stand in is a substitute for one: an item whose project declares no default branch (the folder-project floor) is gated on nothing rather than on an unrelated repository. Freshness is established or preparation refuses: a remote-backed project whose remote cannot be read — failed fetch, no remote recorded as tracking the branch, unreadable branch or comparison — reportsverified=False, names no revision to start from, and blocks asupstream-unverified. There is no implicit offline fall back to the local branch, because that is precisely the silent stale start the step exists to prevent; a project with no remote at all is the different, verified answerno_remote(local-only, silent). On an established reading, a local default branch with no commits the remote lacks is fast-forwarded and the new lane cut from that verified revision; an uncommitted change blocking the fast-forward, or a default branch checked out elsewhere, leaves everything untouched and still hands the lane the fetched upstream revision, which is current. A diverged branch refuses instead (upstream-stale, pending reconciliation): its local commits are preserved and reported, never replayed or discarded, but the only base a lane could take there is local — missing the commits just fetched — so the lane is not created rather than started stale. Ahead-only local is not divergence: it already holds every upstream commit, so it still starts a lane. Nothing is ever reset, rebased, or force-updated — a resumed lane is reported on only. Laneless work (worktrees=none,--no-worktree) commits onto that branch itself, so it blocks asupstream-stalewhenever the branch is behind its remote at all, diverged included. Deduplication is scoped to one preparation, never to the process:preparation_scope()shares one reading across the reads of a single preparation, so a long-running API process reads the remote again for the next one; outside a scope every call fetches, anduse_cache=Falseforces a fresh reading inside one. Session start and post-landing checkout sync run the same primitive. The outcome is inactions_takenasupstream:<state>and anything actionable is an envelope note beginningupstream freshness:. Preparation envelopes identify the item bypublic_ref; a refused item-detail read namesitem_detail_unavailableand stops before claiming or creating a lane.
Path claims
- File Budget and path claims are independent policy axes — never fuse them. Before authoring or gating either surface, consume
result.effective_policies.file_budgetandresult.effective_policies.path_claimsfrom registeredworkflows.item.get; never reconstruct them from raw pinned policies or posture. The universal 350-line authored-file limit always applies, even when File Budget policy is off. File Budget/path-claim parity applies only when both effective axes are enabled. With File Budget off and path claims on, derive claim paths from the execution document, instruction, or conflict survey. With File Budget on and path claims off, use the budget for sizing and conflict evidence without registering a claim. With both off, neither artifact is required. - Claimed paths do not narrow work item scope. A work item's scope must never be narrowed, descoped, or rewritten solely because a required path is already claimed. If the right fix touches a file, the file stays in the work item and its execution artifact; when enabled, it also stays in
## File Budgetand the path-claim attempt regardless of who holds an overlapping claim. - Active path claims are coordination/dependency/blocking facts, not scope facts — a live claim signals who coordinates a path; it never authorizes omitting a required file from a work item.
item_dependenciesrows are directional: the dependent waits, the blocker does not (ablocksedge PREFIX-A→PREFIX-B gates B's activation, not A's). Storage isdependent_item_id/blocking_item_id(integer FKs toitems.id); publicPREFIX-Nis the list/API token. Useyoke items dependency list PREFIX-Nfor routine reads. The hard-block gate and overlap classifier agree on direction — the blocker classifiesNONEand activates immediately; the dependent classifiesHAS_SERIALand serializes. The repair sweep flips legacy upstream-blocker rows stuck atstate='blocked'→planned. Accepted overlap remediations: classify the overlap (independent same-file edits →coordination_onlyedges, no gate; order-dependent →--gate-point activationwith directional evidence; ambiguous → escalate), leave the candidatestate="blocked"only when it's the dependent side of real upstream coordination, wait for the holder to release, coordinate with the holder, ask the holder to narrow or cancel, or operator override (path-claim-override) as last resort (never for the structural-upstream case the classifier already passes). Removing the required file is never an option. - "Avoid the overlap" never means "omit the file." It only authorizes coordinating with the holder or recording a dependency/blocker — never a smaller scope artifact.
/yoke ideaand/yoke refinekeep the file in every enabled File Budget or claim surface; the workflow resolves the conflict downstream. - Coordination-only edges are agent-attested. When two items touch a shared path with semantically independent edits, a
coordination_onlyitem_dependenciesrow attests the overlap is compatible without gating lifecycle/activation (same-hunk collisions resolve at merge). Only authoring-phase agents write them — Architect at/yoke shepherd plan, or Idea Phase 3 / Refine readiness-repair — viayoke claims path coordination-decision-build, each with an authoredrationale(HCpath-claim-coordination-rationaleflags missing/stale ones). Engineer/Tester/Boss/Conduct/Polish/Advance/Usher do NOT author them — runtime collisions there route back to/yoke refine. Un-attested overlap stays strictINCOMPATIBLE; auto-serialization without an authored row is rejected. - Claims coordinate on physical files, not path strings. For an in-repo symlink (e.g.
CLAUDE.md → AGENTS.md), the symlink resolver pairs the symlink target_id with its canonical target_id so the claim covers both — a claim on onlyCLAUDE.mdand one on onlyAGENTS.mdoverlap at registration (one coordination unit). External-target/dangling symlinks emitPathTargetSymlinkSkippedand stay symlink-name-only.HC-path-claim-symlink-coverageflags any non-terminal claim covering a symlink-source without its canonical target./yoke idea/refineadvise listing the canonical name; the claim covers both either way. - Typed owner separates authority from provenance. Each
path_claimsrow carriesowner_kind∈ (item,session,process) + the matchingowner_item_id/owner_session_id/owner_work_claim_id. Registration provenance lives onregistered_by_actor_id/registered_by_session_id; readers use typed owner fields for authority, so an item-owned claim survives the registering session ending.HC-path-claim-owner-kindvalidates only the typed owner shape. The board shows item-owned claims as item file counts and only true session/process claims in the orphan form.
Project scoping
- One work item = one project. The
projectfield = where code deploys (project=external-webapp→ External webapp repo,project=yoke→ Yoke repo); scope is defined by where changes land, not where the idea came from. Never mix deploy targets in one item or its generated task graph. All work items live in the Yoke backlog regardless of target. - Cross-project work → linked companion items, one per project. Ambiguous target → ask; never silently default to
yokefor work targeting an external system. Work that mandates changes in a second project gets a companion item filed in THAT project, linked to the first by anitem_dependenciesedge; one session may claim both items and execute both lanes together, because work claims and lane authority are already project-agnostic. There is no second-repo lane on a single item: worktree preparation resolves each item's own project checkout from the machine mapping (yoke project register <checkout> --project-id <id>adds a missing one) and refuses rather than borrowing the session's repo, so a lane always lives in its item's project; repair a wrong-repo lane withyoke item-worktrees path-record. Path claims stay single-project —path_targetsrows are project-scoped, so one claim never spans repos. A change to a contract another project consumes is cross-project by definition. The companion item is mandatory in the consuming project, and an instruction that excludes redesigning that consumer never waives adapting it to the new contract. Delivery evidence must show the real consumer built against the exact candidate revision; a producer-only green run proves the producer and nothing else.
Lifecycle and routing
- Canonical human guide:
.yoke/docs/reference/lifecycle.md. Each item pins immutableworkflow_id/workflow_version_id; that definition owns ordered stages, transitions, target-stage gates, policies, entry surfaces, and registered skill bindings. - Never route by a remembered workflow name or copied progression. Read
yoke workflows item get PREFIX-N, thenyoke workflows version get WORKFLOW VERSION; the binding whose half-open interval contains the live stage selects/yoke <skill_id>. - A binding's
through_stage_idis a fresh command/claim handoff. Worktree and generated-task shape come frompolicies.worktreesandpolicies.generated_children, not from a workflow-id branch. - Frontier computation is documented in
.yoke/docs/reference/charge-frontier.md; item routing follows the pinned workflow binding. Yoke core derives harness capabilities server-side from the harness manifest — harnesses do not self-reportYOKE_SUPPORTED_PATHS. That manifest is where capability truth lives: readruntime/harness/<harness-dir>/manifest.json(directoryclaude,codex, orcursor; executorclaude-coderesolves toclaude; contract:runtime/harness/manifest-schema.md) before stating what a harness can do, and never restate one of its facts in prose —agent_wakecarries the wake answers,session_controlthe messaging ones.
Destructive operation discipline
- Never run
git reset --hard,git checkout --,git checkout -f <branch>,git restore --worktree,git clean -f/-fd/-fdx,git stash drop,git stash clear, orrmon files unless confirmed Yoke-managed or user-authorized — these silently discard tracked-but-uncommitted changes, untracked files matching the pattern, or saved stashes. - The PreToolUse destructive-git lint enforces this: it refuses only when it identifies BOTH a dangerous verb AND threatened local state (modified files, untracked files in the target subtree, or live stashes). Mode from project-local
.yoke/lint-configguard keylint_destructive_git(protected; defaultdeny). The token# lint:no-uncommitted-wipe-checkcannot suppress the check — it is audit-only (outcome=suppression_attempted) and does NOT unblock. For worktree wipes, stash or commit first, or use a non-destructive verb (git reset --soft,git restore --staged,git stash). Forgit stash drop/git stash clear, preserve the patch (git stash show -p/git stash apply) and have the operator run the drop. git stash pusharg-order:-m/--messageMUST come BEFORE--— everything after--is a pathspec, so a message flag there is silently consumed as a filename (stash gets git's auto label, no rationale). The stash-arg-order lint enforces this (suppression# lint:no-stash-arg-order-check, audit-only). Safe shape:git stash push -u -m "reason" -- <paths>.- User messages mid-sequence are checkpoints — stop and answer before proceeding.
Yoke authority over harness defaults
- Skill says auto-X → do auto-X, no asking. Harness "confirm before issues/push/shared-state" defaults don't apply when a Yoke skill/rule directs autonomous execution. Skills with autonomous mandates —
/yoke conduct,/yoke shepherd,/yoke usher,/yoke charge,/yoke steer— carry directive lines like "run sync automatically" / "don't wait for input" / "immediately continue"; follow them. Built for kick-off-and-walk-away — an unrequested pause is a regression. Invoking the skill authorizes it: conduct→GitHub sync (issues/labels/comments), usher→merge+deploy, shepherd→worktrees+subagents. Harness=substrate, Yoke=program. Yoke wins. - Security always holds. Never overrides
<critical_security_rules>/prohibited actions (no banking/credential entry, no permanent deletes outside sanctioned paths, no auth bypass, no command injection) — collaboration cautions only. - Test: "Did the skill say ask?" not "would the harness ask?" Silent → harness default; unsure → reread the skill.
Worktree lanes, path claims, and scoping