Files
6krrt/plans/readme-restructure.md
adlee-was-taken 3523dcf93e docs(plans): give every plan a Status line so the queue is greppable
plans/ held 58 documents and exactly one said whether it was open. The rest
mixed finished work, reviews of shipped work, parked specs and genuinely
pending ones, with nothing distinguishing them, so "how many plans are in
the queue" had no answer short of reading all 58.

Now `grep -H '^Status:' plans/*.md` is the answer:

    50 done   3 in progress   2 planned   2 reference   1 parked

Statuses were derived rather than guessed: CLAUDE.md's own built list and
"What's NOT built yet" section, plus checking the subject exists in the
code. A review of work that shipped counts as done -- it records what was
found, it is not a request for anything. `reference` separates the two docs
that are conventions rather than work items (admin-design-standards,
admin-work-framework), which otherwise read as permanently-open plans.

The vocabulary is deliberately five words. A larger one invites "mostly
done" and "blocked-ish", which is how the directory became unreadable.

test_plans_declare_status.py keeps it from rotting: a new plan without a
marker fails, as does an unknown status, one buried below the eighth line,
or an open status with no reason -- "planned" alone is the state that rots,
since nobody can tell later whether it waits on a decision, a dependency,
or just nobody's turn.

Also updates the sweep plan with what landed and what did not, including
that #9 was not a defect.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRQXz5SYZYVWscxS1QqF6U
2026-09-08 18:55:16 -04:00

194 lines
12 KiB
Markdown

