agentleFS
scottcrosby-securebinescottcrosby-securebine/doctrine-skills/skills/doctrine-project/SKILL.md

doctrine-project

Skill0 starsChanged 9 days agoMITView on GitHub

Use when the user asks to start tracking a project, or to adopt an existing repo into uniform project and epic tracking, with the doctrine: a ruled end state, epic records with checkable Done means, independent exit passes, and cutover from other trackers.

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    REQUIRED BACKGROUND: Read the doctrine skill first.

    line 10
  2. Very specific:

    Write epic records only for live work that covers the end state.

    line 27
  3. Distinctive:

    Delete nothing and repair no history.

    line 30
  4. Distinctive:

    Every issue in a closed milestone read as an epic being Done.

    line 122

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Doctrine Project

One way to know when a project is done and when each epic is done, the same in every repo. The agent proposes and the owner rules. Only an exit pass by a context that did not build the work moves an epic or the project to Done.

REQUIRED BACKGROUND: Read the doctrine skill first. What this wrapper supplies to it:

  • Core discipline. The lifecycle procedure below. The owner's interview runs through superpowers:brainstorming, whose fallback is the hub's Fallbacks row. Write each question put to the owner, and the owner's answer, into the run record verbatim as the interview goes.
  • Designated review. None is named, so the hub default fills the slot (doctrine step 5): a fresh-context review of the deliverable against the anchor. For an exit pass, what it grades is the Done means or end-state items. For a start or adopt deliverable, its brief pastes that mode's conditions from "End states" below, which it grades the deliverable against, and the owner's interview questions and answers from the run record, verbatim, as the data the end state was drafted from, never the interview's method or posture.
  • Red team axes. The list under "Red team axes" below.
  • Where the record lives. The run record for a phase goes under the path on the project file's Records: line, excluded from version control, per doctrine step 1. Before a project file exists, it goes under .doctrine/records/ in the repo root, excluded through the file git rev-parse --git-path info/exclude names, so no tracked file changes. The project file that start or adopt writes carries Records: .doctrine/records unless the repo's own conventions name another path; where they do, move the run record to that path before committing the project file. docs/PROJECT.md and docs/epics/<ID>.md are tracked contracts, not the record. Never gitignore them.

The file formats, and the rule for when a return counts, are in formats.md beside this file. Read it before writing either file. <plugin-root> below means two directories above this skill's base directory, the one this file loaded from.

Modes

Start, for a repo with no project file. Interview the owner, then propose, in Proposed state: the end state items, the never-becomes list (propose entries yourself and let the owner strike the wrong ones, each strike or addition a scope ruling), the first epic with its Done means, and the coverage map (W1 below). The owner rules on all of it before the first phase opens.

Adopt, for a repo that already tracks work some other way. Adoption is forward-only:

  1. Inventory every tracking surface the repo uses: goals, plans, PRDs, markdown trackers, and the work-item trackers "Trackers" below finds, and write the inventory into the run record. Report any GitHub Projects board as an unread tracking surface. Never report it as empty or as having been read.
  2. Draft the end state from what the repo already says. Where it says nothing, interview the owner. The owner rules it.
  3. Write epic records only for live work that covers the end state. Past work gets no epic record and no archive ruling. List its sources as links under ## History, one index, and nothing more.
  4. Give a destination (a member of an epic, out of scope, or the post-done backlog) to every open item read from a markdown tracker the repo uses, and to every open issue read from a work-item tracker "Trackers" below finds. Each destination is a destination ruling and a row in ## Open issues. Nothing else gets a row: not a remote issue the owner declined, and not an issue in a tracker that could not be read.
  5. Cut over. This step is mandatory. Find every instruction that routes tracking somewhere else and put each rewrite to the owner as its own cutover ruling, one at a time. A tracker a plugin generates is reported and left alone: it is not cut over and never edited. Flag every CLAUDE.md or AGENTS.md edit separately in the delivery, since it changes agent behaviour.
  6. Delete nothing and repair no history. The diff removes only the routing lines the owner ruled.

End states. Start ends when the project is Ruled, the first epic is Not started with its Done means, coverage map and combined check ruled, and check exits 0. Adopt ends when the project is Ruled; every epic record for live work is Not started or Open; every item adopt step 4 names has its destination ruling and its row; every cutover edit has a cutover ruling and is committed; any GitHub Projects board is reported unread; and check exits 0. Either mode's deliverable is prose (the project file, the epic records, and in adopt the cutover diff), so either mode's phase then exits under the hub's prose-deliverable exit, adopted here by name for both modes.

