Discuss one product area

Yard: the record of how a change was built

A specification says what the product must do, and the trace shows which tests check it. Yard keeps the third record on every branch: what your coding agent planned, asked, and decided, and what you answered. It ships with open-source Loft, in its plugin for Claude Code and Codex.

By Loft Published

What a diff leaves out

Say you ask your coding agent to let customers pause a subscription. An afternoon later the branch holds a change to the specification, the code, and its tests. The diff shows what changed, and the specification says what the product must now do. Neither shows that the agent asked whether a paused subscription keeps its billing date, that you said it should, or that you sent its first change to the specification back because it left out the email a customer gets when a pause ends. That history usually stays in a chat transcript that nobody opens again.

Yard keeps it on the branch, as a Yard Log: typed records the agent writes as it works, and the answers you give when it asks. A reviewer reads the Yard Log next to the diff, and the next agent on the branch reads it before it starts.

Three records in one repository

Loft is the first pillar of the Software Plant: a product contract that people ratify and agents build against, kept honest by deterministic checks. Yard is the pillar for coordinating production. Its first part, Yard Client, ships with open-source Loft, and it keeps a Yard Log for each branch beside the two records Loft already keeps.

One repository, three records
  • my-product/
    • spec/What the product must do: features, requirements, and acceptance criteria, checked by loft check and pinned when published.
    • loft.trace.yamlWhich tests verify each criterion, checked by loft reconcile.
    • .yard/feat/pause-subscription/How this branch's change was planned, asked about, decided, and built.
    • ...The code and its tests.
All three are plain files under git. The records of a Yard Log carry keys, as the nodes of a specification do.

Set a repository up once. Install loft as a dev dependency, or with Cargo, then create the specification and register git's merge driver:

npm install --save-dev @ask-loft/loft    # or: cargo install --locked loft-cli
npx loft init
npx loft merge-driver --install --command "npx --no-install loft"

loft init writes an empty specification and the agent skills. The merge driver makes git merge the specification and every Yard Log record by record, by key, instead of line by line. With a loft on your path, loft merge-driver --install needs no --command.

Where Yard came from

Yard started as a habit. During a long build we kept a Claude artifact open as a working document: the plan, the open questions, each decision as it was made, and what each step left done. It became the page we read most that week, and it lived apart from the code it described.

We prototyped the idea on its own as a Claude Code plugin with a local page, then moved it into loft. Like the rest of Loft, Yard was specified in the open format before it was built, and every change to it since went into the specification first. How we build Loft with coding agents in general is in Building Loft with Claude Code.

Opening a Yard Log

In Claude Code, add the plugin from Loft's marketplace with /plugin marketplace add Ask-Loft/loft, then /plugin install loft@ask-loft. A project where loft init ran already enables the plugin in its committed settings, so Claude Code offers it to everyone who trusts the project. The plugin runs loft itself. Where loft is a dev dependency rather than on your path, set the plugin's loftCommand setting to npx --no-install loft or pnpm exec loft.

Then cut a branch and ask for the work. For the pause feature:

git switch -c feat/pause-subscription
/loft:yard Let customers pause a subscription for up to three months.

The yard skill also loads by itself when an agent plans work on a branch; the command makes sure of it. The agent's first write opens the branch's Yard Log with the stages it foresees: shape, specify, and build, the first one active and the others planned, so you see the road before any code is written.

The plugin starts the Yard page and keeps one running for the machine, at http://127.0.0.1:7411/. It listens on the loopback interface only. If that port is taken, set the plugin's yardPort setting.

What a Yard Log holds

A Yard Log is a list of stages with typed blocks inside them. A block kind exists only where you act on it, where its state changes over time, or where it keeps a report from loft. Everything else the agent has to say is Markdown, with tables and Mermaid diagrams where they help. That leaves eight kinds:

stage
A step of the work, with a goal that names what it leaves done, such as "a paused subscription skips its renewal".
task
A unit of a stage, marked active when it starts and done when it ends. A correction you asked for is a task of type fix.
question, approval, plan
What the agent puts to you: questions with options, a change to approve or reject with a reason, a plan for the build.
decision
A choice you made, with what follows from it.
note
What a stage produced, what it means for the next step, and what is left open.
loft
A report of loft's, kept as it was when recorded: the change to the specification, check findings, trace coverage, or a publish.

Only you write answers and decisions. The agent writes the rest through six tools the plugin gives it, and every earlier version of a block stays in the log. Each task is marked as it runs rather than all at once at the end of its stage, which is what lets the page show where the time went.

Ask once, answer anywhere

When the agent reaches a decision point, it sends all of that point's questions together, gives each a recommended option with the reasoning for every option, and waits. For the pause feature it asks whether a paused subscription keeps its billing date and whether the customer hears from you when the pause ends.

