Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lore",
"description": "LLM-optimized knowledge graph for AI-coding teams \u2014 transcripts captured and archived, facts filed as repo artifacts, repo-scoped context injected at session start.",
"version": "0.99.2",
"version": "0.100.0",
"author": {
"name": "Christof Buchbender"
},
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
name: ci

# The prerequisite gate for every PR into epic/161 and main. Keep pytest
# green. ruff is advisory (continue-on-error) until the repo-wide
# lint/format cleanup lands — see #196 — so it reports without blocking.
# The prerequisite gate for every PR. Keep pytest green. ruff is advisory
# (continue-on-error) until the repo-wide lint/format cleanup lands — see
# #196 — so it reports without blocking. `push` is limited to main: a bare
# `push` ran every PR commit twice, once per event.
on:
push:
branches: [main]
pull_request:

jobs:
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Versioning: [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
(0.x means anything can change between minor versions until 1.0).

## [0.100.0] - 2026-11-11

`build` epic mode builds and merges locally, so CI runs once per epic.

### Changed

- **An epic reaches the remote once.** `build` creates `epic/<issue>` locally and pushes nothing while the features build. The epic tail commits docs, logbook entry and version bump locally, then pushes once and opens the epic PR.
- **A feature has no PR.** The teammate commits on its branch and does not push. The lead merges the branch into `epic/<issue>` after a green local run of the full suite and ruff.
- **The sub-issue holds the feature record.** The teammate posts its summary and the red→green evidence as a sub-issue comment. The reviewer posts the verdict block there. The whole-epic verdict goes on the epic issue.
- **The review reads a local range.** In `epic` mode the lead passes `--range epic/<issue>..feat/<n>-<slug>` to `lore workflow risk` and the branch to `code-review`.
- **The logbook entry of an epic refers to the epic issue.** The epic PR does not exist when the lead writes the entry.
- **One early push stays possible.** A cross-repo pin that resolves only from the remote (image, package) lets the lead push the producer's `epic/<issue>` early.
- **CI of this repo runs once per PR commit.** `ci.yml` limits the `push` trigger to `main`. A bare `push` trigger ran each PR commit twice, once per event.

## [0.99.2] - 2026-11-11

PR #583 (fix eight small defects from the triage of 2026-11-11).
Expand Down
3 changes: 2 additions & 1 deletion docs/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ large trackers.
`document` runs inside the `build` epic tail, before the epic PR merges
(ADR 0005):

1. Every feature PR merged into `epic/<n>`, and its CI is green.
1. Every feature branch merged into the local `epic/<n>` on a green local
run. Nothing is pushed yet.
2. `document` in pre-merge mode updates the Diátaxis docs for the whole
diff. It commits them onto the epic branch. No separate docs PR.
3. `document` runs `lore workflow prd-ship` to set the PRD's status to
Expand Down
3 changes: 2 additions & 1 deletion docs/how-to/run-an-epic.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ needs work before any code. For one small, clear change, use the

- **The build runs without you.** AFK features run on their own. `build`
stops for a HITL feature, a review that keeps failing, or a conflict no
teammate resolves. Feature PRs merge into the epic branch without you.
teammate resolves. Feature branches merge into the epic branch locally,
without you and without a PR; the epic branch is pushed once, at the end.
The epic PR into the target branch waits for your merge approval in the
conversation. Without you, the epic PR stays open.
- **Read the run on the board.** `build` keeps one status comment on the
Expand Down
2 changes: 1 addition & 1 deletion lore-workflow/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "lore-workflow",
"description": "Deterministic epic/PRD/TDD workflow skills for AI-coding teams. Depends on lore.",
"version": "0.23.1",
"version": "0.24.0",
"author": {
"name": "Christof Buchbender"
},
Expand Down
2 changes: 1 addition & 1 deletion lore-workflow/skills/build/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ epic starts after its upstream epic merged.
## Rules for every mode

- **Test first.** Use [`tdd`](../tdd/SKILL.md) for every behaviour a test can observe.
- **Never merge on red.** CI status and ruff come from `gh pr checks <n>`, never from a model. No ruff job in CI: run `ruff check` and `ruff format --check`, read the exit codes. Exception: an `epic` feature PR merges on a green local run (`epic.md` § Merge).
- **Never merge on red.** CI status and ruff come from `gh pr checks <n>`, never from a model. No ruff job in CI: run `ruff check` and `ruff format --check`, read the exit codes. Exception: an `epic` feature branch has no PR and merges on a green local run (`epic.md` § Merge).
- **Decision gate.** An ADR, a PRD or a wiki topic-note edit outside a grilling session is a PR. A human approves its merge. Draft an ADR only after the user approved its ledger line.
- **Merge approval.** A PR that ends a `loop` or `issue` run, or an epic PR, merges only after the user approves it in the conversation. Post one message: the PR link, `gh pr diff <n> --name-only`, the review verdict, `gh pr checks <n>`, the ledger outcomes. Ask whether to merge. On a clear yes, merge with the repo's usual method and report the merge SHA. Silence or a reply about something else is not a yes. The user can merge on GitHub instead; then go on from the merged state.
- **Tiers.** A spawn's model is `lore tier resolve <tier>`; its description opens with its stage tag (`../../TIER-DELEGATION.md`). Spawn only the subagents a mode names, or for parallel or isolated work. For one lookup, grep or read directly.
Expand Down
33 changes: 19 additions & 14 deletions lore-workflow/skills/build/epic-tail.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# Epic tail

Read this when every build-order row is `merged`. Do not wait for CI here: the tail adds commits,
and only CI on the last one counts (§ 4).
Read this when every build-order row is `merged`.

## 1. Open the epic PR
## 1. Stay local until § 4

Open one PR `epic/<issue> → <target_branch>` that links every sub-issue. Write the body through
[`file-issue`](../file-issue/SKILL.md) in PR-body mode.
§§ 2 and 3 and the first steps of § 4 commit on the local `epic/<issue>`. The branch reaches
the remote once, in § 4, after the last commit. Each earlier push would run CI again.

## 2. Resolve the ledger

Expand Down Expand Up @@ -38,7 +37,7 @@ gh api repos/<owner>/<repo>/issues/comments/<id> --jq .body \
- **Roadmap.** Remove the shipped roadmap item from its `ROADMAP.md`: the item that links this
epic or its PRD. Commit the change on `epic/<issue>`.
- **Whole-epic review**, only for an epic with three or more features. Follow
[review.md](review.md) on the epic PR, after the docs commit, with the tag
[review.md](review.md) on `<target_branch>..epic/<issue>`, after the docs commit, with the tag
`[build:epic-review]`. The reviewer checks
cross-feature consistency: naming, duplicate helpers, conflicting edits to shared files. It
also checks the docs commit against the behaviour. No separate docs round. For one or two
Expand All @@ -49,16 +48,22 @@ gh api repos/<owner>/<repo>/issues/comments/<id> --jq .body \

## 4. Merge

1. Run `lore log add --ref <owner/repo#epic-pr> --text-file <file>` in the epic worktree, as
[logbook.md](logbook.md) says. The `[logbook]` line stays in the local ledger of that
worktree, not on the board. Commit the change under `docs/logbook/` on `epic/<issue>`.
1. Run `lore log add --ref <owner/repo#epic> --text-file <file>` in the epic worktree, as
[logbook.md](logbook.md) says. The ref is the epic issue: the epic PR does not exist yet. The
`[logbook]` line stays in the local ledger of that worktree, not on the board. Commit the
change under `docs/logbook/` on `epic/<issue>`.
2. Add the version bump as the last commit, if the repo's `AGENTS.md` or `CLAUDE.md` requires
one.
3. Run the ledger check on the board: `gh api repos/<owner>/<repo>/issues/comments/<id> --jq
.body | lore workflow ledger-check -`. Do not merge while it exits 1.
4. Check `gh pr checks <epic-pr>` on the last commit. Pending: post the approval message anyway
and merge once green. Red: fix on `epic/<issue>` before you merge.
5. Ask for the merge approval, as the rules in [SKILL.md](SKILL.md) give it. When `epic-policy` returned `deploy_gate: true`,
4. Run the full suite and ruff on the last commit, and every other check the repo's CI runs
that you can run locally. Red: fix before the push.
5. `git push -u origin epic/<issue>`, then open one PR `epic/<issue> → <target_branch>` that
links every sub-issue. Write the body through [`file-issue`](../file-issue/SKILL.md) in
PR-body mode. Set the PR on the board.
6. Check `gh pr checks <epic-pr>` on the last commit. Pending: post the approval message anyway
and merge once green. Red: fix on `epic/<issue>` and push again before you merge.
7. Ask for the merge approval, as the rules in [SKILL.md](SKILL.md) give it. When `epic-policy` returned `deploy_gate: true`,
name the deploy gate in the same message and note the yes on the board. Merge on a yes.
An unreachable user leaves the epic PR open.

Expand All @@ -73,7 +78,7 @@ its ledger. Name each entry that is still undelivered under **Known limits**.

## 6. Cleanup

Delete every merged feature branch, local and remote, and remove its worktree. Keep only the
Delete every merged feature branch and remove its worktree. Keep only the
history of the epic branch. Run `lore workflow ledger-archive` in the checkout that holds the
board line, so SessionStart stops offering the epic.

Expand All @@ -87,5 +92,5 @@ Verify each item, then report:
- [ ] the board shows no `queued` or `running` row
- [ ] the PRD status is `shipped`, or the catch-up docs PR is open
- [ ] no roadmap item links the epic or its PRD any more
- [ ] every feature branch and worktree gone, local and remote
- [ ] every feature branch and worktree gone
- [ ] the local ledger with the board line archived
36 changes: 19 additions & 17 deletions lore-workflow/skills/build/epic.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ You plan, dispatch, review and merge; teammates write the feature code. Run with
Stop only for completion or a stop condition.

**Map.** Read the epic body and build order. Run `lore workflow epic-policy <repo_root>` once per
repo: `{target_branch, deploy_gate}`. Feature PRs target `epic/<issue>`, which merges into
`target_branch` through one epic PR.
repo: `{target_branch, deploy_gate}`. Feature branches merge into `epic/<issue>` locally. That
branch reaches the remote once, as one epic PR into `target_branch`, so CI runs once per epic.
Issues, their comments and the board stay on GitHub.

**Resume.** Pipe the board comment (marker below) to `lore workflow parse-board`. `merged` is
done; `queued`/`blocked` is dispatched again. Reuse an existing `epic/<issue>`. Read the last
resume line in `ledger`. Write the board line below if the local ledger lacks it. No board: fresh run.

**Gate.** `lore workflow validate-build-order --json` on the epic body. `ok: false`: report
`problems`, stop. A feature's batch is its DAG depth. **Compact** band (one repo, every row AFK,
one feature per batch): one teammate builds the features in order, still one branch and one PR
each. Otherwise **standard**: up to four teammates at once.
one feature per batch): one teammate builds the features in order, still one branch each.
Otherwise **standard**: up to four teammates at once.