Restart and collision. Both modes resume after a crash or compaction. Before the first write, look for an existing docs/PROJECT.md and for an adoption or start run record both under its Records: path and under .doctrine/records/, since a crash can fall between writing the project file and moving the record. If a run record exists, resume from it and never re-inventory. If a project file exists and no run record explains it, the repo is already adopted: switch to the lifecycle procedure, and ask the owner before re-drafting anything. One writer at a time: the run record names the session writing the project files. A session that finds an Open run record it did not write writes nothing and asks the owner.

Trackers. Read the work-item tracker from the repo's own instructions: CLAUDE.md, AGENTS.md, CONTRIBUTING.md and the README. Where the remote has open issues the instructions do not name as the tracker, put the remote's issues to the owner, whether or not the instructions name another tracker: if the owner accepts, they are a work-item tracker like a named one, and if the owner declines, they get no row. The no-tracker branch applies only when the instructions name no tracker and the remote has no open issues, when the instructions name none and the owner declines the remote's issues, or when the tracker cannot be read: its CLI is missing or unauthenticated, or the session is contained. In that branch adoption still runs, and adopt step 4 says which items get a row. The report names each tracker surface separately: which were read, which the owner declined, and which could not be read. Keep what each tracker read returned in the run record, as it returned it. Never invent an issue number. The format check makes no network call and never reads the tracker, so a closed issue or a merged PR is a member's closure, never acceptance.

Lifecycle procedure

This procedure applies to every phase in a repo that carries docs/PROJECT.md, whichever wrapper runs the phase.

The format check

Run node <plugin-root>/hooks/dctr-project.mjs check as your first action in such a phase, and again after every write that changes a state, a ruling, a return, the roster, a membership or the pointer. Run it before committing that write. Exit 0 is clean. Exit 1 lists findings: fix them before any further state change. Exit 2 means the project file is absent or unreadable, or the arguments were malformed. This is the stated way the check runs in a target repo. Add no CI step to an adopted repo. A hand edit made between sessions is caught at the next session's first check, so far as the file as it stands shows it: check keeps no history of any line, so an edit to a Coverage or Combined check line is not among them, and that gap is ruled and known.

node <plugin-root>/hooks/dctr-project.mjs status is read-only and prints the project's progress view. It prints unknown for any source it cannot read. Read an unknown as "could not look", never as "nothing there". A return it labels obsolete is history, never current evidence. Its open records are only those it searches, which its label names: each record directly under Records:, each one directory down that carries a wrapper: line, and each record an epic's Members line names. A record anywhere else is not among them, so its absence there says nothing.

States and who moves them

Epic states are Proposed, Not started, Open, Done, Dropped and Superseded. The terminal states are Done, Dropped and Superseded, and only Done has an exit. The evidence each state needs is what check enforces.