You answer on the Yard page or in Claude Code's own dialog, whichever is in front of you. The first answer counts, and the other place closes. Questions the agent asks through Claude Code's AskUserQuestion, the plans it presents from plan mode, and the tasks it creates all reach the Yard Log on their own, so the page misses nothing that was asked in the terminal. After you answer, the agent records a decision: the billing date stays, and paused cycles are skipped, so renewal reminders skip them too.

The pause feature's Yard Log, after its first questions
billingfeat/pause-subscription
feat/pause-subscription
4 blocks changed since your last visit
  1. DoneShape the pausemain agent3 blocks

    How a pause treats billing is settled.

    Started 2:00 PM, ended 2:06 PM

    Decision 1The billing date stays; paused cycles are skipped. Renewal reminders skip paused cycles too.
    QuestionDoes a paused subscription keep its billing date?answered
    • Keep the date, skip paused cyclesrecommendedThe customer is billed on the same day of the month before and after a pause.
    • Move the date by the length of the pauseEvery later renewal shifts, and so does every reminder.

    Answered Product owner 2:05 PM in the terminal

  2. ActiveSpecify the pausemain agent1 block
  3. PlannedPlan the build0 blocks
  4. PlannedBuild the pause0 blocks
Drawn after the Yard page. The decision sits at the head of the question it settles, and the stages still to come are already listed as planned.

The Yard page

The page follows every Yard Log of every repository on the machine, live. A log reads as a timeline of its stages and blocks, newest or oldest first, or as a Gantt chart of the session, with tasks, subagents, loft runs, and the time spent waiting on you laid out by the clock. A button in the header gathers everything that waits on you and opens it in a panel over the live page, so you can answer while the log keeps moving. Blocks that changed since your last visit are marked. Above the chart, one bar splits the session's busy time into loft runs, subagent runs, active tasks, waits on you, and the rest of the agent's work.

The same branch as a Gantt chart
billingfeat/pause-subscription
feat/pause-subscription
  • Loft runs: 4 min, 8%
  • Subagent runs: 4 min, 8%
  • Active tasks: 23 min, 46%
  • Waits on you: 11 min, 22%
  • Agent work: 8 min, 16%
  • Not idle: 50 min
2:00 PM2:10 PM2:20 PM2:30 PM2:40 PM
main agentSession 1 · Oct 28, 2:00 PM
Shape
Specify
Add the email at the end of a pause
Plan
Build
Pause and resume a subscription
Skip renewals inside a pause
Email when a pause ends
Link the trace
Drawn after the Yard page. The bar at the top splits the session's busy time. Diamonds are decisions on approvals: the first change to the specification was rejected for leaving out the end-of-pause email, and the fix you asked for runs as its own task, named in pink. Each build task is pale from the plan's approval until it starts, then solid until it is done.

Where the repository holds a Loft specification, the agent records loft's reports instead of retelling them: the change to the specification against the branch it was cut from, the findings of loft check with a reason for each one left in place, and trace coverage once the tests are linked. The page draws each report in its own form. It also shows the tokens each stage took, per agent, so the cost of specifying a change sits beside the cost of building it.

The specify stage, opened
  1. DoneSpecify the pausemain agent5 blocks

    An approved change to the specification says how a pause works, end to end.

    Started 2:06 PM, ended 2:24 PM

    DoneFixAdd the email at the end of a pause

    Added a requirement and its criterion for the email a customer gets when a pause ends, after the first change was rejected for leaving it out. fmt and check pass with no findings.

    New since your last visit

    main agentversion 22:21 PM▸ 1 earlier version

    loftSpec change

    One new Feature for pausing a subscription, and one changed criterion of renewal. No change to how invoices are drawn.

    Compared with develop at 4c1e9a7b2d.

    • Billing
      • Subscriptions
        • Pause a subscriptionadded
          • When a customer pauses a subscription, the system shall hold it for up to three months.added
            • A pause longer than three months is refused.added
            • The billing date stays the same after a pause.added
          • When a pause ends, the system shall email the customer.added
            • The email goes out on the day the pause ends.added
        • Renew a subscription
          • The system shall charge each subscription on its billing date.
            • A renewal inside a pause is skipped.changed

    ▸ 7 nodes changed

    Recorded 4c1e9a7b2d on feat/pause-subscription, with changes not committed, by loft, 2:21 PM

    approvalApprove the change to the specificationapproved

    Approved Product owner 2:24 PM on the page

Drawn after the Yard page. The fix task is the correction you asked for when you rejected the first change. loft recorded the spec change as a tree of the nodes it added and changed, and the approval stands right after it.

The loop, written into the skill

The yard skill carries the workflow we use for every change, so it doesn't need restating each session. It follows the Loft loop, Author → Ratify → Implement → Reconcile → Decide, with the Yard Log keeping each step.