# Spec: restructure README.md around a pitch → features → install → per-command usage shape
Status: done -- current README
**Origin.** Modeled on the structure of
[`dsplce-co/supabase-plus`'s README](https://raw.githubusercontent.com/dsplce-co/supabase-plus/refs/heads/master/README.md)
— its section shape and pacing, not its content or voice. `supabase-plus` is
a Rust CLI tool with crates.io badges, install-method sub-sections, and
punchy, jokey per-command usage blurbs; none of that is this project. What's
being borrowed is purely structural: a short pitch up front, a scannable
features list, a Table of Contents for a doc long enough to need one,
installation broken into named sub-methods, and — the part worth the most —
usage organized **per command**, each with its own short "why you'd want
this" motivation before the command itself, rather than one long undifferentiated
block of curl examples.
This project's own voice stays: dry, evidence-first, "measured live on
[date]" citations, numbers with dates on them. Nothing here asks for new
jokes, new claims, or new numbers — only reorganizing what's already true in
the current 1039-line `README.md` into a shape a first-time reader can
actually navigate.
No README changes accompany this document — this is the spec opencode
builds from.
---
## What's being borrowed, what's being skipped, and why
| Reference element | Verdict | Reasoning |
|---|---|---|
| Org attribution banner (top link) | **Skip** | No org; this is a personal project. |
| Badges row (crates.io, license, version) | **Skip, or minimal** | Nothing here is published to a package registry. A license badge only makes sense once a license exists (see Open Decisions below) — don't badge something that isn't true yet. |
| One-line pitch + short elaboration paragraph | **Adopt** | The current README already has this content (see §1 below) — it's just buried under a heading instead of leading the file. |
| Italic disclaimer right after the pitch | **Adopt, re-aimed** | The reference's is a trademark disclaimer. This project's real analog already exists and is more load-bearing: *"Numbers in this README are measurements, not specifications"* (current README, "What This Is"). Same structural slot — a caveat before anyone trusts a number — different content. |
| Demo GIF | **Optional, not this pass** | `tui.py`'s live dashboard is the natural candidate, but capturing one is a manual terminal recording step, not something a text plan can produce. Leave a placeholder comment (`<!-- TODO: tui.py demo gif -->`) rather than skip the idea entirely. |
| `## Features` — punchy bulleted list | **Adopt, own voice** | See §2. The existing "At a Glance" table already IS a features summary, just in dry-table form instead of scannable bullets. |
| `---` / Table of Contents | **Adopt, straightforwardly** | The current README has **no TOC at all** across ~25 major sections and 1039 lines. This is the single highest-value, lowest-risk item in this whole plan — pure navigation, no content decisions required. |
| `## Installation` with named sub-methods | **Adopt, honestly scoped** | The reference has 6 real install methods (nix/cargo/homebrew/deb/apt/aur). This project has exactly one (`venv` + `pip`) plus a systemd deployment path. Structure as two sub-sections — "Local" and "As a systemd service" — not six fake ones. Do not invent install methods that don't exist to mimic the reference's breadth. |
| `## Usage` — one sub-heading per command, motivation → command → bullets | **Adopt — the main point of this plan** | See §3. This is the biggest actual improvement available: the current "Quick Usage" section is 9 curl commands in one code block with almost no narrative, while the *reasons* for each one are already written elsewhere in the doc, disconnected from the command they justify. |
| `## Requirements` | **Adopt** | Already exists as a sentence in "Setup" ("You need: a Neuralwatt API key, Python 3.10+...") — promote it to its own short section, matching the reference's terse bulleted form. |
| `## Repo & Contributions` | **Needs a decision, see below** | The reference is a public GitHub project soliciting PRs. This repo's remote is a private, self-hosted Gitea instance (`git.adlee.work`) — "PRs welcome" isn't true here. |
| `## License` | **Needs a decision, see below** | No `LICENSE` file exists in this repo (checked directly). The reference names MIT/Apache-2.0 because those are real, chosen licenses. Do not write a license section that names something that isn't actually true. |
## Open decisions (yours, not opencode's to invent)
Two sections in the reference structure map to facts that don't exist yet
in this repo. Both should be **explicit decisions**, not filled in by
guessing during implementation:
1. **License.** Pick one (or explicitly decide "unlicensed / private, not
for redistribution") before a `## License` section gets written. Whatever
is decided, add the matching `LICENSE` file at the same time — a README
section naming a license with no `LICENSE` file in the repo would be the
exact "documented but not actually true" failure mode this project's own
`config.yaml` strictness rules exist to prevent elsewhere.
2. **Repo & Contributions.** Given the remote is a private Gitea instance
rather than a public GitHub project, decide whether this section exists
at all, and if so what it actually says — a link to the internal remote
for your own reference, not an open invitation for outside contributions
that can't reasonably arrive here.
If no decision is made, the plan's default is: **omit both sections** rather
than have opencode fabricate a license or a contribution policy that isn't
real.
## Section-by-section mechanism
### §1. Pitch + elaboration (replaces the top of "What This Is")
Move the existing lead paragraph up to immediately follow the `# Local LLM
Model Router` title, ahead of any subheading — this is exactly what the
reference does (pitch line, then one elaborating paragraph, before any `##`).
Source material already exists verbatim in the current README's opening
paragraph and the "Numbers in this README are measurements, not
specifications" caveat — this section is a move-and-reflow, not a rewrite.
### §2. `## Features`
Reference pattern: one bullet per capability, phrased as a real situation
the reader has been in, followed by the command that fixes it. This
project's own voice should replace "clever/jokey" with "concrete/measured" —
the through-line of the whole existing document. Candidate bullets, pulled
directly from existing content rather than invented:
- `POST /route` — "Want to know what a task would cost before you spend
anything on it?" *(current README: "no provider call, no cost")*
- Per-request energy/cost pricing — "List price ranks models backwards for
this workload; billing is per-kWh, and this router prices per request from
what's actually shaped like your traffic." *(current: "Weighted Scoring"
section)*
- Local vision fallback — "Your cheapest coding model doesn't support
images. This one falls back to a local model instead of 422ing."
*(current: "Local Vision Fallback")*
- Live TUI — "`python tui.py`, a live routing feed with no polling delay."
*(current: "Monitoring")*
- Structural + local-LLM verification — "Every response gets checked for
free before routing ever learns from it." *(current: "Verification
Pipeline")*
Five bullets, matching the reference's scope (3 headline + "and others
like"), not an exhaustive re-listing of every feature — the full detail
still lives in its own section further down, same as the reference's
`## Usage` expands on its `## Features` teasers.
### §3. `## Usage` — the main restructuring work
Current "Quick Usage" is one code block, 9 `curl` commands, minimal
narrative. Reference pattern is one `###` sub-heading per command: a short
paragraph on *why* (often phrased as the problem the reader already has),
then the command, then a bullet list of what it actually does.
This project already has the "why" prose for nearly every command — it's
just located in a different section than the command itself. Concrete
mapping (existing source section → new usage sub-heading):
| New `### ` sub-heading | Command | Source prose already written |
|---|---|---|
| Route without spending anything | `POST /route` | API Endpoints table: "no provider call, no cost" |
| Skip the classifier when you already know the shape | `/route` with overrides | "Input to `/route` and `/dispatch` can include... overrides — these skip the classifier" |
| Actually dispatch and log energy | `POST /dispatch` | API Endpoints table |
| Point any OpenAI-compatible client at it | `/v1/chat/completions`, `/v1/models` | "Pointing a Coding Agent at It" |
| Route overnight/batch work through flex rows | `latency_tolerance: batch` | "auto:batch admits flex rows for async work" |
| Ask an image question | image_url request | "Local Vision Fallback" |
| Force JSON output | `response_format` | Weighted Scoring, hard filter #6 |
| Watch it live | `python tui.py`, `/metrics`, `/events/decisions` | "Monitoring" section, mostly verbatim |
| Probe routing without spending | `router_cli.py` | "Monitoring" section |
This is reorganization, not new writing: every cell in the right column
already exists in the current README. The work is moving each explanation
next to the command it explains, and adding a one-line "why" lead-in where
the existing text is purely descriptive rather than motivating.
### §4. `## Installation`
Two named sub-sections, matching what's actually true:
- **Local (`venv`)** — the existing "Setup" code block, unchanged.
- **As a systemd service** — the existing "Scheduled Jobs (systemd)" table
and its install pointer to `deploy/README.md`.
Do not add a third method. The reference's breadth (6 install paths) exists
because that project targets a general audience installing a CLI tool from
multiple ecosystems; this one has an owner, a GPU, and a fixed deployment
shape.
### §5. `## Requirements`
Pull the existing "Setup" opening sentence — "a Neuralwatt API key, Python
3.10+ (suite verified on 3.10 and 3.14), and an Ollama reachable from
wherever this runs with a classifier model pulled" — into its own short
bulleted section, ahead of Installation, matching the reference's
`requirements`-before-`installation` ordering.
### §6. Table of Contents
Auto-derivable from the final heading structure once the above moves are
made. Every existing `##`/`###` heading gets an entry; nest sub-headings
(Usage's per-command sections, Installation's two methods) the way the
reference nests its own.
## What must NOT change
This is a restructuring of entry points and navigation, not a rewrite of
substance. Everything below stays exactly as it is, moved but not
rewritten:
- The architecture diagram, the module table, the full schema documentation
(`models`/`proficiency`/`energy_observations`/`verifications`/
`route_decisions`), the weighted-scoring mechanism, the classifier
reliability notes, and Known Limitations & Open Items — none of this has
a reference-README equivalent because `supabase-plus` doesn't carry
this much operational depth. It stays as reference material past the new
Usage/Installation front matter, in its current form.
- No new measurements, dates, or claims. Every fact placed into a new
section must already exist verbatim (or near-verbatim, for reflow)
somewhere in the current `README.md`.
- No jokes or voice imported from the reference. "Had buckets locally once,
never found them in prod" works for a Supabase CLI's audience; this
project's own established register — measured numbers, dated
observations, named caveats — is what every other document in this repo
already uses, and the README should not be the one place that departs
from it.
## Recommendation
Build it. The highest-value pieces (a Table of Contents for a 1039-line
document that currently has none, and moving existing "why" prose next to
the commands it explains) require no new facts and no voice risk — they're
pure reorganization. The two sections that need a real answer (License,
Repo & Contributions) should get one from you before opencode touches them;
absent that, the plan's default is to leave them out rather than invent
them.