The third design layout (1c Logbook) had no page. This lands it, and with it the four routes a reader reaches for when the guides have stopped answering: /reference/settings and the three contracts a project implements against. The settings page is parsed, not transcribed. site/build.py grows a second way to make a body — a page may say "generate": "settings" instead of a "from" heading — and manager/core/.env.example is read on every build: its blank-line blocks become the page's entries, a comment block documents the keys directly under it, and the file's own NAME=value lines are the defaults shown. A key with no comment above it, or one set twice, stops the build naming the route; a settings page that disagrees with the settings file is worse than no settings page. Generated bodies render with raw HTML off. The file writes <git user.name> meaning a placeholder, and a parser honouring HTML swallows it — it was never written to be markdown. The reference layout is the article's three columns with the contents gutter given over to a console: every entry on the page once more in the machine register, keys with their defaults on the settings page and headings on a sliced one. It links the same anchors "On this page" carries, so the 1080px step folds the whole column away and the contents strip hands them back — no third copy of anything, and the responsive rules already in the sheet cover it. The contract pages are slices like every other page: the adapter contract and its event schema out of manager/core/adapters/README.md, the driver and local-command contracts out of AGENTS.md. Renaming any of those headings stops the build naming its route. tests/test_site_reference.py holds the promise: add a key to .env.example with its comment, rebuild, and it is on the page with its default, with nothing in site/ edited. 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.