Epic fromToWho moves it
(new)Proposedyou, writing a roster line and a record
ProposedNot startedthe owner, ruling the baseline Done means, the coverage map and the combined check
Not startedOpenyou, opening the first member phase
OpenDonean epic exit pass whose return counts
DoneOpenyou, on a done-means-change ruling, a ruled Combined check change as below, or a recorded regression
Proposed, Not started, Open or DoneDroppedthe owner, by a drop ruling
Proposed, Not started, Open or DoneSupersededthe owner, by a supersede ruling naming the successor
Project fromToWho moves it
(new)Proposedyou, writing end state items
ProposedRuledthe owner, ruling the baseline end state
RuledDonea project exit pass whose return counts, with every roster epic terminal
DoneRuledyou, on an end-state ruling, a regression, an epic leaving a terminal state, or a new roster line
  • Epics. You create each epic in Proposed and record each member phase and issue under ## Members when it joins.
  • The pointer. Move Current epic: only when a member phase opens an epic. Never move it when a regression reopens an epic.
  • A Done means change. On a Not started or Open epic it is allowed. On any epic it needs an impact ruling from the owner listing the same items (W3), and every phase contribution to those items needs fresh evidence. On a Done epic it also moves the epic to Open.
  • A Combined check change. The owner rules an epic's Combined check: line once, with the ruling that moves the epic to Not started, so what you draft before that is yours to revise. After it is ruled, a change to what the check runs, or to its pass rule, goes to the owner and is recorded by the baseline ruling formats.md defines for it, in that epic's own record and nowhere else. That ruling is then the current baseline, so every return on an older one stops counting, and on a Done epic you move the epic to Open. Where that epic stands at the end of a Superseded satisfy epic's successor chain, the coverage ruling comes first, in the order and for the reason exit passes step 5 gives. A change that leaves the command and the pass rule both doing the same thing, a typo or a reworded description of the same run, is a repair: it gets no ruling, because a baseline ruling becomes the current baseline whatever it was written for, and writing one for a repair stops the epic's own returns counting. Judge which it is by what the check now does, never by whether the line's words moved: a line whose words stand while the command it names runs something else has changed what runs. check sees none of this: it keeps no history of the line, so a change recorded with no ruling, and a ruling written for what was only a repair, are both invisible to it and are yours to get right.
  • A record written before the combined check result. A record whose deciding return predates that line is reported against it: the missing line, whatever state the epic is in, and on a Done epic the epic's own Done being unevidenced as well, since the seam check the owner approved was never run at that revision. Each is true where it fires. Clear it with the moves this skill already has, and never by writing a result into a return a seat gave. On an epic that can still take a pass: a baseline ruling re-approving the same Combined check: line, quoting it as any such ruling does, which reopens the epic to Open; it reaches Done again on a fresh exit pass, whose return carries the line. Reopening it takes the project out of Done too, by the row for it in the table above, so expect check to say so until you move the project to Ruled. Where that epic stands at the end of a Superseded satisfy epic's successor chain, the coverage ruling comes first, in the same order and for the same reason "A Combined check change" above gives, since this reopens an epic exactly as that bullet does. On an epic that is Dropped or Superseded, where no fresh pass is possible and only the missing line is reported, set its Certification target: to none, after which no return counts and the record is history. That move clears nothing on a Done epic, which still needs its fresh pass. Nothing else in an old record changes (owner ruling, 2026-09-14).
  • A decision that moves nothing. An escalation the owner rules when a phase's alarm fires, a finding the owner rules closed, any approval that changes no item, no line and no map: record it as a note ruling, which formats.md defines and which voids nothing. Never as a baseline ruling, for the reason "A Combined check change" above gives: such a ruling voids the epic's own returns whatever it was written for, so a decision that changed nothing would void a pass that was good.
  • Work nothing covers. Work a Dropped or Superseded epic no longer covers goes into a new epic. A successor covers an end-state item only once it is Done. While it is not, check reports the item. Where the successor chain ends at an epic that is Proposed, Not started or Open, the fix is a coverage ruling naming that epic as the item's satisfy epic. Where it ends at a Dropped epic, loops, or leaves the roster, nothing on it can reach Done: the fix is a new epic on the roster and a coverage ruling naming it. formats.md defines the coverage ruling: write it in the project file, and change the Coverage: line of each end-state item its Items list. Exit passes step 5 below says when it comes first on a failed item.

Done means items

Every item has the seven fields formats.md defines. Before any item goes to the owner as part of a baseline, apply the admission test to it: "Can [requirement] be objectively measured/verified?" If not, it is type T4, owner judgement: its check verifies that the owner's ruling on a named revision exists, never the taste. Then, where the Check is runnable at the revision the item is admitted at, run its Control and its Check there, and keep what both runs printed under Records:: that is the item's admission evidence, which exit passes step 2 hands the exit seat. A Control that does not fail means the Check cannot fail: repair the Check and its Control before the item goes anywhere. Only once the Control fails for the reason the Check measures, and something other than that Check's own result shows the item's Outcome present at that revision, does a Check that already passes mean the item is not live Done means: it is then history, or the owner rules it preserve for the phase that must keep it passing. A Check that passes there while the Outcome is absent cannot tell present from absent: repair the Check and its Control before the item goes anywhere, as for a Control that does not fail. Where the Check cannot run at that revision, for any reason and not only because it needs a platform, a harness or a deployment the host does not have, the item goes to the owner with the not-yet-shown-failing mark on its Control line that formats.md defines. What decides which of these a failure is, is whether the run measured the item's Outcome at all, never what happened to be missing. A run that fell over before it measured anything, the work unbuilt or something the measurement itself needs absent, has not run: a Check in that state takes the mark, and a Control failing the same way shows nothing about the Check. A run that did measure and found the Outcome absent has failed informatively, whether because the Control removed what the Check measures, the feature off or the artifact taken away, or because the Outcome really is absent, which is what a Check is for. A run that died partway, or that you cannot place from what it left behind, has established nothing and counts as not having run, unless what it did record already shows the Outcome absent, which is an informative failure whatever else the run never reached. Treating a transcript you have not read as an informative failure is how a Check that cannot discriminate gets admitted. A Control that fails for a reason of its own, unrelated to what the Check measures, discriminates nothing whatever the Check did: repair the Check and its Control before the item goes anywhere, as for a Control that does not fail. Split a conjunction into separate items. An item missing any field is not put to the owner.

  • W1. The coverage map is ruled before the first phase opens, by a coverage ruling. It names, for each end-state item, exactly one satisfy epic, or a project-level ruling. For each epic it names the planned member phases, in its Done means items' Coverage: lines, and, for the seams between them, the epic's combined check, whose own line and pass rule are ruled by the epic's baseline ruling and not by this one, as formats.md says. A phase opened for the epic takes one of those names, or comes with a coverage ruling that adds it. When the epic opens, record every phase its Coverage: lines name under ## Members. From then on those names and the - phase members stay one set: a change to either comes with the matching change to the other.
  • W2. Each phase serving an item carries exactly one obligation toward it: satisfy, contribute (named partial evidence), or preserve. Doctrine step 1 carries a phase's served items and their obligations into its anchor.
  • W3. The impact ruling "A Done means change" above requires is the owner's, because the owner is the one who accepts that the evidence behind the changed items is now stale.

