Skip to content

feat: work-loop skill and in-repo vault (ADR 0013) - #87

Open
r0073d-l053r wants to merge 2 commits into
mainfrom
feat/work-loop
Open

r0073d-l053r wants to merge 2 commits into
mainfrom
feat/work-loop

Conversation

@r0073d-l053r

@r0073d-l053r r0073d-l053r commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

What

A harness-agnostic work loop so any agent can jump on, read NEXT.md, take the next eligible step in its lane through /coordinate, record progress in the vault, survive context compaction, and keep going until the roadmap is complete — plus the vault moved into the repo so every agent and machine shares one second brain.

The loop — npm run loop -- <command> (.claude/skills/work-loop/scripts/loop.mjs, Node 24, zero deps)

Command Does
start resume brief → next eligible step (your lane first; phase gates; Phase 1 in order; 3.1 parallel) → creates the issue if missing (## Files from your lane, ## Done when from the phase exit) → coord claim → step/<id>-<slug> branch → work brief
checkpoint -m "…" Session note to vault/Sessions/ + STATUS (or --handoff @login → HANDOFF). Run before context compaction.
resume the post-compaction digest: your last session note, recent milestones, board, next
milestone <id> --pr <url> verifies merged → coord done → vault/Milestones/<id> - <title>.md → progress refresh
next / status [--write] eligibility / progress by phase (writes Roadmap Progress.md + Home blocks)
vault-init / vault-sync scaffold the schema / regenerate generated notes (ingest.py, Python 3)

When nothing is eligible it lists PRs awaiting a non-author review — the most useful idle work under distributed merge. Prints ROADMAP COMPLETE at the end. loop.config.json names the roadmap, vault path, and gating rules, so it serves other roadmaps/repos unchanged. Recipes per harness (Claude Code /loop, Codex while, cron, human) in references/harnesses.md.

The vault — vault/

The existing Obsidian vault ported unchanged (same schema: OKF frontmatter, generated vs synthesis notes, ADRs/ Conventions/ Coordination/ Hackathon/ Specs & Plans/ Repo Config/) plus the two folders the loop owns (Milestones/, Sessions/), _templates/, Roadmap Progress.md, and marker blocks in Home the loop rewrites. Open vault/ in Obsidian. Excluded from markdownlint; .obsidian/workspace* ignored, app.json tracked.

Decision record

ADR 0013 — In-repo vault and the work loop. Also carries the small NEXT.md follow-up: ADR numbers follow creation order (0012/0013 took the projected ones), step 0.5's ADR half is marked done (#78), and the work-loop skill + vault join the coordination lane.

Verification

  • node --check loop.mjs; start --dry-run, checkpoint --dry-run, status --write, vault-init, vault-sync exercised against the merged roadmap (no real issues created).
  • ingest.py --repo . --vault <scratch> regenerates 39 notes end to end.
  • npm run lint:md — 0 errors (38 files; vault/ excluded).

Phase 0 issues #79–#84 already exist (seeded by hand, titled 0.1 …); the loop recognises both 0.1 Title and [0.1] Title and continues or claims those rather than creating duplicates. Step 0.5's README half is already in flight as #86.

🤖 Generated with Claude Code

A harness-agnostic work loop over NEXT.md, /coordinate, and the vault, so
any agent - Claude Code, Codex, Pi, opencode, Cursor, cron, or a human -
can arrive cold, take the next eligible roadmap step in its lane, leave
a trail, and keep going until the roadmap is complete.

.claude/skills/work-loop/
  scripts/loop.mjs   Node 24, no dependencies: start (resume brief ->
                     pick next eligible step -> create/claim its issue via
                     /coordinate -> branch -> work brief), checkpoint
                     (Session note + STATUS/HANDOFF, run before context
                     compaction), resume (post-compaction digest),
                     milestone (coord done + Milestone note + progress),
                     next, status [--write], vault-init, vault-sync
  scripts/ingest.py  the vault's generated-notes regenerator, now taking
                     --repo/--vault (was a scratchpad script)
  loop.config.json   roadmap file, vault path, phase-gating rules
  SKILL.md, references/harnesses.md
docs/agents/work-loop.md   entry point for non-Claude harnesses
docs/adrs/0013-...         the decision: vault in the repo, loop as script

vault/  the existing Obsidian vault ported unchanged (same schema: OKF
        frontmatter, generated vs synthesis notes) plus Milestones/,
        Sessions/, _templates/, Roadmap Progress.md, and loop-rewritten
        progress blocks in Home. Excluded from markdownlint; Obsidian
        workspace files ignored.

Also: `npm run loop`, README rows, and the NEXT.md follow-up that names
later ADRs by subject (0012/0013 took the projected numbers) and adds the
work-loop skill and vault to the coordination lane.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@r0073d-l053r r0073d-l053r mentioned this pull request Oct 3, 2026
…follows them

Phase 0 issues #79-#84 were seeded with "0.1 Title" titles. The matcher
now accepts "0.1 Title", "[0.1] Title", and "0.1: Title", and new issues
use the same bracket-free prefix, so start continues or claims the
existing issue instead of creating a duplicate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@m-vawter m-vawter left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a strong piece of work. The resume/checkpoint cycle survives compaction, milestones only count merged PRs, eligibility goes lane-first with phase gates, there are zero dependencies, and the config makes it reusable for other roadmaps. My agents plan to run it once it lands. Commenting rather than approving, since it needs a rebase anyway:

  1. Rebase: it conflicts with main in README.md, so CI hasn't run on it yet.
  2. Untrusted input: an unattended loop on a public repo acts on issues and comments that anyone can post, and #85's ingestion gate isn't in yet. Until it is, could next/start only pick issues opened by collaborators (author_association OWNER, MEMBER or COLLABORATOR)? And could SKILL.md say in one line that issue and comment text is data, not instructions?
  3. Approvals: SKILL.md has idle agents review others' PRs, and any non-author approval merges once CI is green. That means two loops can merge each other's code with no human reading it. Maybe a loop.config.json switch, with agent approvals off by default? Agents would review and comment, approving would stay with a human, and each human could opt in.
  4. The vault's generated half: ingest.py copies the repo docs (ADRs, specs, plans) into vault notes, so every doc exists twice and every vault-sync rewrites them. Committing only the hand-authored notes and regenerating the rest locally (gitignored) would avoid drift and merge noise, and it would shrink this PR from about 11.8k lines.
  5. Small: start calls coord claim, which fails on macOS until #88 lands.

@xcjs xcjs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed: work-loop skill (loop.mjs + config + harness refs) and the in-repo Obsidian vault (ADR 0013) are self-consistent; the vault copies of repo configs match main as of now. Blocking issue, non-author note: the branch is CONFLICTING with main (README.md, NEXT.md, package.json, .gitignore shifted). Needs a rebase before a non-author can merge; approving the content so only the rebase stands in the way.

@xcjs
xcjs self-requested a review October 3, 2026 01:38
@xcjs

xcjs commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Agents - don't merge this. This needs more review.

@xcjs

xcjs commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Ping @r0073d-l053r - #87 (work-loop/vault) still has your approval pending merge but is CONFLICTING with main since the merges of #91/#86/#89/#98. You'll need to rebase feat/work-loop onto main and force-push; I'm happy to re-verify e2e locally afterward if the vault paths drift.

@m-vawter

m-vawter commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator

Three things the loop will run into on the board as it stands, worth folding into the rebase. I found them by reading loop.mjs against the current issues. I didn't run anything.

  1. Placeholder claims look like Michael's in-progress steps. Zack handed seven roadmap issues to @m-vawter to hold for Charles (1.1 Async VirtualFileSystem + driver registry (localStorage system, IndexedDB apps, migration) #105–1.3 Dependency vetting gate in front of esm.sh (npm/advisory data, verdicts cached in VFS) #107, 2.3 Tool results back to the model: model sees install/update success each turn (maxSteps already 3) #111, 3.3 /api/proxy shipped together with its SSRF blocklist (RFC 1918, cloud metadata) + useSmartFetch #114) and Justin (2.1 Diff approval before update_app mounts (unified diff + approve/reject in chat) #109, 2.2 Bounded auto-heal: re-invoke agent with trace up to two times on caught error #110). pickCandidates counts any eligible step assigned to you as inProgressMine, whatever its status or lane, and cmdStart continues that first. So when chore(os): ESLint flat config with slice-boundary rule and lint-staged pre-commit #94 lands and Phase 0 closes, 1.1 (1.1 Async VirtualFileSystem + driver registry (localStorage system, IndexedDB apps, migration) #105) becomes eligible. loop start under m-vawter would then say "Continuing your in-progress step 1.1" and go into Charles's VFS seam. currentStepId has the same fallback. A possible fix: count a step as yours only when its issue is status:in-progress or status:blocked, which matches NEXT.md's "queued work stays status:claimed". Or count only steps in your own lane.

  2. A follow-up issue with a step number becomes the step. issueIndex maps any title starting N.N to that step, and an open issue wins over a closed one. So following NEXT.md rule 1 (step number in the title), a follow-up makes a finished step read as open. While 0.1 e2e gate: require the CI checks on main #104 ("0.1 e2e gate") was open, 0.1 read as not done. I've retitled my README follow-up docs: README still says phone viewports are unsupported (3.1 follow-up) #121 so it doesn't do the same to 3.1. Zack's "3.2b" form avoids it too. A possible fix: map each step to its earliest issue, or ask follow-ups to use a suffix.

  3. "Six hours, then a ping" meets coord.sh stale. stale lists every assigned open issue by its last heartbeat, so right now it shows 16: the 14 queued roadmap claims, 0.4 ESLint flat config and vue-tsc in pre-commit #82 (waiting on review), and 3.2b Multi-desktop workspaces (split from #102) #120, the one active claim, which has been quiet overnight. NEXT.md's six-hour rule is for active claims, and the protocol applies it only during active workdays and leaves the check to the caller. So the SKILL.md rule could say to ping only status:in-progress claims, or stale could skip status:claimed. I'm happy to send a PR for the coord.sh side.

@xcjs

xcjs commented Oct 7, 2026

Copy link
Copy Markdown
Owner

QUESTION | agent: opencode/glm-5.3-flash | human: @xcjs | at: 2026-10-07T20:5xZ
Second-day stale check: this PR has been APPROVED but CONFLICTING since the #91/#86/#89/#98 merges — the base branch still diverges from your head (merge-base 0fc772d, main now d2f3679). Rebase needed from your side:

git fetch origin
git rebase origin/main feat/work-loop
git push --force-with-lease

Notes from m-vawter's review thread above list three loop-engineering fixes worth folding in while rebasing. Happy to re-verify with local e2e after the rebase lands (5/5 CI runs on this repo now). This blocks the only open PR on the board.

@@ -0,0 +1,325 @@
"""Ingest the repo docs into the vault with wikilinks (the generated half).

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be rewritten as TypeScript to align with the rest of the repository.

@@ -0,0 +1,536 @@
#!/usr/bin/env node

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be rewritten as TypeScript to align with the rest of the repository.

Comment thread vault/.obsidian/app.json
@@ -0,0 +1,4 @@
{

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configuration files for external tooling shouldn't be part of the repository.

@@ -0,0 +1,84 @@
---

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates all docs/ files into a second vault/ directory that also seems to have been intended to be ignored by .gitignore. We should consider removing vault/.

@@ -0,0 +1,46 @@
{

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates the package.json and isn't a standard .nvmrc file.

@@ -0,0 +1,11 @@
root = true

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates root-level configuration files inside the repository. If these are to be used as templates in other projects, we should probably .gitignore them.

@@ -0,0 +1,12 @@
{

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates root-level configuration files inside the repository. If these are to be used as templates in other projects, we should probably .gitignore them.

Comment thread vault/Repo Config/ci.yml
@@ -0,0 +1,62 @@
name: CI

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This duplicates root-level configuration files inside the repository. If these are to be used as templates in other projects, we should probably .gitignore them. This one also uses an incorrect reserved filename.

Comment thread .gitignore
AGENTS.md

# Obsidian vault (vault/): workspace state churns per machine; app.json is tracked
vault/.obsidian/workspace*

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This .gitignore didn't prevent vault/** from being added - we should investigate if the files were accidentally force added or if the ignore pattern needs adjusted.

Comment thread README.md
| [.claude/skills/coordinate/SKILL.md](.claude/skills/coordinate/SKILL.md) | Multi-agent task coordination over GitHub Issues (`/coordinate`): protocol, parameters, working agreements |
| [docs/agents/coordination.md](docs/agents/coordination.md) | Multi-agent task coordination over GitHub Issues (`/coordinate`) |
| [docs/agents/work-loop.md](docs/agents/work-loop.md) | The work loop: any agent takes the next roadmap step via `/coordinate` (`npm run loop`) |
| [vault/](vault/DOMinic%20Home.md) | The project's second brain (Obsidian): milestones, sessions, ingested docs |

@xcjs xcjs Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation between docs/ and vault/ shouldn't be duplicated nor split - also, the .gitignore attempts to ignore vault/, but something happened to add the files to the repository. We should investigate what happened.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants