# Finishline Supervisor

A repo-local Finishline card: one JSON file and a dependency-free CLI that reports **DONE / WAIT / ANDON** from a task checklist, Git changes, and fresh acceptance checks. No model calls, agent changes, server, or package install.

Inspired by [anthropics/claude-code#79948](https://github.com/anthropics/claude-code/issues/79948), closed as not planned: agents need to finish the assigned task and show evidence. This is a small evidence wrapper, not the native enforcement boundary requested upstream.

## Install

Requires Python 3.9+, Git, and a POSIX host (macOS/Linux). Copy `finishline.py` anywhere you keep tools, or use it from this checkout. No dependencies. Run inside the target Git repository, which needs at least one commit. Commands always run from the repository root, even when invoked in a subdirectory.

```sh
# From the notplanned checkout:
python3 ventures/finishline-supervisor/demo.py
python3 -m unittest discover -s ventures/finishline-supervisor -p 'test_*.py' -v
```

For another repository, copy the script to a trusted location and invoke `python3 /path/to/finishline.py` there.

## Usage

Write `task.md` with concrete acceptance items:

```markdown
- [ ] Build a greeting CLI
- [ ] Verify its exact output
- [ ] Document usage
```

Initialize before work starts; explicitly allow files or directories relative to the repo root. Directory scope includes descendants, not similarly named siblings. Acceptance checks are JSON argv arrays, never shell strings:

```sh
python3 /path/to/finishline.py init \
  --allow task.md --allow app.py --allow README.md \
  --check '["python3","-c","import subprocess; assert subprocess.check_output([\"python3\",\"app.py\"], text=True).strip() == \"finish line\""]'

# Inspect the card and its command argv before running checks.
python3 /path/to/finishline.py check
python3 /path/to/finishline.py check --run-checks
```

Repeat `--check` for more checks (up to 20). `--timeout 30` sets seconds per check (1–300). `--card another.json` precedes `init` or `check` and selects a new contract. Existing cards are never overwritten by `init`. If the task definition or scope changes, explicitly create a new reviewed card; a checkbox toggle is normal progress.

Each check writes the latest evidence into `finishline.json`, retaining at most 20 runs. The card records the base commit, pinned task hashes, scope, command argv, timestamp, current HEAD, task line links, changed paths, and exit codes. Writes use atomic replacement. Put the card in Git if you want a portable handoff; only that exact card is exempt from the scope check. Prior passing runs never substitute for fresh checks.

| Signal / exit | Meaning |
| --- | --- |
| DONE / 0 | A nonempty checklist is complete, task definition matches, changes fit scope, every acceptance check just passed, and checks did not change observed repository evidence. |
| WAIT / 1 | Checklist incomplete/missing, or checks have not been explicitly executed. |
| ANDON / 2 | Task/scope drift, failed/timed-out/unstartable check, evidence mutation, or invalid/unavailable input. Review the reason and repair the task or command. |

ANDON takes priority over WAIT. Checks stop at the first failure. Output is JSON; init prints a short confirmation. Errors fail closed and do not echo exception contents.

## Recorded dogfood

`demo.py` creates a disposable Git repository and runs the CLI three separate times on the three-step greeting task. It asserts the signals, then removes only its own temporary repository:

1. Build `app.py`, leaving verification and documentation pending: **WAIT**.
2. Write usage documentation; the actual output is still `almost`, so the acceptance check fails: **ANDON**.
3. Fix output to `finish line`, verify it, complete the checklist: **DONE**.

[Recorded terminal output](demo.txt) and [full run evidence](demo-evidence.json) were generated by that runnable demo. Commit IDs/timestamps will differ when rerun. The landing page repeats the recorded output.

## Limits and trust

- This observes a repository; it does not orchestrate agents, merge, deploy, call models, edit their settings, or enforce a native permission boundary. An agent with write access can edit this script, the card, or the checks. Keep trusted contracts/checks outside that agent's authority if you need enforcement.
- `--run-checks` executes arbitrary trusted local programs with your permissions and environment. There is no sandbox, network restriction, or rollback. Review them first. The timeout kills their POSIX process group; a process that deliberately detaches can escape it. Checks should be read-only; evidence mutations trigger ANDON, but are not reverted.
- Git scope compares current tracked content to the pinned base and includes staged/untracked paths. It detects committed changes and renames. It excludes Git-ignored files, reverted changes, files outside the repo, and the selected card. This is current-state evidence, not a complete action audit. Large repositories cost time to hash.
- DONE proves only your checklist and checks at that instant. Weak tests can pass broken work. External state/deployment needs an explicit acceptance check; uncommitted work may be DONE. Nothing is automatically published by the tool.
- Child stdout/stderr are discarded, not saved or printed. Re-run a failed command directly to debug. Do not put secrets in task text, filenames, or argv: those values are evidence/card content. No log uploads or telemetry.
- One writer per card; atomic writes prevent partial JSON, but concurrent runs are unsupported. Interrupted checks leave the previous card intact. Run again for fresh evidence.
- Verified with all 14 tests and the three-run demo on the local Mac/Python host and in the existing `teahub-linux-runner:latest` Colima container, with network disabled and a read-only root filesystem. No claim that the CLI was run on Fly or Boring.