Exit passes

You open an epic exit pass when its member phases have exited. You open the project exit pass when every roster epic is terminal. That is the project exit entry point. Either pass reuses the hub gate by reference: a context that did not build the work, one identified revision, a recorded return.

  1. Open. Write the revision on the file's Certification target: line as the pass opens. An epic has one certification target at a time. Opening a pass on a new revision voids any pending pass on the old one. Completed returns on the old revision stay in the file as history.
  2. Dispatch. The exit seat is handed the project file or epic record with every return and regression entry removed, and its search scope excludes those entries in every tracked file, as doctrine step 4 excludes the record. Owner ruling entries stay, because a T4 check verifies that a ruling exists. The same exclusion applies to every phase reviewer and red team in an adopted repo. Past exit-pass results and run state never reach a seat. The exit seat's brief pastes, verbatim, the definitions its results rely on: the item types T1 to T4 and the evidence kinds, from the Type and Evidence bullets under "Item fields" in formats.md; the current-baseline rule and the rule for when a return counts, from "Entries" there; and the admission test, as "Done means items" above states it. For each item whose Control line carries no not-yet-shown-failing mark, it also pastes that item's admission evidence, the Control's and the Check's runs "Done means items" keeps under Records:, so the seat can check that the Control was really shown failing for the reason the Check measures. Where any Check, or the epic's Combined check: line, runs a command, the exit seat is one that can run commands, never a seat limited to read-only tools, such as the cross-model seat a host reference starts with no command tool.
  3. Evidence. The seat returns PASS, FAIL or UNVERIFIED per item, each with an evidence reference. For an epic pass it also runs that epic's Combined check: line at the certification target and returns its result the same way, on the Combined check result: line formats.md defines. That check covers the seam between the epic's member phases, which no single phase's own gate covers, and this pass is the only context that spans them. A result other than PASS is a failed pass, exactly as a failed item is, and the epic stays where it is. Brief it that missing evidence is UNVERIFIED, never PASS, and that an item whose Control line carries the not-yet-shown-failing mark formats.md defines gets PASS only once its Control has been run and shown failing at the certification target, its result UNVERIFIED until then. Brief it too that admission evidence step 2 handed it which does not show the Control failing for the reason the Check measures makes that item UNVERIFIED, or FAIL where its Check fails; that an item with no admission evidence kept, as for one admitted before admission runs were kept, is graded by its Check and named in its reply apart from the item lines, which carry only the result and its evidence reference; and that this absence alone never makes the item UNVERIFIED, the missing-evidence rule above being about the Check's own evidence. A path:line reference and a web quote held in a retained copy can both be checked offline. Checking that a live page still says what was quoted needs a fetch, which belongs in a separate manual check, never in check. A check that a quote is present does not show that the quote supports the claim.
  4. Record. You write the return entry as the seat gave it, with the Baseline it was briefed on, and keep the seat's list of items graded with no admission evidence kept in the run record, never in the entry, even when a ruling that changed the current baseline landed while it worked. A return missing any item's result is a failed pass, and so is an epic return missing the Combined check result: line step 3 requires. Read what counts from formats.md. Whether the return counts is decided by the accounting check, which you run, never a seat: the exit seat, every phase reviewer and every red team stay blind to returns and regressions, and none is asked to judge one. Run it as soon as the return is written, before any state move the return could license. It is check and status, which read the project file and the epic records whole, returns, regressions and rulings included, and apply to every return the conditions under which formats.md says a return counts, status labelling obsolete each return that fails one; and your read of each PASS's evidence reference against its item's Type and Evidence line, where a reference not of the kind that line names is UNVERIFIED, as formats.md reads an empty one, which check cannot see. Only a return the accounting check counts moves a state.
  5. A failed item. For a failing end-state item with a satisfy epic, the epic that reopens is the Done epic at the end of the satisfy epic's successor chain, which is the satisfy epic itself when it is not Superseded. When the satisfy epic is Superseded, first put to the owner the coverage ruling "Work nothing covers" above describes, naming that end epic as the item's satisfy epic: this changes the coverage map (W1), and reopening the epic before it leaves a chain that does not end at a Done epic, which check reports. Record a regression in that epic's record against each of its Done means items that serve the failing end-state item, each by its own ID. Where you cannot name which Done means items serve it, record one against every Done means item of that epic. Reopen that epic only (Done to Open). Those regressions and that reopen are one write: a regression recorded after the epic's counting return stops that return counting, so until the reopen lands check reports the epic as Done on no counting return, truly, and that state is passed through inside a single write and never left on disk to be checked between. A failing item ruled project-level may be fixed by a phase outside any epic. The project exit pass then reruns.

