diff --git a/.pi/memory-vault/packs/paperclip-harness/20-context/paperclip-harness.md b/.pi/memory-vault/packs/paperclip-harness/20-context/paperclip-harness.md index 40100b9..dc1a30b 100644 --- a/.pi/memory-vault/packs/paperclip-harness/20-context/paperclip-harness.md +++ b/.pi/memory-vault/packs/paperclip-harness/20-context/paperclip-harness.md @@ -524,3 +524,91 @@ Say go on 1 and I will run the project-docs pass before anything else. - session: [[packs/paperclip-harness/80-sessions/paperclip-harness-headroom-integration-machine-drift-cancel-|paperclip-harness: headroom integration, machine drift, cancel feature, office workflow]] - session: [[packs/paperclip-harness/80-sessions/rich-discovery-itself-2026-11-11-08-00-32|Rich discovery: itself 2026-11-11 08:00:32]] - context: [[packs/paperclip-harness/20-context/tmp|itself]] + + +--- + +## Update (2026-11-11 08:20:35) + +## Rich discovery update (2026-11-11 08:20:35) + +You were right to push back on Headroom, and I had the reason wrong. Here is what the tests actually show. + +## Headroom: corrected, with evidence + +``` +router POST /v1/chat/completions deepseek/deepseek-v4-flash → 200, SSE, "ok" in 1.1 s +headroom POST /v1/chat/completions deepseek/deepseek-v4-flash → 502 {"code":"proxy_error"} +``` + +`docker logs headroom` shows LiteLLM repeating *"Provider List: https://docs.litellm.ai/docs/providers"*. Headroom runs from `ghcr.io/chopratejas/headroom:latest` and is built on **LiteLLM**, which does not recognise this router's model ids (`deepseek/deepseek-v4-flash`, `auto/best-fast`), so it never makes the call. The same request to the router succeeds, so key, model and request shape are all fine. + +So it is **not** blocked by Anthropic and **not** by a key. It is blocked by LiteLLM not knowing your router's models. To use it as a provider, headroom's own model list must define them, for example `openai/deepseek-v4-flash` with `api_base: http://192.168.20.13:20129/v1` and your key. That is a change inside that container, not in our software. My earlier "needs an Anthropic credential" was wrong, and the docs are corrected. + +## headroom-ai installed, and tested + +Installed for Pi on **`.13`, `.27` and `.51`**, and the library resolves and calls the service: + +``` +tokensBefore: 2809 tokensAfter: 2809 message length 12800 of 12800 +``` + +No saving there because headroom protects a single long user message — the tool works, the test case was just one it deliberately leaves alone. So `compress_for_agent` can now load; giving it to one agent is `space` in `Agents>agents` → extensions. + +## Machines + +| | `.13` | `.27` | `.51` | +|---|---|---|---| +| Go | 1.26.5 | 1.26.2 | **added to config, needs a rebuild** | +| headroom-ai for Pi | installed | installed | installed | +| Nerd Fonts | 384 | 98 | 98 | +| Pi | 0.82.1 | 0.82.1 | 0.87.1 | + +On `.51` I added `go gopls` to `/etc/nixos/hosts/sam-thinkpad/configuration.nix` (backup at `.bak-go`), and `nix build --dry-run` evaluates cleanly. You rebuild with: + +``` +sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad +``` + +`.13` and `.27` are behind `.51` on Pi (0.82.1 vs 0.87.1). That is a flake bump, and I would do it with you rather than alone. + +## Documentation: first piece done + +`docs/architecture.mmd` and `docs/diagrams/architecture.png` — one diagram showing the person, the eight TUIOS panes, the `bin/` commands, Paperclip with its database and Pi agents, and where the work physically happens (worktrees, Pi sessions, skills, git). Linked from the README top. Committed as `28993d0`. + +The project-docs skill prescribes five layers, and I need one answer from you before writing into them: + +1. **Gitea** — this repo has no remote. Should I create a Gitea repo and push? +2. **Obsidian** — a note in `010 inbox` on `.27` (the skill says never to choose its folder; `obsidian-sorter` proposes and you approve). +3. **Mermaid + Archify** — the diagram is written and rendered; publishing the interactive map to `maps.lab.audasmedia.com.au/paperclip-harness/` is the remaining step. +4. **Vikunja** — a board for human task tracking, or the JSON in `docs/`. +5. **Outline** — the AI-context collection (`00-index`, `01-system-overview`, `02-config-and-env`, `03-code-map`, `04-agent-runbook`). + +Say which of 1, 2, 4, 5 you want (3 is half done), and I will write them in that order. + +## Source paths observed + +- `nix/store/kh6c296264jngs70d8ibqk7zglyvd533-user-units.drv` +- `nix/store/qv508bjxrbsnn6hj8lvrlb38x3j631lx-etc.drv` +- `nix/store/v8rgpfj7ighpjbjmz184djg11m20c7bm-activate.drv` +- `nix/store/jarpr30smi73c6wwjlrigd98dmhj7vnl-nixos-system-sam-thinkpad-26.11.20260926.e158d9e.drv` +- `home/sam/.pi/agent/skills/project-docs--6f4714e4e7/SKILL.md` +- `home/sam/.agents/skills/project-docs` +- `home/sam/.agents/skills/project-docs/SKILL.md` +- `etc/profiles/per-user/sam/bin/mmdc` +- `docs/diagrams/architecture.png` +- `v1/chat/completions` +- `docs.litellm.ai/docs/providers` +- `ghcr.io/chopratejas/headroom` +- `etc/nixos/hosts/sam-thinkpad/configuration.nix` + +## Evidence + +- Confidence: 84% +- Reason: Update component/repository context with detailed discovered structure and configuration + +## Related learned memories + +- session: [[packs/paperclip-harness/80-sessions/rich-discovery-has-2026-11-11-08-20-35|Rich discovery: has 2026-11-11 08:20:35]] +- context: [[packs/paperclip-harness/20-context/paperclip-harness|has]] +- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|has repository structure and configuration patterns]] diff --git a/.pi/memory-vault/packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns.md b/.pi/memory-vault/packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns.md index fa2ca81..dd36f10 100644 --- a/.pi/memory-vault/packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns.md +++ b/.pi/memory-vault/packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns.md @@ -3533,3 +3533,91 @@ Say go on 1 and I will run the project-docs pass before anything else. - session: [[packs/paperclip-harness/80-sessions/paperclip-harness-headroom-integration-machine-drift-cancel-|paperclip-harness: headroom integration, machine drift, cancel feature, office workflow]] - session: [[packs/paperclip-harness/80-sessions/rich-discovery-itself-2026-11-11-08-00-32|Rich discovery: itself 2026-11-11 08:00:32]] - context: [[packs/paperclip-harness/20-context/tmp|itself]] + + +--- + +## Update (2026-11-11 08:20:35) + +## Structural/configuration observations (2026-11-11 08:20:35) + +You were right to push back on Headroom, and I had the reason wrong. Here is what the tests actually show. + +## Headroom: corrected, with evidence + +``` +router POST /v1/chat/completions deepseek/deepseek-v4-flash → 200, SSE, "ok" in 1.1 s +headroom POST /v1/chat/completions deepseek/deepseek-v4-flash → 502 {"code":"proxy_error"} +``` + +`docker logs headroom` shows LiteLLM repeating *"Provider List: https://docs.litellm.ai/docs/providers"*. Headroom runs from `ghcr.io/chopratejas/headroom:latest` and is built on **LiteLLM**, which does not recognise this router's model ids (`deepseek/deepseek-v4-flash`, `auto/best-fast`), so it never makes the call. The same request to the router succeeds, so key, model and request shape are all fine. + +So it is **not** blocked by Anthropic and **not** by a key. It is blocked by LiteLLM not knowing your router's models. To use it as a provider, headroom's own model list must define them, for example `openai/deepseek-v4-flash` with `api_base: http://192.168.20.13:20129/v1` and your key. That is a change inside that container, not in our software. My earlier "needs an Anthropic credential" was wrong, and the docs are corrected. + +## headroom-ai installed, and tested + +Installed for Pi on **`.13`, `.27` and `.51`**, and the library resolves and calls the service: + +``` +tokensBefore: 2809 tokensAfter: 2809 message length 12800 of 12800 +``` + +No saving there because headroom protects a single long user message — the tool works, the test case was just one it deliberately leaves alone. So `compress_for_agent` can now load; giving it to one agent is `space` in `Agents>agents` → extensions. + +## Machines + +| | `.13` | `.27` | `.51` | +|---|---|---|---| +| Go | 1.26.5 | 1.26.2 | **added to config, needs a rebuild** | +| headroom-ai for Pi | installed | installed | installed | +| Nerd Fonts | 384 | 98 | 98 | +| Pi | 0.82.1 | 0.82.1 | 0.87.1 | + +On `.51` I added `go gopls` to `/etc/nixos/hosts/sam-thinkpad/configuration.nix` (backup at `.bak-go`), and `nix build --dry-run` evaluates cleanly. You rebuild with: + +``` +sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad +``` + +`.13` and `.27` are behind `.51` on Pi (0.82.1 vs 0.87.1). That is a flake bump, and I would do it with you rather than alone. + +## Documentation: first piece done + +`docs/architecture.mmd` and `docs/diagrams/architecture.png` — one diagram showing the person, the eight TUIOS panes, the `bin/` commands, Paperclip with its database and Pi agents, and where the work physically happens (worktrees, Pi sessions, skills, git). Linked from the README top. Committed as `28993d0`. + +The project-docs skill prescribes five layers, and I need one answer from you before writing into them: + +1. **Gitea** — this repo has no remote. Should I create a Gitea repo and push? +2. **Obsidian** — a note in `010 inbox` on `.27` (the skill says never to choose its folder; `obsidian-sorter` proposes and you approve). +3. **Mermaid + Archify** — the diagram is written and rendered; publishing the interactive map to `maps.lab.audasmedia.com.au/paperclip-harness/` is the remaining step. +4. **Vikunja** — a board for human task tracking, or the JSON in `docs/`. +5. **Outline** — the AI-context collection (`00-index`, `01-system-overview`, `02-config-and-env`, `03-code-map`, `04-agent-runbook`). + +Say which of 1, 2, 4, 5 you want (3 is half done), and I will write them in that order. + +## Source paths observed + +- `nix/store/kh6c296264jngs70d8ibqk7zglyvd533-user-units.drv` +- `nix/store/qv508bjxrbsnn6hj8lvrlb38x3j631lx-etc.drv` +- `nix/store/v8rgpfj7ighpjbjmz184djg11m20c7bm-activate.drv` +- `nix/store/jarpr30smi73c6wwjlrigd98dmhj7vnl-nixos-system-sam-thinkpad-26.11.20260926.e158d9e.drv` +- `home/sam/.pi/agent/skills/project-docs--6f4714e4e7/SKILL.md` +- `home/sam/.agents/skills/project-docs` +- `home/sam/.agents/skills/project-docs/SKILL.md` +- `etc/profiles/per-user/sam/bin/mmdc` +- `docs/diagrams/architecture.png` +- `v1/chat/completions` +- `docs.litellm.ai/docs/providers` +- `ghcr.io/chopratejas/headroom` +- `etc/nixos/hosts/sam-thinkpad/configuration.nix` + +## Evidence + +- Confidence: 82% +- Reason: Captured factual repo structure/configuration patterns from rich discovery + +## Related learned memories + +- session: [[packs/paperclip-harness/80-sessions/rich-discovery-has-2026-11-11-08-20-35|Rich discovery: has 2026-11-11 08:20:35]] +- context: [[packs/paperclip-harness/20-context/paperclip-harness|has]] +- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|has repository structure and configuration patterns]] diff --git a/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-has-2026-11-11-08-20-35.md b/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-has-2026-11-11-08-20-35.md new file mode 100644 index 0000000..e261e11 --- /dev/null +++ b/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-has-2026-11-11-08-20-35.md @@ -0,0 +1,107 @@ +--- +type: session +id: session.paperclip-harness.rich-discovery-has-2026-11-11-08-20-35 +title: Rich discovery: has 2026-11-11 08:20:35 +status: active +source_of_truth: false +freshness: current +last_reviewed: 2026-11-11 +tags: + - pack/paperclip-harness + - agent-memory/session + - autolearn + - rich-discovery + - repo/has +--- + +# Rich discovery: has 2026-11-11 08:20:35 + +Sanitized rich discovery snapshot captured automatically from the completed turn. + + +## Source paths observed + +- `nix/store/kh6c296264jngs70d8ibqk7zglyvd533-user-units.drv` +- `nix/store/qv508bjxrbsnn6hj8lvrlb38x3j631lx-etc.drv` +- `nix/store/v8rgpfj7ighpjbjmz184djg11m20c7bm-activate.drv` +- `nix/store/jarpr30smi73c6wwjlrigd98dmhj7vnl-nixos-system-sam-thinkpad-26.11.20260926.e158d9e.drv` +- `home/sam/.pi/agent/skills/project-docs--6f4714e4e7/SKILL.md` +- `home/sam/.agents/skills/project-docs` +- `home/sam/.agents/skills/project-docs/SKILL.md` +- `etc/profiles/per-user/sam/bin/mmdc` +- `docs/diagrams/architecture.png` +- `v1/chat/completions` +- `docs.litellm.ai/docs/providers` +- `ghcr.io/chopratejas/headroom` +- `etc/nixos/hosts/sam-thinkpad/configuration.nix` + +## Final answer snapshot + +You were right to push back on Headroom, and I had the reason wrong. Here is what the tests actually show. + +## Headroom: corrected, with evidence + +``` +router POST /v1/chat/completions deepseek/deepseek-v4-flash → 200, SSE, "ok" in 1.1 s +headroom POST /v1/chat/completions deepseek/deepseek-v4-flash → 502 {"code":"proxy_error"} +``` + +`docker logs headroom` shows LiteLLM repeating *"Provider List: https://docs.litellm.ai/docs/providers"*. Headroom runs from `ghcr.io/chopratejas/headroom:latest` and is built on **LiteLLM**, which does not recognise this router's model ids (`deepseek/deepseek-v4-flash`, `auto/best-fast`), so it never makes the call. The same request to the router succeeds, so key, model and request shape are all fine. + +So it is **not** blocked by Anthropic and **not** by a key. It is blocked by LiteLLM not knowing your router's models. To use it as a provider, headroom's own model list must define them, for example `openai/deepseek-v4-flash` with `api_base: http://192.168.20.13:20129/v1` and your key. That is a change inside that container, not in our software. My earlier "needs an Anthropic credential" was wrong, and the docs are corrected. + +## headroom-ai installed, and tested + +Installed for Pi on **`.13`, `.27` and `.51`**, and the library resolves and calls the service: + +``` +tokensBefore: 2809 tokensAfter: 2809 message length 12800 of 12800 +``` + +No saving there because headroom protects a single long user message — the tool works, the test case was just one it deliberately leaves alone. So `compress_for_agent` can now load; giving it to one agent is `space` in `Agents>agents` → extensions. + +## Machines + +| | `.13` | `.27` | `.51` | +|---|---|---|---| +| Go | 1.26.5 | 1.26.2 | **added to config, needs a rebuild** | +| headroom-ai for Pi | installed | installed | installed | +| Nerd Fonts | 384 | 98 | 98 | +| Pi | 0.82.1 | 0.82.1 | 0.87.1 | + +On `.51` I added `go gopls` to `/etc/nixos/hosts/sam-thinkpad/configuration.nix` (backup at `.bak-go`), and `nix build --dry-run` evaluates cleanly. You rebuild with: + +``` +sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad +``` + +`.13` and `.27` are behind `.51` on Pi (0.82.1 vs 0.87.1). That is a flake bump, and I would do it with you rather than alone. + +## Documentation: first piece done + +`docs/architecture.mmd` and `docs/diagrams/architecture.png` — one diagram showing the person, the eight TUIOS panes, the `bin/` commands, Paperclip with its database and Pi agents, and where the work physically happens (worktrees, Pi sessions, skills, git). Linked from the README top. Committed as `28993d0`. + +The project-docs skill prescribes five layers, and I need one answer from you before writing into them: + +1. **Gitea** — this repo has no remote. Should I create a Gitea repo and push? +2. **Obsidian** — a note in `010 inbox` on `.27` (the skill says never to choose its folder; `obsidian-sorter` proposes and you approve). +3. **Mermaid + Archify** — the diagram is written and rendered; publishing the interactive map to `maps.lab.audasmedia.com.au/paperclip-harness/` is the remaining step. +4. **Vikunja** — a board for human task tracking, or the JSON in `docs/`. +5. **Outline** — the AI-context collection (`00-index`, `01-system-overview`, `02-config-and-env`, `03-code-map`, `04-agent-runbook`). + +Say which of 1, 2, 4, 5 you want (3 is half done), and I will write them in that order. + +## Evidence + +- Confidence: 86% +- Reason: Preserve full sanitized discovery detail from a rich investigation turn + +## Related + +- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]] + +## Related learned memories + +- session: [[packs/paperclip-harness/80-sessions/rich-discovery-has-2026-11-11-08-20-35|Rich discovery: has 2026-11-11 08:20:35]] +- context: [[packs/paperclip-harness/20-context/paperclip-harness|has]] +- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|has repository structure and configuration patterns]] diff --git a/README.md b/README.md index 6ddc5f7..3a76e22 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,117 @@ -# Paperclip harness — start here +# Paperclip Harness -This is a new project. Nothing here runs yet. It exists so the third attempt starts from -a clean place, with the history of the first two attempts attached. - -If you are an agent: read `AGENTS.md` first, then `HANDOVER.md`, then `docs/PLAN.md`. - -If you are the person: read these in order: - -1. `HANDOVER.md` — what we tried before, what worked, what failed, and why this is different. -2. `docs/PLAN.md` — the plan: the four screens, the milestones, what is Paperclip's job and what is ours. -3. `docs/PAPERCLIP-API-NOTES.md` — what we measured against your running Paperclip, with the endpoint and the response. -4. `CHECKLIST.md` — the exact steps for the next session, in order, with boxes to tick. -5. `docs/TUIOS-RUNBOOK.md` — TUIOS, not tmux: the three machines, starting a session, driving panes. -6. `docs/OPERATING-RULES.md` — the nine rules, including how a task is judged finished. -7. `docs/DOCMAP.md` — which document is authoritative for what. One home per document. -6. `docs/ENVIRONMENT-FACTS.md` — the ids, the installed tools, and the one step that is - still unproven. +**A terminal control room for an AI coding factory.** Paperclip runs the work — tasks, +blockers, agents, runs, cost and a git worktree per task. This is the surface a person uses to +see it, direct it, and decide what lands. ![architecture](docs/diagrams/architecture.png) -## The one-line version +Eight workspaces in TUIOS, one Go program in each, and a small set of commands for the parts +that should not be a keystroke (merge, review, adopt a folder). No web UI, no database of our +own, no second copy of any fact. -Paperclip already owns tasks, blockers, comments, approvals, runs, cost and git -worktrees. We are building one small Go terminal program with four screens on top of it. -Nothing else. +--- -## What you need installed (all present on .13 today) +## What it does -- Paperclip server running locally on `http://127.0.0.1:3100` (it is; 685 endpoints). -- `PAPERCLIP_BOARD_KEY` in the environment — the **user** key. The terminal program uses - this one. An agent key cannot write outside a heartbeat run. -- Go toolchain — **now installed** (`go1.26.5`, from `nix profile`). The NixOS config change - that makes it permanent is staged in `/etc/nixos/configuration.nix` and needs one - `sudo nixos-rebuild switch`. See `docs/ENVIRONMENT-FACTS.md`. -- Pi, which is already the worker adapter on your Paperclip agent. +| Workspace | What it answers | What it shows | +|---|---|---| +| **Board** | what is the state of the work | tasks by group, the chosen task with its blockers and check, what needs a person | +| **Work** | what is happening and what changed | run timeline, the diff from the task's own worktree, review verdicts, the run's log, and a merge that asks before it acts | +| **Agents** | who is working, on what, for how much | agent roster with spend and budget, every run in the company, the run log, editable role/model/budget/heartbeat, per-agent skills and extensions | +| **Reply** | what was said and what I say back | the thread and a reply box that can also set the task's status | +| **New task** | what am I asking for | a five-field form, what each field means, and exactly the text the agent will receive | +| **Project** | which folder, which machine, what it costs | a dashboard (agents, tasks, money, run activity), costs as bars, the project's settings, adopted projects | +| **Repair** | is the layout sound | three-state health checks, the live TUIOS layout, the rebuild log, session cleanup | +| **Shell** | where am I | a prompt in the project folder, above a box naming every path that matters | -## Running the terminal program +Keys follow TUIOS's rules: `Tab` moves between panels, `↑↓` or `jk` move, `(` `)` switch tabs, +`R` rebuilds the layout, `?` lists the keys for the panel you are in. A bare `Esc` closes a box +and never quits. -```bash -bin/layout # open every screen as a TUIOS pane -bin/screen reply AUD-162 # or one screen +--- -cd tui -go run . -screen tree -project spike-2026-11-10 # one screen in this terminal -go run . -screen tree -project spike-2026-11-10 -dump # the same data as plain text +## The design decisions that matter + +**One owner per fact.** Tasks, blockers, comments, approvals, runs, cost and worktrees belong to +Paperclip. The interface reads them every time and stores none of them. Two screens cannot +disagree because there is only one record. + +**One project is one folder on one machine.** That is the only thing we keep: a small file in +`/.harness/harness.toml` naming the session, the machine and the task being watched. +Everything else is Paperclip's. + +**Choosing a task is one act.** `Enter` on the board writes the choice into that file and every +other workspace follows within a second. No message bus, no second state to keep in sync. + +**A task is finished when the agent says so.** A review stage or `ocr` can refuse the change. A +project's `check.sh` is a regression check at merge time — the same job a CI pipeline does — not +the definition of done. + +**Merging is a decision, so it asks.** `m` names the branch, the base branch and the checks, and +waits for `y`. It takes a lock, rebases, runs the checks, runs the review, merges, then re-runs +the checks on the base branch and rolls back if they fail. + +**TUIOS owns the keyboard.** `h j k l z n` and `[ ] tab , . = ;` and the digits are its. The +program navigates with arrows, `jk`, `(` `)`, `Space` and `Enter`, and keeps `Esc` free. + +**Nothing hardcodes a size.** Every pane re-asks the terminal for its size on each refresh, +because a window manager can re-tile a pane without the program hearing about it. + +--- + +## Measured, not asserted + +| Claim | Measurement | +|---|---| +| An assignment wakes the agent | wake recorded 46 ms after the assignment, run started 0.1 s later, task done in 28 s | +| Cost is readable per task | `cost-summary`: 1 cent, 101,002 input tokens, 1,515 output tokens, one run | +| Blockers are real answers | `diagnostics/blockers` returns `unresolvedBlockerCount: 1` — and the task **list** never carries it, so the tree asks per task | +| Worktrees are Paperclip's | branch `AUD-160-…` at `.paperclip/worktrees/…`, cut from `main` | +| A review can refuse a merge | `ocr` found `rm -rf "$HOME/tmp"` deleting `/tmp` when `HOME` is empty; the merge was refused and the file never landed | +| A task can have several runs | `AUD-166`: `assignment`, then `automation` — Paperclip's corrective wake | +| Per-agent skills work | adding one skill changed that agent's list and no other | +| A new project can be adopted in one command | `bin/office` created the session, wrote the project file and built all eight panes | + +--- + +## Technology + +- **Go** with Bubble Tea, Lipgloss, Bubbles and BubbleZone; one binary, one program per pane. +- **TUIOS** for sessions, workspaces and panes, including the control-protocol verbs used to + create sessions and switch between them. +- **Paperclip** as the control plane: 685 API endpoints, isolated git worktrees per task, Pi as + the agent runtime. +- **ocr** for code review over the diff; **Lazygit**, **Hunk**, **Yazi**, **Neovim**, **fzf** and + a shell open as tool panes on demand instead of being rebuilt. +- **Mouse-1** for one narrow job — labelling a failed run with one of four next actions. + +--- + +## What this demonstrates + +- **Integration under real constraints**: a dozen independent systems (TUIOS, Paperclip, git + worktrees, Pi agents, ocr, skills) joined so that each keeps its own job. +- **Single-source-of-truth discipline**: no cached facts, no second task list, no guessed state — + and the API was measured until the traps were known (blockers absent from list endpoints, + cross-issue writes refused outside a run). +- **Failure-aware design**: a merge that asks, a review that can refuse, a lock so two merges + cannot overlap, a rollback when post-merge checks fail, and health checks that have three + states because "not run" is not "pass". +- **Terminal interface engineering**: resize handling, a focus model, tabs, overlays that wrap + instead of clipping, and keys chosen around another program's keymap. +- **Evidence-based reporting**: every claim in the docs names the command that showed it, and the + unproven ones are marked unproven. + +--- + +## Repository + +``` +bin/ commands: office, board, merge, review, triage, project-reset +tui/ the Go program: one binary, eight screens +docs/ the plan, the measurements, the runbook, the test plan +docs/architecture.mmd the system diagram, rendered to docs/diagrams/ ``` -The screens live in the session named `paperclip-harness`, one per workspace. How that is -built and repaired is in `docs/TUIOS-RUNBOOK.md`. - -The project can be an id or its url key. Keys inside the program: arrows or Tab and -Shift-Tab move, `r` re-reads from Paperclip, `q` quits. A bare Esc is left free, because in -TUIOS it has to close a box. - -## The six workspaces - -Written the way we talk about them: **Workspace>pane**. `Board>board` means the board -program running in the Board workspace. - -| Workspace>pane | shows | keys | -|---|---|---| -| Shell>shell | a prompt in the project folder, with a box saying where the project's files, worktrees and Pi sessions are | — | -| Board>board | tasks by group · the chosen task · needs you | ↑↓ j k · enter · a · u · / · t (tools) · tab | -| Work>work | runs · change · facts · review · log · merge | [ ] tab · n p (task) · o (pick task) · ↑↓ j k · enter (open a run) · m (merge, asks first) · t (tools) | -| Reply>reply | the task · the thread · the reply box | enter · s · esc | -| New task>new | the form · what a task needs · what will be sent | tab · enter · ctrl+n | -| Project>project | overview · facts · costs · settings | [ ] tab · ↑↓ j k | -| Repair>repair | health · layout · rebuild log | [ ] tab · ↑↓ j k · R · B | -| Agents>agents | roster · runs · log · settings | [ ] tab · ↑↓ j k · enter · p P w · A | - -Choosing a task on the board and pressing Enter writes it into the project's -`.harness/harness.toml`, and every other workspace follows within a second. - -### Tool panes - -`t` in `Board>board` or `Work>work` opens a chooser: shell, Lazygit, Hunk, Yazi, Neovim, -fzf, ocr. Note that TUIOS also binds `t` in **window management mode** (toggle tiling, new -window); inside the program the pane must be in terminal mode for `t` to arrive, which is -the normal state while you are typing in it. The tool opens as a pane beside the one you are in, in the same workspace, and -`esc` closes the chooser. Quitting the tool (its own key) closes its pane. Nothing is added -to the layout, so the eight workspaces stay as they are. - -### Refresh and rebuild - -- **`r`** — read the data again in this panel. Nothing closes, nothing moves, the - layout is untouched. Use it when the numbers look stale. -- **`B`** — on the Repair screen only: add whatever panes are missing without - closing any, so it is safe to press from inside a pane. -- **`?`** — the keys for the panel you are in, as an overlay. -- **`/`** — filter the task list by identifier, title or assignee name. -- **`u`** — unblock a task whose blocker has finished but which still says blocked. -- **`R`** — rebuild everything: `bin/board --replace` closes each pane the layout - owns and builds all seven again, in order. It runs detached in its own session, - because the panel you pressed it in is one of the panes being replaced; the - output is written to `/tmp/paperclip-harness-rebuild.log`, and the Repair - workspace shows that log on its third tab. - -`R` is on every screen except the new-task form, where letters are text. - -## How an interface change is tested - -Not in a plain terminal, and not in tmux. TUIOS owns part of the keyboard and forwards -clicks relative to the pane, so the check is a real TUIOS pane read back with -`capture-pane`. The commands are in `docs/TUIOS-RUNBOOK.md`, which is the one place they -live. - -## The commands - -| command | what it does | -|---|---| -| `bin/office [--project X] [--session Y]` | adopt a folder: write `.harness/harness.toml`, build its pages | -| `bin/board [--folder DIR] [--replace]` | build or repair the pages; run twice and nothing is duplicated | -| `bin/project-reset [--dry-run] [--yes]` | close the pages, remove the worktrees and branches; keep the folder and every Paperclip record | -| `bin/merge [--check]` | rebase, verify, review with `ocr`, merge; a refusal is a decision for the person | -| `bin/review [--post]` | the same review on its own | -| `bin/screen [task or project]` | open one page by name | - -## Rules for this project - -- No interface work before a real task has run end to end. -- Paperclip owns the facts. We never keep a second copy of a task, a blocker or a cost. -- Every claim in a document names the command that showed it. -- Nothing is copied from the old project except documents. +Start with `HANDOVER.md`, then `docs/WORKSPACES.md`, then `docs/PLAN-INTERFACE.md`. diff --git a/docs/outline/00-index.md b/docs/outline/00-index.md new file mode 100644 index 0000000..700d36a --- /dev/null +++ b/docs/outline/00-index.md @@ -0,0 +1,26 @@ +# Index + +What is in this collection, and what each document is for. Written in Simplified Technical +English: short sentences, one idea each, no metaphor. + +| Document | Read it when | +|---|---| +| `01-system-overview.md` | you need to know what the system is and how the parts fit | +| `02-config-and-env.md` | you need to run it, or find a setting, a path or a key | +| `03-code-map.md` | you need to change the code and want to know which file does what | +| `04-agent-runbook.md` | an agent is picking up this project and needs the rules and the traps | + +Outside this collection: + +| File | What it is | +|---|---| +| `AGENTS.md` | the first file an agent reads | +| `HANDOVER.md` | where the project is now, and why it is shaped this way | +| `docs/PLAN-INTERFACE.md` | the plan, and the measurements behind each decision | +| `docs/WORKSPACES.md` | every workspace and pane, with its status | +| `docs/RUNS-AND-MERGE.md` | what a task, a run and a merge are | +| `docs/TEST-PLAN.md` | every step of a manual test, with the keys | +| `docs/SESSIONS.md` | TUIOS sessions, Pi conversations, cleanup | +| `docs/PAPERCLIP-API-NOTES.md` | what the API actually returned | +| `docs/ENVIRONMENT-FACTS.md` | ids, machines, toolchain, fonts | +| `docs/NEXT.md` | what is left to build, and what is unproven | diff --git a/docs/outline/01-system-overview.md b/docs/outline/01-system-overview.md new file mode 100644 index 0000000..d49f42f --- /dev/null +++ b/docs/outline/01-system-overview.md @@ -0,0 +1,45 @@ +# System overview + +## What it is + +Paperclip Harness is a terminal interface over Paperclip. Paperclip is a control plane. It keeps +tasks, blockers, comments, approvals, runs, cost and a git worktree for each task. This project +shows that work in a terminal, inside TUIOS, and adds the few actions a person needs. + +## The parts + +- **Paperclip** on `http://127.0.0.1:3100`. It owns every fact. It runs Pi agents. +- **TUIOS**. It owns sessions, workspaces, panes and part of the keyboard. +- **The Go program** in `tui/`. One binary. Each pane runs one screen. +- **Commands** in `bin/`. They do the work that should not be a keystroke: adopt a folder, build + panes, merge one task, review one task, ask Mouse-1 one question. + +## The eight workspaces + +| Workspace | Purpose | +|---|---| +| Shell | a prompt in the project folder, with the paths printed above it | +| Board | the state of the work, and what needs a person | +| Work | runs, diff, facts, review, run log, merge | +| Agents | who is working, on what, for how much; and their settings, skills, extensions | +| Reply | the task thread and a reply box | +| New task | the form that creates a task | +| Project | dashboard, costs, settings, adopted projects | +| Repair | health checks, live layout, rebuild log, session cleanup | + +## The data flow + +1. A person creates a task in `New task`, or one already exists in Paperclip. +2. The person assigns it on `Board`. Paperclip wakes the agent. +3. The agent works in its own git worktree, on its own branch. +4. The agent comments and sets the status. +5. The person reads the run log, the diff and the review. +6. The person merges. `bin/merge` rebases, checks, reviews, merges, and checks again. + +## What the project stores + +One file per project: `/.harness/harness.toml`. It holds the session name, the machine, +the Paperclip project id, and the task being watched. It holds no task data. + +A registry at `~/.config/paperclip-harness/projects.toml` lists adopted projects, so a person can +see which folder lives where. diff --git a/docs/outline/02-config-and-env.md b/docs/outline/02-config-and-env.md new file mode 100644 index 0000000..5adc95c --- /dev/null +++ b/docs/outline/02-config-and-env.md @@ -0,0 +1,58 @@ +# Configuration and environment + +## Required + +| Name | Where | What it is | +|---|---|---| +| `PAPERCLIP_BOARD_KEY` | `~/.config/environment.d/10-secrets.conf` | the person's key. All writes use it. | +| `PAPERCLIP_API_KEY` | the same file | the agent key. Use it for reads only. Writes are refused outside a run. | +| `MOUSE_API_KEY` | the same file | the Mouse-1 API key | +| `GITEA_TOKEN` | the same file | used once, to create and push the repository | + +Never print a key. Never commit a key. Never put a key in a prompt. + +## The project file + +`/.harness/harness.toml`: + +```toml +session = "paperclip-harness" +watching = "AUD-171" + +[paperclip] +company = "d4921013-…" +project = "17adbb47-…" + +[machine] +host = "nixos-desktop" +folder = "/tmp/pc-sandbox-2026-11-10" +``` + +`bin/office ` writes it and also writes `.harness/check.sh` and `.harness/NOTES.md` when +they are missing. It never overwrites an existing file. + +## Paths that matter + +| What | Where | +|---|---| +| task worktrees | `/.paperclip/worktrees/` | +| Pi conversations | `~/.pi/paperclips/-.jsonl` | +| Pi skills (installed by Paperclip) | `~/.pi/agent/skills/` | +| the person's skills | `~/.agents/skills/` | +| Paperclip data | `~/.paperclip/instances/default/` | +| merge log | `/tmp/paperclip-harness-merge.log` | +| rebuild log | `/tmp/paperclip-harness-rebuild.log` | + +## Instance settings that change behaviour + +- `enableIsolatedWorkspaces` and `enableWorktreeRunExecution` must be true, or no task gets a + worktree. `GET /api/instance/settings/experimental` shows them. +- `enableIsolatedWorkspacesByDefault` is left off. Only projects that ask for a worktree get one. + +## Machines, measured 2026-11-11 + +| | `.13` | `.27` | `.51` | +|---|---|---|---| +| Go | 1.26.5 | 1.26.2 | installed in config, needs a rebuild | +| Pi | 0.82.1 | 0.82.1 | 0.87.1 | +| TUIOS | 0.12.1 | 0.12.1 | 0.12.1 | diff --git a/docs/outline/03-code-map.md b/docs/outline/03-code-map.md new file mode 100644 index 0000000..0159438 --- /dev/null +++ b/docs/outline/03-code-map.md @@ -0,0 +1,46 @@ +# Code map + +## The binary + +`tui/` builds one binary. `main.go` reads the flags and starts one screen. + +| File | Does | +|---|---| +| `main.go` | flags, palette, which screen to start | +| `model.go` | the task tree screen and the shared row loader | +| `board.go` | `Board`: tasks, chosen task, needs you | +| `work.go` | `Work`: runs, change, facts, review, log, merge | +| `agents.go` | `Agents`: roster, runs, log, settings, skills, extensions | +| `reply.go` | `Reply`: thread and reply box | +| `newtask.go` | `New task`: the form, guidance, preview | +| `project.go` | `Project`: overview, facts, costs, settings, projects | +| `repair.go` | `Repair`: health, layout, log, cleanup | +| `frame.go` | the panel frame, tabs, hints, overlays, wrapping | +| `theme.go` | the palette and the icon set | +| `toolpane.go` | opening a tool as a pane, and finding the current workspace | +| `picker.go` | skills and extensions for one agent | +| `rebuild.go` | detached rebuild, merge and review, and their logs | + +`tui/paperclip/client.go` is the whole API client. It holds no state. + +## The commands + +| File | Does | +|---|---| +| `bin/office` | adopt a folder, create its session, build its panes | +| `bin/board` | build or repair the panes, by name, in order | +| `bin/merge` | rebase, check, review, merge, re-check, roll back on failure | +| `bin/review` | the review alone | +| `bin/triage` | ask Mouse-1 one four-option question | +| `bin/project-reset` | close panes, remove worktrees and branches, keep the folder | +| `bin/shell-banner` | the box printed at the top of `Shell` | +| `bin/lib/tuios.py` | sessions, workspaces, panes: claim by name, never by number | +| `bin/lib/harness.py` | API, git, ocr, and the tool-path fix | +| `bin/lib/project.py` | the project file and the registry | + +## The rules the code keeps + +- No network or git call inside an update or view function. They run in commands. +- No hardcoded sizes. The size comes from the terminal on every refresh. +- One click-zone manager, created once, wrapping the whole view. +- Every panel line is exactly the width asked for. `tui/frame_test.go` fails if it is not. diff --git a/docs/outline/04-agent-runbook.md b/docs/outline/04-agent-runbook.md new file mode 100644 index 0000000..0a0ef8b --- /dev/null +++ b/docs/outline/04-agent-runbook.md @@ -0,0 +1,45 @@ +# Agent runbook + +Read this before you change anything. + +## First + +1. Read `AGENTS.md`. +2. Read `HANDOVER.md`. +3. Run `tuios ls` and find the session called `paperclip-harness`. +4. In a pane, run `Repair>repair`. Every check must pass. If it does not, fix that first. + +## Build and restart + +```sh +cd tui && go build -o ../bin/harness . +``` + +Then press `R` in `Repair>repair`. Do not start a second copy of a panel: `bin/board` adopts the +pane that is already there. + +## Rules that are not preferences + +- Writes use `PAPERCLIP_BOARD_KEY`. The agent key is refused outside a run, and that refusal is + correct. +- Read blockers from `/api/issues/{id}/diagnostics/blockers`. The task list does not carry them. +- Read a worktree path from a single-task read. The task list does not carry it either. +- Never store a fact Paperclip owns. +- A comment on an assigned task wakes its agent. Tool verdicts hand the task back to the person + first. +- TUIOS keeps `h j k l z n` and also `[ ] Tab , . = ;` and the digits. Use arrows, `jk`, `(` `)`, + `Space`, `Enter`. Keep `Esc` free. + +## Traps, measured + +- A pane started by TUIOS has a smaller `PATH`. `bin/lib/harness.py` and `toolpane.go` add the + usual directories for that reason. +- TUIOS can re-tile a pane without the program hearing about it. Re-ask for the size. +- Closing the last pane deletes a workspace and renumbers the rest. Resolve workspaces by name. +- `switch-session` is refused when the call comes from a pane. A program cannot move the person's + client. + +## Reporting + +Say what you ran and what came back. If something is unproven, say it is unproven. A dry run is +not a test.