Fills the middle of the site. Nine routes, every body a heading slice of AGENTS.md or README.md, and the article layout given the furniture the design calls for. The manifest gains the two concepts nothing covered: /concepts/task-files/ (the header format, from AGENTS.md's own section) and /concepts/adapters/ (the adapter summary, which is the other half of the three-layer law). /concepts/stages/ now runs through "Moving a task", because the five directories and moving between them are one idea. The layout: - A lede under the title — the one sentence an article authors, taken from the manifest's `description` or an explicit `lede` where the two want different words. A slice starts mid-document; a reader arriving from the nav is owed a line saying what they are looking at. - Prev/next at the foot, walking the sidebar's own order so the arrows and the rail cannot disagree. Pages with no section (the landing page, the 404) are not on the flow. - "Edit this page on GitHub" anchors to the section the page was cut from, built from the same `from` heading the slice starts at. Two bugs the new pages found: - string.Template substitutes inside HTML comments, so a comment naming the body placeholder emitted the whole body twice and closed itself early on the first `-->` in it. - Promotion could produce a second <h1>. A slice that deliberately runs past its own section carries headings at the `from` level, and those promoted to h1 on a page that already had one. Promotion now stops at h2, where they read as peers — which is what putting them on one page said in the first place. tests/test_site_pages.py covers the furniture on the real built site: the routes, the layout, the sidebar marking one page, the contents list being exactly the body's own h2s in order, the prev/next chain end to end, the edit link's anchor, the six landing-page doors, and a table, a fenced block and a nested list surviving the renderer. The scratch-repo helper now copies every file a slice links to, since the builder checks those exist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Bench
A live kanban for coding-agent work: task files in stage directories are
the only source of truth; a stdlib-only board narrates everything that
happens to them — agents working in git worktrees, PRs opening on review,
CI and Copilot state on the cards, drives of the app from a task's own
branch, and an archive that is never a delete. Turn on team mode
(BOARD_SYNC=1) and the truth is origin/main: moves commit and push
themselves, every board pulls on a beat, and the person who claimed a
card first keeps it.
Install into a repo
mkdir .task-manager && curl -L \
https://github.com/12vectors/bench/releases/latest/download/bench.tar.gz \
| tar -xz -C .task-manager
./.task-manager/start.sh # wires the project (idempotent) and serves
No token, no clone: releases are curated artifacts that never contained bench's own cards or settings, so the board starts empty by construction.
The first run asks three questions it cannot answer for you — solo or
team, which agent adapter, what command runs your tests — and writes
manager/local/.env from the documented example, so every other setting
is discoverable in your own copy. Bare Enter takes the default
throughout; with no terminal (CI, a script) it asks nothing and
install.py --setup asks later.
Commit .task-manager/ into the host repo — core is vendored on purpose,
so clones work offline and updates show up in the host's own diffs.
The workflow brief ships as .task-manager/AGENTS.md — the cross-vendor
name coding agents read natively — with CLAUDE.md beside it as a one-line
compatibility pointer. Both live inside .task-manager/, so a host repo's
own root AGENTS.md is never touched.
Update
./.task-manager/update.sh # latest release
BENCH_REF=v2 ./.task-manager/update.sh # an exact release tag
The artifact is stamped with the repo it was built from, so updating
needs no configuration; BENCH_SOURCE=<owner/repo> in
manager/local/.env overrides the stamp. Updates replace
manager/core/ and the top-level scripts wholesale and touch nothing
else — tasks, plans, reference, and everything under manager/local/
(your driver, commands, prompt overrides, settings, state) survive every
update. Then python3 .task-manager/install.py and restart the board.
If the source repo has no published release yet, update.sh says so and
changes nothing.
Working on bench itself
git clone git@github.com:12vectors/bench.git && cd bench && ./start.sh
A clone carries bench's own cards and local/ content — that is dev mode,
not an install. (Installing from a clone anyway works: install.py
clears the shipped cards on its first boot in a host repo.) Releases are
built by ./release.sh from the manifest at
manager/core/release-manifest: tag = v<VERSION>, one stable asset
name (bench.tar.gz), contents at the tarball root — the two things the
install one-liner above depends on.
The three-layer law
Core knows about tasks, worktrees, PRs and events. It knows nothing about
any particular app (drivers do: manager/local/driver/start), agent
vendor (adapters do: manager/core/adapters/), or project
(manager/local/ does).
The consequence is what makes an update safe: update.sh replaces
manager/core/ wholesale, and everything a project taught bench about
itself lives outside it. Full docs in AGENTS.md; the adapter
contract in
manager/core/adapters/README.md.
License
MIT.