Docs

Thinking

Tranches and tasks

The Planner cuts a tranche into task Issues under one label and declares which tasks depend on or conflict with each other. Each task gets one branch, task/<tranche>/<n>.

Planner
Tranche label
Depends-on
Conflicts-with

About tranches and tasks

A tranche is a set of related tasks with declared dependencies and conflicts. It lives as the label vinaya/tranche:<slug> on its Issues. The label is the tranche's whole identity: no Milestone, file or plan pull request is required.

A task is one GitHub Issue: one immutable Intent (the frozen brief), one branch, at most one pull request, one parent branch. The Issue carries the plan; the forge carries the state. A task's status is never written. It is derived from the Issue state, branch presence, pull request state, review decision and the vinaya/blocked label.

The Planner exists because the relationships between tasks (dependencies, conflicts, split or combine) are invisible to a brief written on its own.

To plan and run a tranche end to end, follow Deploy medium work.

How it works

The Planner announces each stage out loud, in this order: Readiness → Deep dig and sizing → Topology → Decision and spec records → Issues → Done.

  1. 1

    Readiness

    Nine inputs are confirmed before a single task is sized. See Readiness and the frozen brief.

  2. 2

    Deep dig and sizing

    Every candidate task must pass four tests, or be split: one verification story; one agent can hold it; a bounded file surface; a single failure mode. Verification coupling decides split or combine. Work that can be verified independently splits, with a depends-on edge. Work whose verification is coupled stays one task, one branch, one pull request, across several projects.

  3. 3

    Blast radius

    A change to a shared package lists every consuming project in **Project:**. The list is found by command, not memory, for example git grep -l '@attalabs/<pkg>' -- '*/package.json'. Only names registered in .vinaya/projects.md count.

  4. 4

    Topology

    The Planner declares the edges (see below), and checks the Boundary for hedge words before presenting the topology.

  5. 5

    Issues

    One vinaya issue create --label vinaya/tranche:<slug> --body-file <path> per task, written from the Issue rationale template. Cutting the Issues is the plan; it commits nothing.

  6. 6

    Independent plan review

    A fresh Planner session answers four fixed questions for each Issue. Does every consumed input have a named source? Does each stop condition have a command the Developer can run? Is every premise true on the default branch? Does every edge's shared files really get edited by both tasks? Every finding is fixed before planning is declared complete.

  7. 7

    Done

    The Planner closes with: "Planning complete … dispatch order is […]. Next stage is dispatch, which is yours to trigger."

If the plan also changes a file in the repository (most often a spec), that change goes through a worktree on branch plan/<tranche>, a pull request and green checks. Only one plan pull request per tranche may be open (single-plan-pr).

The tranche label

  • The label has the form vinaya/tranche:<slug>. It is a prefix family, matched by prefix.
  • GitHub caps a label at 50 characters, and the prefix uses 15.
  • Name the tranche after its centre of gravity: the durable, highest-leverage work. Never name it after a narrower feature than its Project(s) reveal.
  • vinaya issue create creates the label if it does not exist.

Dependencies and conflicts

Edges are written on each Issue, inside the rationale field **Dependency rationale** — …, which must be in exactly this bold-inline form. Only the labelled Depends-on: and Conflicts-with: lists inside it are read. To change an edge, edit that field and write the body back with vinaya issue edit.

EdgeMeaningEnforced at dispatch
Depends-on: #<n>This task needs the other merged firstThe dependency's pull request must be merged
Conflicts-with: #<n>Both touch the same collision domain and must not run in parallelNo conflicting sibling may have an open pull request or be in flight
  • The rationale must say why each edge exists. For a conflict, it names the shared files on both sides. An edge with no nameable overlap is dropped or raised as a warning.
  • Collision domains are packages, derived from the workspace declaration, plus a built-in cross-cutting set (lockfile, tsconfig.json, biome.json, turbo.json, .github/workflows, .husky) and any blastRadius.extraDomains.
  • Conflicts hold across tranches running at the same time. The Planner of the second tranche checks the first one's collision domains.
  • No dynamic conflict scanner over in-flight branches is allowed.