**Board.** One comment on the epic issue, edited in place, never a second one:

Expand All @@ -35,11 +36,12 @@ each. Otherwise **standard**: up to four teammates at once.
```

`parse-board` reads marker and columns verbatim; the marker keeps its old name. `State` is
queued, running, review, merged or blocked. Then create and push `epic/<issue>` from `target_branch`.
queued, running, review, merged or blocked. The `PR` column stays `—` until the epic PR exists.
Then create `epic/<issue>` from `target_branch`, locally. Push nothing before the epic tail.

**Spec branch.** Run `lore workflow spec-branch <body file> --repo <repo_root>` only in the repo
of the `**PRD:**` link; it prints `{branch, prd, needs_merge, ref}`; exit 1: stop. `needs_merge`:
merge the printed `ref` into the new `epic/<issue>` there, push it, then dispatch. A conflict:
merge the printed `ref` into the new `epic/<issue>` there, then dispatch. A conflict:
abort the merge, stop and report. No second PR; push nothing to `target_branch`.

**Board line.** Record the board in this checkout's local ledger: `lore workflow
Expand All @@ -54,31 +56,31 @@ Tier: `mid` well-scoped, `strong` cross-cutting. Fill [teammate-brief.md](teamma
teammate silent about 30 minutes is spawned once more in the same worktree; a second death
blocks the feature.

**Review.** Feature PR: [review.md](review.md). PASS: merge as below.
**Review.** Feature branch: [review.md](review.md). PASS: merge as below.

**Merge.** Never wait for CI here. In a worktree of `epic/<issue>`: `git pull --ff-only`, `git
merge --no-ff feat/<n>-<slug>`, run the full suite and ruff, read the exit codes. Green: `git
push`; GitHub marks the PR merged. Red or a conflict: `git reset --hard ORIG_HEAD`, back to the
teammate. Cross-repo: read the `pin` of the edge between producer and consumer
**Merge.** No CI runs here; the local run is the gate. In a worktree of `epic/<issue>`: `git
merge --no-ff feat/<n>-<slug>`, run the full suite and ruff, read the exit codes. Green: the
merge stands. Red or a conflict: `git reset --hard ORIG_HEAD`, back to the teammate.
Cross-repo: read the `pin` of the edge between producer and consumer
(`lore map <consumer> --json`). Merge the producer and record what the pin names (SHA, tag, image
or package version) before dispatching the consumer. Without an edge, record the producer's SHA.
The consumer reads the producer from its local checkout. A pin that resolves only from the
remote (image, package) is the one early push: push the producer's `epic/<issue>` and note it
on the board.
After each merge:
- tick its build-order box;
- close the sub-issue (`gh issue close <n> --comment "Merged via PR #<pr>"`);
- close the sub-issue (`gh issue close <n> --comment "Merged into epic/<issue> at <sha>"`);
- set the row to `merged`;
- add the teammate's ADR and term candidates to the ledger;
- add the resume line (breakpoint);
- where the repo has migrations, check that one migration head remains.

At next dispatch glance at `gh run list --branch epic/<issue> -L 3`. A red run the local
suite missed gets a fix; the epic PR merges on green CI only.

Then dispatch what the merge made ready.

**Human present, on request.** Needs all three: the user asks for a quick run and stays
present; every row is AFK; one repo without a deploy gate holds all rows.
- Build the slices that share new files yourself, on `epic/<issue>`.
- Teammates get only independent slices. They commit without a PR; you merge with `--no-ff`.
- Teammates get only independent slices.
- Your own slices may write tests beside the code. Then break two or three pieces of key logic,
confirm the tests fail, restore, and note the check on the board.
- Then run the epic tail.
Expand All @@ -87,7 +89,7 @@ present; every row is AFK; one repo without a deploy gate holds all rows.

**Stop conditions:**
- a HITL row;
- a PR still failing after two fix rounds;
- a feature still failing after two fix rounds;
- an ambiguous spec that needs a scientific or architectural call;
- a merge conflict no teammate resolves;
- a CI infrastructure failure.
Expand Down
23 changes: 15 additions & 8 deletions lore-workflow/skills/build/review.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
# Review a PR

Read this when a PR opens in `issue` or `epic` mode, and for the epic PR.
Read this when a PR opens in `issue` mode, for each `epic` feature branch, and for the
whole-epic review.

## 1. Deterministic checks first

- `gh pr checks <n>` answers CI and ruff. A red check blocks the merge. The reviewer does not
judge it. An `epic` feature PR is the exception: the lead's local run gates it
([epic.md](epic.md) § Merge), and nobody waits for its CI.
judge it. `epic` mode is the exception: a feature branch and the whole-epic review have no PR
and no CI run. The lead's local run gates them ([epic.md](epic.md) § Merge), and CI answers
once, on the epic PR ([epic-tail.md](epic-tail.md) § 4).
- A check that fails on the base branch too is inherited. It does not count against this PR.
Name it as a blocker: in `epic` mode in the board's Notes, in `issue` mode in the PR body.

## 2. Risk level sets the review depth

Run `lore workflow risk <n> --json`. It prints `{level, reasons, notes, files, lines}`.
In `epic` mode nothing has a PR number: pass `--range epic/<issue>..feat/<n>-<slug>` to `risk`
and the feature branch to `code-review` in place of `<n>`. The whole-epic review uses
`<target_branch>..epic/<issue>` and the epic branch.

| Level | Reviewer tier | Correctness pass |
|---|---|---|
Expand All @@ -29,7 +34,7 @@ Resolve the tier with `lore tier resolve <tier>` and pass the result as the mode
description with `[build:review] <owner/repo#issue>`, the epic or issue under review. For the
whole-epic review, open it with `[build:epic-review] <owner/repo#epic>`. The reviewer
reads the diff and the linked sub-issue. In `epic` mode, keep one reviewer per batch and level.
Send each later PR of that batch to it with `SendMessage`, so it sees siblings side by side.
Send each later feature of that batch to it with `SendMessage`, so it sees siblings side by side.

The reviewer judges three things only: correctness, acceptance criteria, scope. A roadmap item
that `lore roadmap add` filed under `## Not placed yet` is in scope. The reviewer runs
Expand All @@ -39,7 +44,9 @@ finding fails the line. Cleanup findings go in the note only.
The "failing test first" check does not apply to the lead's own slices in the human-present
option of `epic` mode. There the mutation check on the board replaces it.

The reviewer posts this block as a PR comment (`gh pr comment <n> --body-file …`) and returns it:
The reviewer posts this block as a PR comment (`gh pr comment <n> --body-file …`) and returns it.
In `epic` mode the block goes on the sub-issue (`gh issue comment <n> --body-file …`), the
whole-epic block on the epic issue. Its first line then names the branch and its head SHA:

```
PR #<n>
Expand All @@ -56,11 +63,11 @@ Any `fail` line makes the verdict FAIL.

## 4. Act on the verdict

- **PASS, `epic` feature PR:** merge it into `epic/<issue>` on a green local run ([epic.md](epic.md) § Merge).
- **PASS and green checks, the epic PR:** go back to [epic-tail.md](epic-tail.md) § 4.
- **PASS, `epic` feature branch:** merge it into `epic/<issue>` on a green local run ([epic.md](epic.md) § Merge).
- **PASS, the whole-epic review:** go back to [epic-tail.md](epic-tail.md) § 4.
- **PASS and green checks, `issue` mode:** go on to the finish point. Merge after the merge approval.
- **FAIL:** send the numbered fixes to the teammate. In `issue` mode, fix them yourself. The same
reviewer checks that PR again. At most two fix rounds.
reviewer checks the change again. At most two fix rounds.
- A round that does not move the verdict gets the [`debug`](../debug/SKILL.md) method, not "try
again".
- Still FAIL after two rounds: in `epic` mode, mark the feature `blocked`, note it on the board
Expand Down
Loading
Loading