The sidebar

Inside herdr, publish the phase's counters with node <plugin-root>/hooks/dctr-token.mjs <round> <exit-count> <valve> --epic <ID> --phase <name>, adding --owed while a ruling is owed. Doctrine step 5 defines the three counters. Re-publish whenever a value changes and at least once an hour, or the tokens expire.

  • Owed. Set --owed while an alarm has fired and awaits a ruling, while a direction question is open, or once a closing round has finished. Clear it when the owner rules.
  • One owner. The session's orchestrator is the only writer of its pane's tokens, under source custom:doctrine. herdr does not refuse a second writer, so no seat publishes them.
  • Attention. herdr's native blocked and done states and its state_icon carry attention. Never run herdr pane report-agent: a reporter replaces native detection for that pane, including those two states.
  • Rendering. Wherever you verify that the tokens render, name the view and the width. Pane tokens render only on an Agent row. Custom rows show only in the expanded sidebar, on a client wider than ui.mobile_width_threshold (64 columns by default). At the default sidebar width, $epic, $phase and $doctrine truncate on one row. A $doctrine change raises no toast, so ·owed is seen only by someone looking at the row.

Red team axes

Hand the red team these, per doctrine step 4:

  • An end-state item with no live satisfy epic, or a Superseded epic's successor counted before it is Done.
  • An item that fails the admission test typed T1 to T3, or a conjunction left unsplit.
  • An item adopt step 4 names with no destination ruling or no row, or an issue number nobody read from a tracker.
  • An instruction that still routes tracking elsewhere after cutover.
  • History deleted or rewritten, or a plugin-generated tracker edited.
  • A return or regression entry, or run state, inside a seat's prompt or search scope.

The red team's brief pastes, verbatim, the definitions exit passes step 2 lists: the item types T1 to T4, the evidence kinds, the current-baseline rule, the rule for when a return counts and the admission test. For a start or adopt deliverable it pastes the owner's interview questions and answers as the designated review is handed them, and in adopt it also pastes, verbatim from the run record and never the record itself, the tracking-surface inventory adopt step 1 produced and what each tracker read for adopt step 4 returned.

Red flags

  • An epic moved to Done by the session that built it, with no return from another context.
  • A return recorded against a revision other than the certification target, and counted.
  • Current epic: moved when a regression reopened an older epic.
  • Every issue in a closed milestone read as an epic being Done.
  • A cutover that rewrote five routing lines on one ruling.
  • A plugin-generated tracker hand-edited during cutover.
  • A GitHub Projects board reported as holding nothing, when nobody read it.
  • docs/PROJECT.md gitignored because an orchestrator took it for the run record.
  • An exit seat handed the epic record whole, including last month's FAIL.
  • A second session re-running an adoption the first session left Open.
  • A herdr pane report-agent call, and a pane that never shows blocked again.
  • A state change committed with no check run after it.
  • An epic's Combined check quietly rewritten, or a baseline ruling written for what was only a typo in it: check reads the line as it stands and can see neither.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.