How collisions are counted

At the Issue write, collisions are counted in files. The Boundary's pinned files are compared with other open task Issues' pinned files and with open pull requests' changed files.

  • Below planning.collisionThreshold (default 3), the write passes with a warning.
  • At or above it, a Conflicts-with edge in either direction is required.

The same comparison runs again at dispatch, against open pull requests only.

To see what the Boundary's pinned files force on the Surface before you write, run:

vinaya issue surface --body-file <draft>

It prints importers as reached, disclaimed or uncovered, and writes nothing.

A task: Issue, branch and worktree

ItemRule
IssueOne per task. A real number is required; #TBD is forbidden
Branchtask/<tranche>/<n>; for a backlog Issue, task/issue-<n>
Worktree.worktrees/task/<tranche>/<n>, forked from origin/main
Pull requestOne, opened by the Developer, closing its Issue with Closes #<n>
Re-cut taskThe old Issue is closed as NOT_PLANNED (dropped). Readers prefer the open Issue over the closed one, and refuse two open Issues with the same number

The branch name links a task number to its branch and pull request, so any role finds live status with one forge query and writes nothing.

Moving a task between tranches

The Planner can move a task at plan time, and only a todo task: one with no task/<src>/<n> branch and no open pull request.

  1. 1

    Relabel

    Change vinaya/tranche:<src> to vinaya/tranche:<dest>.

  2. 2

    Reattach

    Attach the Issue to the destination Milestone, if there is one.

  3. 3

    Leave a trace

    Post a one-line provenance comment.

A moved task counts as neither done nor dropped in the source tranche.

Roles

RoleDoesNever does
PlannerRuns the readiness step; sizes by reading the code; cuts one Issue per task with its rationale; declares edges; names the tranche; moves todo tasks between tranches; runs the dispatch actWrite status, a brief or a Milestone; execute; settle contested architecture alone; invent an unregistered project; close a tranche
Planner (fresh session)Reviews a newly cut tranche independently. Writes no forge state—
PrincipalApproves the tranche and its rationales before dispatch; decides when dispatch starts; rules on calibrated warningsBreak the tranche into tasks
Tranche ArchivistCloses a finished tranche. See Tranche and Milestone closeMove tasks, edit topology

Gates

GateWhenRefuses
The five Issue checksIssue create or editTitle grammar, objectives numbering, Parts coverage, Surface globs, Milestone attach. See Ring 1 Issue checks
Rationale checkIssue writeMissing rationale fields; a Dependency rationale not in the exact bold-inline form
Project registry checkIssue writeA Project: with no registry row
File collision checkIssue write and dispatchShared pinned files at or above the threshold without a Conflicts-with edge
coherenceRing 0 at push, Ring 1Open task Issues whose bodies fail the same grammar. Issues older than the grammar are exempt by number
single-plan-prRing 0, Ring 1Plan pull requests open at the same time on the same legacy tranche plan
branch-topologyRing 0 at push, Ring 1A task/<tranche>/<n> branch whose tranche has no topology on the forge, or whose <n> is not a task in it
dispatch-readiness, first-push-dispatchBefore dispatch; first pushAn unmerged dependency or an open conflicting sibling

The Planner also refuses, by doctrine rather than code: execution metadata, planning metadata, plan data in a spec, a conflict scanner, and a new committed report file.

Configuration

KeyEffect
planning.collisionThresholdThe shared-file count that requires a Conflicts-with edge. Default 3
blastRadius.extraDomainsExtra collision domains
projects and .vinaya/projects.mdThe project registry every Project: must resolve to
briefSchema.issue.sectionsThe builtins the Issue write runs

What gets logged

ActLog events
issue create, issue edit, issue surfaceoperation · completed
A Planner agent turn, when dispatcheddispatch, role_attempt, usage
A failing checkgate · checked, gate · summary

The Planner reports tokens as Tokens: planning — Planner — <model> — … in the plan pull request body. When there is no plan pull request, it posts them in a comment on the pinned lessons Issue.

What's next