One change, one branch, one Yard Log
  1. Ask for the change on a new branch
  2. Opens the Yard Log with its stages and sends the first decision point's questions together
  3. Answer on the page or in the terminal
  4. Writes the change to the specification, passes loft check, records the change, and asks for approval
  5. Approve the change, or reject it with a reason
  6. Commits the specification on its own, then presents the build in plan mode, step by step against the criteria
  7. Approve the plan
  8. Builds test-first, marks each task as it runs, links the trace, and closes the Yard Log before the merge

Two rules carry most of the weight. The change to the specification is approved before it is committed, and committed on its own, so the code is checked against criteria you have already read. The build is then planned in plan mode from that specification, naming the criteria each step meets; if you change a requirement midway, the agent presents again only the steps the change touches. If you ask only for a plan, the agent stops once the plan is written and leaves the build stages planned until you ask for the build.

The build plan, approved from plan mode
  1. DonePlan the buildmain agent2 blocks

    A bounded build plan covers the approved pause and its tests.

    Started 2:24 PM, ended 2:29 PM

    planBuild the pauseapproved

    Approved Product owner 2:29 PM in the terminal

    Outcome

    Build the specification approved in 4c1e9a7: a customer can pause a subscription for up to three months, renewals inside the pause are skipped, the billing date stays, and an email goes out when the pause ends.

    Four bounded tasks

    1. Pause and resume in the billing model. Store the pause with its end date and refuse one longer than three months. Meets "A pause longer than three months is refused."
    2. Skip renewals inside a pause. The renewal job skips a cycle inside a pause and keeps the billing date. Meets the changed renewal criterion and "The billing date stays the same after a pause."
    3. Email when a pause ends. Send it once, on the day the pause ends. Meets "The email goes out on the day the pause ends."
    4. Link the trace. Each test is written first, fails, then passes; link it to its criterion and run loft reconcile.
Drawn after the Yard page. The agent presented the plan from plan mode, and the approval given in the terminal reached the Yard Log on its own. Each step names the criteria it meets.

When the work is finished, ask the agent to close the Yard Log. It commits the closed log, and then the branch merges. Run loft publish on the publish branch afterwards, and the change becomes part of the next published, immutable version of the contract; the agent records that publish in the Yard Log the merge brought in.

A Yard Log lives in git

A Yard Log is YAML under .yard/<branch>/, committed in each commit of the work, so it travels with the branch and is read in review. Answers you gave since the last commit go in with the next one, along with each session's token totals and activity. When a merge brings two copies of one Yard Log together, the merge driver joins them record by record.

If your team keeps plans off git, add .yard/ to .gitignore. The agent sees that git ignores the folder and commits nothing of it; the log stays on your machine, and the page works the same. What belongs to the machine rather than a branch, such as the page server's address and each session's events, lives in ~/.yard/.

Built with Yard

Once the first version worked, we built the rest of Yard with it. Each ticket got its own branch and its own Yard Log, and each began the same way: the agent read the ticket, asked its questions on the page, and had its change to the specification approved before writing code.

The logs showed what the transcripts had hidden. Work that a subagent did without a stage of its own went uncounted, so it now counts toward the stage of the agent that launched it and is drawn inside that stage's bar. Part of each stage went on corrections we had asked for, so a task can be a fix, and the page marks fixes apart. A status pane built earlier for Claude Code turned out to show nothing the Yard page didn't, so we removed it, through the specification like any other change.

Claude Code and Codex

Yard's core keeps the log, the submissions, the reports, and the page without knowing which agent writes to them. Each agent host has a native adapter that turns its tools and events into Yard's commands, and both adapters are built from one skill source with a short adaptation per host. A Claude Code session on one branch and a Codex session on another appear side by side on the same page.

In Codex, add the same marketplace with codex plugin marketplace add Ask-Loft/loft, then codex plugin add loft@ask-loft, or choose it in /plugins. Review and trust the plugin's hooks in /hooks, and keep features.hooks = true in Codex's configuration, since the skill alone leaves the hooks off. Then ask for the work with $yard. Answer Codex's questions on the Yard page: a background watcher passes each answer into the session, so the agent picks it up without polling. Plans from both agents look the same on the page. The adapter works with local Codex sessions.

The Codex adapter was itself built in Codex, with Yard keeping its log, while a Claude Code session checked that the Claude adapter still worked.

Try it on one branch

Pick a change you were about to start anyway. Set the repository up with loft init and the merge driver, add the plugin, cut the branch, and ask for the work with the yard skill. Answer the first questions on the page, read the change to the specification before you approve it, and read the closed Yard Log beside the diff before you merge. The source and the full command reference are in the Loft repository on GitHub.