office --new creates the Paperclip project; the two clean tests written step by step

This commit is contained in:
Sam
2026-11-12 09:36:37 +11:00
parent d2cf643eca
commit 08a4b4e822
9 changed files with 691 additions and 1 deletions

View File

@@ -719,3 +719,78 @@ Choosing a task here writes the same choice the Board writes, so `Reply>reply` a
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|navigate tasks and runs inside Work>work and merge safely (paperclip-harness)]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-home-2026-11-11-02-17-44|Rich discovery: home 2026-11-11 02:17:44]]
- context: [[packs/paperclip-harness/20-context/home|home]]
---
## Update (2026-11-11 21:45:49)
## Rich discovery update (2026-11-11 21:45:49)
## Headroom: what the failure actually is, and what you do
I tested three configurations on a throwaway container on a spare port, so the running one was untouched:
| Configuration | Result |
|---|---|
| default image (`HEADROOM_BACKEND` unset → `anthropic`) + your router key | `502 proxy_error` |
| plus `OPENAI_API_KEY` | `openai/deepseek-v4-flash` → `404 No active credentials for provider: openai`; `deepseek/deepseek-v4-flash` → `502` |
| plus `HEADROOM_BACKEND=openai` | `502 proxy_error` |
Two things that answer your questions directly:
- **`openai/` is not OpenAI's model.** In this stack the prefix names the *protocol* to speak — "use the OpenAI-compatible client" — and the rest is the model name your router uses. So `openai/deepseek-v4-flash` means "call the router with its `deepseek-v4-flash` model". That is why I wrote it that way, and it was a guess about headroom's routing, not a fact.
- **The `404 … provider: openai` came from your router, not headroom.** The router read `openai/` as a provider name and had no key for it. So that path was never going to work with our router's ids.
`/stats` on the test container reported `api_requests: 0` for all of those attempts — headroom refused or failed before forwarding. That is inside headroom's deployment, and it needs someone with its logs open; nothing in our software can fix it.
**What does work, re-checked:** `POST /v1/compress` answers 200 and reports tokens before and after. That is the endpoint `headroom-bridge` uses, and `headroom-ai` is now installed on `.13`, `.27` and `.51`.
**So: use Path A, not both.** `Agents>agents` → `)` to extensions → `space` on `headroom-bridge`. That agent, and no other, gets `compress_for_agent`. Path B is yours to fix in the headroom container if you still want automatic compression; I have recorded the three tests and their exact responses so nobody repeats them.
## The rest
**Archify in the Obsidian note** — added, with the map URL, the Mermaid source path, the Outline collection and the repository link. Note is now 3,511 bytes at `010 inbox/Paperclip Harness.md` on `.27`.
**Outline — pushed.** New collection **Paperclip Harness** with five published documents:
```
/doc/00-index-o6hhlKTFXR
/doc/01-system-overview-dGpfQOk1vt
/doc/02-configuration-and-environment-redTWei0y2
/doc/03-code-map-y6KPFbBbIC
/doc/04-agent-runbook-Sd9ZznhBqo
```
**Point 4, specifically.** Two tests, both about whether a person can get from "a folder" to "a working set of panes":
1. **A brand-new project.** An empty folder, a new Paperclip project, then `bin/office /tmp/fresh-project-2026-11-11 --project fresh-project`. Expected: session created, eight panes built, `Shell>shell` in that folder. **This already passed tonight** — except the session opened at 78 columns and `Board>board` correctly said "this workspace needs 80 × 24", which is the too-small screen doing its job, not a failure. The real test is: switch to that session, press `R` to rebuild at full size, create one task, assign it, watch it run, merge it.
2. **An existing folder.** Adopt this repository: `bin/office ~/paseo/projects/paperclip-harness --project <new paperclip project>`. Expected: `.harness/` appears, nothing existing is overwritten, the panes read *this* repo's tasks. That proves adoption is safe on real code.
**Pi versions.** `.51` is 0.87.1; `.13` and `.27` are 0.82.1. You rebuilt `.51` — the Go addition there is in place (`go gopls` in `hosts/sam-thinkpad/configuration.nix`, dry-run evaluates). For Pi: on `.13` and `.27`, Pi is the Nix package `pi-coding-agent`, so aligning means bumping that package in each machine's flake and rebuilding. Do you want me to prepare those two bumps (I can edit both flakes and run the dry-run evaluations), or leave `.13`/`.27` on 0.82.1 since they work?
Committed as `d2cf643` and pushed to Gitea.
## Source paths observed
- `nix/store/rgnappqqc5vbq60gza5fflyk84sylwl6-python3-3.14.6/lib/python3.14/json/__init__.py`
- `nix/store/rgnappqqc5vbq60gza5fflyk84sylwl6-python3-3.14.6/lib/python3.14/json/decoder.py`
- `outline.lab.audasmedia.com.au/api/collections.list`
- `home/sam/obsidian/010`
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
- `paseo/projects/paperclip-harness`
- `hosts/sam-thinkpad/configuration.nix`
## Evidence
- Confidence: 84%
- Reason: Update component/repository context with detailed discovered structure and configuration
## Related learned memories <!-- same-turn-2026-11-11 21:45:49 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip Harness acceptance test plan (Point 4) and Pi/Go host versions]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|publish Paperclip Harness docs to Outline and update Obsidian note]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip Harness: use Path A (headroom-bridge agent extension), not automatic headroom compression]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Paperclip Harness: docs published to Outline, Obsidian note updated, repo pushed]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-link-2026-11-11-21-45-49|Rich discovery: link. 2026-11-11 21:45:49]]
- context: [[packs/paperclip-harness/20-context/home|link.]]

View File

@@ -943,3 +943,39 @@ Vikunja integration ignored per user.
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Headroom integration paths on Pi]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Delivered paperclip-harness documentation to Gitea, Obsidian, and docs/outline]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-docs-and-gitea-publication|paperclip-harness docs and Gitea publication]]
---
## Update (2026-11-11 21:45:49)
Completed turn delivered three artifacts for the Paperclip Harness project:
1. **Outline collection created** — "Paperclip Harness" (collection id 4570974e-fb8f-4a87-8fcd-937729a40ed2) with five published docs on host http://outline.lab.audasmedia.com.au:
- /doc/00-index-o6hhlKTFXR
- /doc/01-system-overview-dGpfQOk1vt
- /doc/02-configuration-and-environment-redTWei0y2
- /doc/03-code-map-y6KPFbBbIC
- /doc/04-agent-runbook-Sd9ZznhBqo
2. **Obsidian note updated** — `010 inbox/Paperclip Harness.md` on host `.27` (3511 bytes) now includes archify map URL, Mermaid source path, Outline collection reference, and repository link.
3. **Git push** — commit d2cf643 pushed to `https://gitea.lab.audasmedia.com.au/sam/paperclip-harness.git` main (range e883b11..d2cf643).
Validation: collection create returned 200; each doc upload returned 200; note file rewrite confirmed via ls/byte count; git push output confirmed.
Follow-up flagged but not performed: bumping Pi `pi-coding-agent` Nix package on hosts `.13` and `.27` from 0.82.1 to align with `.51` (0.87.1) — awaiting user decision.
## Evidence
- Confidence: 90%
- Reason: Concrete completed deliverables with IDs, URLs, paths and commit hash are durable and reusable.
## Related learned memories <!-- same-turn-2026-11-11 21:45:49 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip Harness acceptance test plan (Point 4) and Pi/Go host versions]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|publish Paperclip Harness docs to Outline and update Obsidian note]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip Harness: use Path A (headroom-bridge agent extension), not automatic headroom compression]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Paperclip Harness: docs published to Outline, Obsidian note updated, repo pushed]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-link-2026-11-11-21-45-49|Rich discovery: link. 2026-11-11 21:45:49]]
- context: [[packs/paperclip-harness/20-context/home|link.]]

View File

@@ -404,3 +404,32 @@ 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 21:45:49)
**Decision:** Use Path A — grant `compress_for_agent` to the `headroom-bridge` agent only via `Agents>agents` → `)` extensions → `space` on `headroom-bridge` — rather than enabling both paths.
**Context:** Headroom's automatic backend compression failed in three tested configurations (502 proxy_error, 404 provider openai, 502), with `/stats` showing `api_requests: 0` (never forwarded). Meanwhile `POST /v1/compress` (the endpoint headroom-bridge uses) works reliably, returning 200 with token counts.
**Rationale:** The working, verifiable path is the bridge's `/v1/compress` call; the headroom backend failure is inside its own deployment and cannot be fixed from our software.
**Alternatives considered:** Path B (automatic compression inside headroom container) — deferred; user may still fix it later.
**Consequences/caveats:** Only the headroom-bridge agent gets `compress_for_agent`; other agents do not compress. Path B remains a separate optional fix requiring access to headroom container logs.
## Evidence
- Confidence: 85%
- Reason: Architectural choice with rationale and alternatives, useful for future agents.
## Related learned memories <!-- same-turn-2026-11-11 21:45:49 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip Harness acceptance test plan (Point 4) and Pi/Go host versions]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|publish Paperclip Harness docs to Outline and update Obsidian note]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip Harness: use Path A (headroom-bridge agent extension), not automatic headroom compression]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Paperclip Harness: docs published to Outline, Obsidian note updated, repo pushed]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-link-2026-11-11-21-45-49|Rich discovery: link. 2026-11-11 21:45:49]]
- context: [[packs/paperclip-harness/20-context/home|link.]]

View File

@@ -3643,3 +3643,128 @@ Path B (provider-level, inside the headroom container): its compose file has no
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Headroom integration paths on Pi]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Delivered paperclip-harness documentation to Gitea, Obsidian, and docs/outline]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-docs-and-gitea-publication|paperclip-harness docs and Gitea publication]]
---
## Update (2026-11-11 21:45:49)
**Acceptance tests for folder→working panes (Point 4):**
1. **Brand-new project:** empty folder, new Paperclip project, run `bin/office /tmp/fresh-project-2026-11-11 --project fresh-project`. Expected: session created, eight panes built, `Shell>shell` in that folder. Already passed once tonight, except session opened at 78 columns and `Board>board` correctly reported "needs 80 × 24" (small screen behaving correctly). Full test: switch session, press `R` to rebuild at full size, create/assign/run/merge one task.
2. **Existing folder (adoption):** `bin/office ~/paseo/projects/paperclip-harness --project <new paperclip project>`. Expected: `.harness/` appears, nothing existing overwritten, panes read this repo's tasks. Proves adoption is safe on real code.
**Version state:**
- Host `.51`: Pi 0.87.1; Go addition in place (`go gopls` in `hosts/sam-thinkpad/configuration.nix`, dry-run evaluates).
- Hosts `.13` and `.27`: Pi 0.82.1 via Nix package `pi-coding-agent`; aligning requires bumping that package in each machine's flake and rebuilding. Awaiting user decision.
**Host/service facts:** Outline reachable at `http://outline.lab.audasmedia.com.au` (port 3002 returned 404, port 3000 returned 401). Outline API `collections.list` used for discovery (14 collections total).
## Evidence
- Confidence: 85%
- Reason: Concrete test procedures and version/environment facts worth preserving.
---
## Update (2026-11-11 21:45:49)
Tested headroom configurations on a throwaway container (spare port) so the running service was untouched. Results:
| Configuration | Result |
|---|---|
| default image (`HEADROOM_BACKEND` unset → anthropic) + router key | `502 proxy_error` |
| plus `OPENAI_API_KEY`, model `openai/deepseek-v4-flash` | `404 No active credentials for provider: openai` |
| model `deepseek/deepseek-v4-flash` | `502` |
| plus `HEADROOM_BACKEND=openai` | `502 proxy_error` |
Key facts:
- `openai/` prefix in model id names the *protocol/client* to use, not OpenAI's model. `openai/deepseek-v4-flash` means "call the router with its deepseek-v4-flash model". This was a guess about headroom routing, not documented.
- The `404 ... provider: openai` originates from the router, not headroom: router read `openai/` as a provider and had no key.
- `/stats` on the test container reported `api_requests: 0` for all attempts — headroom failed before forwarding. Fix lies inside headroom's deployment/logs; not fixable from our software.
- Working path re-verified: `POST /v1/compress` returns 200 and reports token counts before/after. This endpoint is what `headroom-bridge` uses.
- `headroom-ai` is now installed on hosts `.13`, `.27`, `.51`.
- Recommendation issued: use Path A only (`Agents>agents` → `)` extensions → `space` on `headroom-bridge`), granting `compress_for_agent` to that agent only; Path B (automatic headroom compression) needs fixing in the headroom container.
No secret values recorded (an `OL_API_KEY`/router key appeared in tool output but is redacted here).
## Evidence
- Confidence: 90%
- Reason: Evidence-backed failure matrix and root-cause distinction, directly reusable to avoid repeating tests.
---
## Update (2026-11-11 21:45:49)
## Structural/configuration observations (2026-11-11 21:45:49)
## Headroom: what the failure actually is, and what you do
I tested three configurations on a throwaway container on a spare port, so the running one was untouched:
| Configuration | Result |
|---|---|
| default image (`HEADROOM_BACKEND` unset → `anthropic`) + your router key | `502 proxy_error` |
| plus `OPENAI_API_KEY` | `openai/deepseek-v4-flash` → `404 No active credentials for provider: openai`; `deepseek/deepseek-v4-flash` → `502` |
| plus `HEADROOM_BACKEND=openai` | `502 proxy_error` |
Two things that answer your questions directly:
- **`openai/` is not OpenAI's model.** In this stack the prefix names the *protocol* to speak — "use the OpenAI-compatible client" — and the rest is the model name your router uses. So `openai/deepseek-v4-flash` means "call the router with its `deepseek-v4-flash` model". That is why I wrote it that way, and it was a guess about headroom's routing, not a fact.
- **The `404 … provider: openai` came from your router, not headroom.** The router read `openai/` as a provider name and had no key for it. So that path was never going to work with our router's ids.
`/stats` on the test container reported `api_requests: 0` for all of those attempts — headroom refused or failed before forwarding. That is inside headroom's deployment, and it needs someone with its logs open; nothing in our software can fix it.
**What does work, re-checked:** `POST /v1/compress` answers 200 and reports tokens before and after. That is the endpoint `headroom-bridge` uses, and `headroom-ai` is now installed on `.13`, `.27` and `.51`.
**So: use Path A, not both.** `Agents>agents` → `)` to extensions → `space` on `headroom-bridge`. That agent, and no other, gets `compress_for_agent`. Path B is yours to fix in the headroom container if you still want automatic compression; I have recorded the three tests and their exact responses so nobody repeats them.
## The rest
**Archify in the Obsidian note** — added, with the map URL, the Mermaid source path, the Outline collection and the repository link. Note is now 3,511 bytes at `010 inbox/Paperclip Harness.md` on `.27`.
**Outline — pushed.** New collection **Paperclip Harness** with five published documents:
```
/doc/00-index-o6hhlKTFXR
/doc/01-system-overview-dGpfQOk1vt
/doc/02-configuration-and-environment-redTWei0y2
/doc/03-code-map-y6KPFbBbIC
/doc/04-agent-runbook-Sd9ZznhBqo
```
**Point 4, specifically.** Two tests, both about whether a person can get from "a folder" to "a working set of panes":
1. **A brand-new project.** An empty folder, a new Paperclip project, then `bin/office /tmp/fresh-project-2026-11-11 --project fresh-project`. Expected: session created, eight panes built, `Shell>shell` in that folder. **This already passed tonight** — except the session opened at 78 columns and `Board>board` correctly said "this workspace needs 80 × 24", which is the too-small screen doing its job, not a failure. The real test is: switch to that session, press `R` to rebuild at full size, create one task, assign it, watch it run, merge it.
2. **An existing folder.** Adopt this repository: `bin/office ~/paseo/projects/paperclip-harness --project <new paperclip project>`. Expected: `.harness/` appears, nothing existing is overwritten, the panes read *this* repo's tasks. That proves adoption is safe on real code.
**Pi versions.** `.51` is 0.87.1; `.13` and `.27` are 0.82.1. You rebuilt `.51` — the Go addition there is in place (`go gopls` in `hosts/sam-thinkpad/configuration.nix`, dry-run evaluates). For Pi: on `.13` and `.27`, Pi is the Nix package `pi-coding-agent`, so aligning means bumping that package in each machine's flake and rebuilding. Do you want me to prepare those two bumps (I can edit both flakes and run the dry-run evaluations), or leave `.13`/`.27` on 0.82.1 since they work?
Committed as `d2cf643` and pushed to Gitea.
## Source paths observed
- `nix/store/rgnappqqc5vbq60gza5fflyk84sylwl6-python3-3.14.6/lib/python3.14/json/__init__.py`
- `nix/store/rgnappqqc5vbq60gza5fflyk84sylwl6-python3-3.14.6/lib/python3.14/json/decoder.py`
- `outline.lab.audasmedia.com.au/api/collections.list`
- `home/sam/obsidian/010`
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
- `paseo/projects/paperclip-harness`
- `hosts/sam-thinkpad/configuration.nix`
## Evidence
- Confidence: 82%
- Reason: Captured factual repo structure/configuration patterns from rich discovery
## Related learned memories <!-- same-turn-2026-11-11 21:45:49 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip Harness acceptance test plan (Point 4) and Pi/Go host versions]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|publish Paperclip Harness docs to Outline and update Obsidian note]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip Harness: use Path A (headroom-bridge agent extension), not automatic headroom compression]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Paperclip Harness: docs published to Outline, Obsidian note updated, repo pushed]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-link-2026-11-11-21-45-49|Rich discovery: link. 2026-11-11 21:45:49]]
- context: [[packs/paperclip-harness/20-context/home|link.]]

View File

@@ -1149,3 +1149,150 @@ Committed as `70e1f55`.
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-discovery-snapshot-overlay-check-sh-headro|paperclip-harness discovery snapshot: overlay, check.sh, headroom, mouse-1]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-8787-2026-11-11-05-36-08|Rich discovery: 8787 2026-11-11 05:36:08]]
- context: [[packs/paperclip-harness/20-context/omni|8787]]
---
## Update (2026-11-11 21:45:49)
**Trigger:** Need to (re)publish project documentation to Outline and refresh the Obsidian index note.
**Prerequisites:** Outline reachable at http://outline.lab.audasmedia.com.au (API accepts `collections.list`, `collections.create`, doc create at `/api/...`); Obsidian vault on host `.27`; auth token available (do not log it).
**Steps:**
1. List collections via `GET /api/collections.list` to check for existing target.
2. Create collection via API (POST returns 200). Record the returned collection id.
3. Upload the five docs in order (00-index, 01-system-overview, 02-config-and-env, 03-code-map, 04-agent-runbook). Each returns 200 with a `/doc/<slug>` path.
4. Rewrite `010 inbox/Paperclip Harness.md` on `.27` to include archify map URL, Mermaid source path, Outline collection link, and repository link.
5. Verify byte count of note file.
6. Commit and push repo to Gitea: `git push` to `https://gitea.lab.audasmedia.com.au/sam/paperclip-harness.git` main.
**Known gotchas:** Parsing non-JSON curl output as JSON throws `JSONDecodeError: line 1 column 1` — check HTTP status separately from body. Port 3002 returns 404; port 3000 returns 401 (not Outline).
**Rollback:** Delete created Outline collection/docs via API; revert git commit.
## Detailed procedure from completed turn
## Headroom: what the failure actually is, and what you do
I tested three configurations on a throwaway container on a spare port, so the running one was untouched:
| Configuration | Result |
|---|---|
| default image (`HEADROOM_BACKEND` unset → `anthropic`) + your router key | `502 proxy_error` |
| plus `OPENAI_API_KEY` | `openai/deepseek-v4-flash` → `404 No active credentials for provider: openai`; `deepseek/deepseek-v4-flash` → `502` |
| plus `HEADROOM_BACKEND=openai` | `502 proxy_error` |
Two things that answer your questions directly:
- **`openai/` is not OpenAI's model.** In this stack the prefix names the *protocol* to speak — "use the OpenAI-compatible client" — and the rest is the model name your router uses. So `openai/deepseek-v4-flash` means "call the router with its `deepseek-v4-flash` model". That is why I wrote it that way, and it was a guess about headroom's routing, not a fact.
- **The `404 … provider: openai` came from your router, not headroom.** The router read `openai/` as a provider name and had no key for it. So that path was never going to work with our router's ids.
`/stats` on the test container reported `api_requests: 0` for all of those attempts — headroom refused or failed before forwarding. That is inside headroom's deployment, and it needs someone with its logs open; nothing in our software can fix it.
**What does work, re-checked:** `POST /v1/compress` answers 200 and reports tokens before and after. That is the endpoint `headroom-bridge` uses, and `headroom-ai` is now installed on `.13`, `.27` and `.51`.
**So: use Path A, not both.** `Agents>agents` → `)` to extensions → `space` on `headroom-bridge`. That agent, and no other, gets `compress_for_agent`. Path B is yours to fix in the headroom container if you still want automatic compression; I have recorded the three tests and their exact responses so nobody repeats them.
## The rest
**Archify in the Obsidian note** — added, with the map URL, the Mermaid source path, the Outline collection and the repository link. Note is now 3,511 bytes at `010 inbox/Paperclip Harness.md` on `.27`.
**Outline — pushed.** New collection **Paperclip Harness** with five published documents:
```
/doc/00-index-o6hhlKTFXR
/doc/01-system-overview-dGpfQOk1vt
/doc/02-configuration-and-environment-redTWei0y2
/doc/03-code-map-y6KPFbBbIC
/doc/04-agent-runbook-Sd9ZznhBqo
```
**Point 4, specifically.** Two tests, both about whether a person can get from "a folder" to "a working set of panes":
1. **A brand-new project.** An empty folder, a new Paperclip project, then `bin/office /tmp/fresh-project-2026-11-11 --project fresh-project`. Expected: session created, eight panes built, `Shell>shell` in that folder. **This already passed tonight** — except the session opened at 78 columns and `Board>board` correctly said "this workspace needs 80 × 24", which is the too-small screen doing its job, not a failure. The real test is: switch to that session, press `R` to rebuild at full size, create one task, assign it, watch it run, merge it.
2. **An existing folder.** Adopt this repository: `bin/office ~/paseo/projects/paperclip-harness --project <new paperclip project>`. Expected: `.harness/` appears, nothing existing is overwritten, the panes read *this* repo's tasks. That proves adoption is safe on real code.
**Pi versions.** `.51` is 0.87.1; `.13` and `.27` are 0.82.1. You rebuilt `.51` — the Go addition there is in place (`go gopls` in `hosts/sam-thinkpad/configuration.nix`, dry-run evaluates). For Pi: on `.13` and `.27`, Pi is the Nix package `pi-coding-agent`, so aligning means bumping that package in each machine's flake and rebuilding. Do you want me to prepare those two bumps (I can edit both flakes and run the dry-run evaluations), or leave `.13`/`.27` on 0.82.1 since they work?
Committed as `d2cf643` and pushed to Gitea.
## Evidence
- Confidence: 80%
- Reason: Repeatable multi-step procedure with concrete endpoints and caveats.; enriched with final-answer detail because persistence should be reusable
---
## Update (2026-11-11 21:45:49)
## Deployment/runbook details discovered (2026-11-11 21:45:49)
## Headroom: what the failure actually is, and what you do
I tested three configurations on a throwaway container on a spare port, so the running one was untouched:
| Configuration | Result |
|---|---|
| default image (`HEADROOM_BACKEND` unset → `anthropic`) + your router key | `502 proxy_error` |
| plus `OPENAI_API_KEY` | `openai/deepseek-v4-flash` → `404 No active credentials for provider: openai`; `deepseek/deepseek-v4-flash` → `502` |
| plus `HEADROOM_BACKEND=openai` | `502 proxy_error` |
Two things that answer your questions directly:
- **`openai/` is not OpenAI's model.** In this stack the prefix names the *protocol* to speak — "use the OpenAI-compatible client" — and the rest is the model name your router uses. So `openai/deepseek-v4-flash` means "call the router with its `deepseek-v4-flash` model". That is why I wrote it that way, and it was a guess about headroom's routing, not a fact.
- **The `404 … provider: openai` came from your router, not headroom.** The router read `openai/` as a provider name and had no key for it. So that path was never going to work with our router's ids.
`/stats` on the test container reported `api_requests: 0` for all of those attempts — headroom refused or failed before forwarding. That is inside headroom's deployment, and it needs someone with its logs open; nothing in our software can fix it.
**What does work, re-checked:** `POST /v1/compress` answers 200 and reports tokens before and after. That is the endpoint `headroom-bridge` uses, and `headroom-ai` is now installed on `.13`, `.27` and `.51`.
**So: use Path A, not both.** `Agents>agents` → `)` to extensions → `space` on `headroom-bridge`. That agent, and no other, gets `compress_for_agent`. Path B is yours to fix in the headroom container if you still want automatic compression; I have recorded the three tests and their exact responses so nobody repeats them.
## The rest
**Archify in the Obsidian note** — added, with the map URL, the Mermaid source path, the Outline collection and the repository link. Note is now 3,511 bytes at `010 inbox/Paperclip Harness.md` on `.27`.
**Outline — pushed.** New collection **Paperclip Harness** with five published documents:
```
/doc/00-index-o6hhlKTFXR
/doc/01-system-overview-dGpfQOk1vt
/doc/02-configuration-and-environment-redTWei0y2
/doc/03-code-map-y6KPFbBbIC
/doc/04-agent-runbook-Sd9ZznhBqo
```
**Point 4, specifically.** Two tests, both about whether a person can get from "a folder" to "a working set of panes":
1. **A brand-new project.** An empty folder, a new Paperclip project, then `bin/office /tmp/fresh-project-2026-11-11 --project fresh-project`. Expected: session created, eight panes built, `Shell>shell` in that folder. **This already passed tonight** — except the session opened at 78 columns and `Board>board` correctly said "this workspace needs 80 × 24", which is the too-small screen doing its job, not a failure. The real test is: switch to that session, press `R` to rebuild at full size, create one task, assign it, watch it run, merge it.
2. **An existing folder.** Adopt this repository: `bin/office ~/paseo/projects/paperclip-harness --project <new paperclip project>`. Expected: `.harness/` appears, nothing existing is overwritten, the panes read *this* repo's tasks. That proves adoption is safe on real code.
**Pi versions.** `.51` is 0.87.1; `.13` and `.27` are 0.82.1. You rebuilt `.51` — the Go addition there is in place (`go gopls` in `hosts/sam-thinkpad/configuration.nix`, dry-run evaluates). For Pi: on `.13` and `.27`, Pi is the Nix package `pi-coding-agent`, so aligning means bumping that package in each machine's flake and rebuilding. Do you want me to prepare those two bumps (I can edit both flakes and run the dry-run evaluations), or leave `.13`/`.27` on 0.82.1 since they work?
Committed as `d2cf643` and pushed to Gitea.
## Source paths observed
- `nix/store/rgnappqqc5vbq60gza5fflyk84sylwl6-python3-3.14.6/lib/python3.14/json/__init__.py`
- `nix/store/rgnappqqc5vbq60gza5fflyk84sylwl6-python3-3.14.6/lib/python3.14/json/decoder.py`
- `outline.lab.audasmedia.com.au/api/collections.list`
- `home/sam/obsidian/010`
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
- `paseo/projects/paperclip-harness`
- `hosts/sam-thinkpad/configuration.nix`
## Evidence
- Confidence: 83%
- Reason: Extracted repeatable deploy/configuration procedure from rich discovery
## Related learned memories <!-- same-turn-2026-11-11 21:45:49 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip Harness acceptance test plan (Point 4) and Pi/Go host versions]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|publish Paperclip Harness docs to Outline and update Obsidian note]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip Harness: use Path A (headroom-bridge agent extension), not automatic headroom compression]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Paperclip Harness: docs published to Outline, Obsidian note updated, repo pushed]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-link-2026-11-11-21-45-49|Rich discovery: link. 2026-11-11 21:45:49]]
- context: [[packs/paperclip-harness/20-context/home|link.]]

View File

@@ -0,0 +1,94 @@
---
type: session
id: session.paperclip-harness.rich-discovery-link-2026-11-11-21-45-49
title: Rich discovery: link. 2026-11-11 21:45:49
status: active
source_of_truth: false
freshness: current
last_reviewed: 2026-11-11
tags:
- pack/paperclip-harness
- agent-memory/session
- autolearn
- rich-discovery
- repo/link
---
# Rich discovery: link. 2026-11-11 21:45:49
Sanitized rich discovery snapshot captured automatically from the completed turn.
## Source paths observed
- `nix/store/rgnappqqc5vbq60gza5fflyk84sylwl6-python3-3.14.6/lib/python3.14/json/__init__.py`
- `nix/store/rgnappqqc5vbq60gza5fflyk84sylwl6-python3-3.14.6/lib/python3.14/json/decoder.py`
- `outline.lab.audasmedia.com.au/api/collections.list`
- `home/sam/obsidian/010`
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
- `paseo/projects/paperclip-harness`
- `hosts/sam-thinkpad/configuration.nix`
## Final answer snapshot
## Headroom: what the failure actually is, and what you do
I tested three configurations on a throwaway container on a spare port, so the running one was untouched:
| Configuration | Result |
|---|---|
| default image (`HEADROOM_BACKEND` unset → `anthropic`) + your router key | `502 proxy_error` |
| plus `OPENAI_API_KEY` | `openai/deepseek-v4-flash` → `404 No active credentials for provider: openai`; `deepseek/deepseek-v4-flash` → `502` |
| plus `HEADROOM_BACKEND=openai` | `502 proxy_error` |
Two things that answer your questions directly:
- **`openai/` is not OpenAI's model.** In this stack the prefix names the *protocol* to speak — "use the OpenAI-compatible client" — and the rest is the model name your router uses. So `openai/deepseek-v4-flash` means "call the router with its `deepseek-v4-flash` model". That is why I wrote it that way, and it was a guess about headroom's routing, not a fact.
- **The `404 … provider: openai` came from your router, not headroom.** The router read `openai/` as a provider name and had no key for it. So that path was never going to work with our router's ids.
`/stats` on the test container reported `api_requests: 0` for all of those attempts — headroom refused or failed before forwarding. That is inside headroom's deployment, and it needs someone with its logs open; nothing in our software can fix it.
**What does work, re-checked:** `POST /v1/compress` answers 200 and reports tokens before and after. That is the endpoint `headroom-bridge` uses, and `headroom-ai` is now installed on `.13`, `.27` and `.51`.
**So: use Path A, not both.** `Agents>agents` → `)` to extensions → `space` on `headroom-bridge`. That agent, and no other, gets `compress_for_agent`. Path B is yours to fix in the headroom container if you still want automatic compression; I have recorded the three tests and their exact responses so nobody repeats them.
## The rest
**Archify in the Obsidian note** — added, with the map URL, the Mermaid source path, the Outline collection and the repository link. Note is now 3,511 bytes at `010 inbox/Paperclip Harness.md` on `.27`.
**Outline — pushed.** New collection **Paperclip Harness** with five published documents:
```
/doc/00-index-o6hhlKTFXR
/doc/01-system-overview-dGpfQOk1vt
/doc/02-configuration-and-environment-redTWei0y2
/doc/03-code-map-y6KPFbBbIC
/doc/04-agent-runbook-Sd9ZznhBqo
```
**Point 4, specifically.** Two tests, both about whether a person can get from "a folder" to "a working set of panes":
1. **A brand-new project.** An empty folder, a new Paperclip project, then `bin/office /tmp/fresh-project-2026-11-11 --project fresh-project`. Expected: session created, eight panes built, `Shell>shell` in that folder. **This already passed tonight** — except the session opened at 78 columns and `Board>board` correctly said "this workspace needs 80 × 24", which is the too-small screen doing its job, not a failure. The real test is: switch to that session, press `R` to rebuild at full size, create one task, assign it, watch it run, merge it.
2. **An existing folder.** Adopt this repository: `bin/office ~/paseo/projects/paperclip-harness --project <new paperclip project>`. Expected: `.harness/` appears, nothing existing is overwritten, the panes read *this* repo's tasks. That proves adoption is safe on real code.
**Pi versions.** `.51` is 0.87.1; `.13` and `.27` are 0.82.1. You rebuilt `.51` — the Go addition there is in place (`go gopls` in `hosts/sam-thinkpad/configuration.nix`, dry-run evaluates). For Pi: on `.13` and `.27`, Pi is the Nix package `pi-coding-agent`, so aligning means bumping that package in each machine's flake and rebuilding. Do you want me to prepare those two bumps (I can edit both flakes and run the dry-run evaluations), or leave `.13`/`.27` on 0.82.1 since they work?
Committed as `d2cf643` and pushed to Gitea.
## 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 <!-- same-turn-2026-11-11 21:45:49 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip Harness acceptance test plan (Point 4) and Pi/Go host versions]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|publish Paperclip Harness docs to Outline and update Obsidian note]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip Harness: use Path A (headroom-bridge agent extension), not automatic headroom compression]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Paperclip Harness: docs published to Outline, Obsidian note updated, repo pushed]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-link-2026-11-11-21-45-49|Rich discovery: link. 2026-11-11 21:45:49]]
- context: [[packs/paperclip-harness/20-context/home|link.]]

View File

@@ -28,7 +28,10 @@ import tuios # noqa: E402
def parse(argv):
opts = {"folder": ".", "project": "", "session": "", "dry": "--dry" in argv,
"host": "", "no_switch": "--no-switch" in argv}
"host": "", "no_switch": "--no-switch" in argv, "new": ""}
for i, a in enumerate(argv):
if a == "--new" and i + 1 < len(argv):
opts["new"] = argv[i + 1]
args = [a for a in argv if not a.startswith("--")]
if args:
opts["folder"] = args[0]
@@ -42,6 +45,45 @@ def parse(argv):
return opts
def create_project(name, folder, dry):
"""Create a Paperclip project for a folder, with the worktree policy set.
Adopting a folder that Paperclip has never heard of needed two steps before:
make the project in the browser, then run this command. One command is enough.
"""
body = {
"name": name,
"description": "Adopted from %s by bin/office." % folder,
"status": "backlog",
"workspace": {"name": name, "sourceType": "git_repo", "cwd": folder, "isPrimary": True},
"executionWorkspacePolicy": {
"enabled": True,
"defaultMode": "isolated_workspace",
"allowIssueOverride": True,
"workspaceStrategy": {"type": "git_worktree", "baseRef": "main",
"branchTemplate": "{{issue.identifier}}-{{slug}}"},
},
}
if dry:
h.say("would create Paperclip project %r for %s" % (name, folder))
return "(dry run)"
try:
created = h.api("POST", "/api/companies/%s/projects" % h.COMPANY, body)
except h.Refused as exc:
# A project with that name may already exist; adopting it is the right
# thing to do then, not a failure.
try:
for p in h.api("GET", "/api/companies/%s/projects" % h.COMPANY):
if p.get("name") == name:
h.say("project: %s (already in Paperclip)" % name)
return p["id"]
except h.Refused:
pass
raise exc
h.say("project: %s created (%s)" % (name, created.get("id")))
return created.get("id")
def ensure_session(session, folder):
"""Make the session exist. It cannot be shown from here, and that is fine.
@@ -126,6 +168,13 @@ def main():
# so one command takes a person from a folder to a working layout. TUIOS has
# the verb for exactly this; asking the person to run `tuios new` first was
# the step everyone forgot.
if opts["dry"]:
h.say("would create a Paperclip project %r for %s" % (opts["new"] or opts["project"], folder))
h.say("would write %s" % os.path.join(folder, ".harness", "harness.toml"))
h.say("would create or reuse session %r and build eight panes there" % session)
h.say("dry run: nothing was written")
return 0
if not opts["no_switch"]:
ensure_session(session, folder)
@@ -133,6 +182,11 @@ def main():
# Only a note, because the panes are built by the machine that owns them.
h.say("host: %s (build the pages there)" % host)
if opts["new"]:
ref = create_project(opts["new"], folder, opts["dry"])
if not ref:
return 1
opts["project"] = ref
ref = opts["project"]
if not ref and pj.exists(folder):
ref = pj.load(folder)["paperclip"]["project"]

129
docs/CLEAN-TESTS.md Normal file
View File

@@ -0,0 +1,129 @@
# The two clean tests, step by step
Both tests answer one question: can a person get from a folder to a working set of panes, and
then from a task to merged work, without editing a file.
Run them in this order. Write down what you see; that is the useful part.
---
## Test 1 — a project that does not exist yet
### Step 1. Make the folder and its repository
```sh
mkdir -p ~/paseo/projects/test-alpha
cd ~/paseo/projects/test-alpha
git init -b main
printf '# test alpha\n' > README.md
git add . && git commit -m "initial commit"
```
### Step 2. Adopt it with one command
```sh
cd ~/paseo/projects/paperclip-harness
bin/office ~/paseo/projects/test-alpha --new "test-alpha"
```
`--new` creates the Paperclip project, its workspace and the worktree policy. Without `--new`,
`--project <id|name>` adopts a project that already exists.
Expected output:
```
project: test-alpha created (…)
folder: /home/sam/paseo/projects/test-alpha
session: test-alpha
machine: nixos-desktop
wrote …/.harness/harness.toml
wrote …/.harness/check.sh
wrote …/.harness/NOTES.md
session: test-alpha (created; switch to it with TUIOS's session switcher)
shell created Shell
board created Board
…
workspaces in use: 8
```
### Step 3. Show the session
A program cannot move your client: TUIOS refuses that from a pane. Use TUIOS's own session
switcher, or from a terminal:
```sh
tuios attach test-alpha
```
### Step 4. Check the panes
1. `Repair>repair` → every check passes.
2. `Shell>shell` → the box at the top says the project folder is `…/test-alpha`.
3. `Board>board` → "no tasks in this project".
4. Press `R` once. All eight panes come back, still pointing at `test-alpha`.
### Step 5. One task, end to end
1. `New task>new`: title `Add a STATUS.md with one line`, description `Create STATUS.md at the
repository root with the line: alpha is running. Change no other file. Commit it.`
Leave the blocker and the command empty. Assign `yes`. Press `Enter` on the last field.
2. `Board>board`: the task appears and goes `todo` → `in progress` → `done`.
3. `Agents>agents`: `)` to **runs**, `↑` to the newest run, `Enter` → its log.
4. `Work>work`: `change` shows one file, one line. `review` says no review recorded yet.
5. `Work>work` → `v` starts a review; the tab shows it run.
6. `Work>work` → `m` → the dialog names the branch and `main` → `y`. The merge tab shows the
rebase, the check, the review and `merged into main at …`.
**Pass:** the file exists on `main`, the task is `done`, cost is visible in `Project>costs`, and
nothing was typed into a terminal after step 2.
---
## Test 2 — a folder that already exists
This uses **this repository**, which is real code with real history.
### Step 1. Adopt it into its own session
```sh
cd ~/paseo/projects/paperclip-harness
bin/office . --project harness-repo --session harness-repo
```
The project `harness-repo` already exists in Paperclip and points at this folder, so `--project`
adopts it. A separate session is used on purpose: the working session `paperclip-harness` shows
the sandbox project, and this test must not rebuild it.
### Step 2. Confirm nothing was overwritten
```sh
git status --short
```
Expected: only new files under `.harness/` (the project file, `check.sh`, `NOTES.md`). Nothing
existing is changed. If you see any modified file that you did not touch, stop and say so.
### Step 3. Show the session and look
```sh
tuios attach harness-repo
```
1. `Project>project` → `projects` tab lists both `spike-2026-11-10` and `harness-repo`, each with
its folder and machine.
2. `Board>board` → empty, because this project has no tasks yet.
3. `New task>new` → create `Add a line to README`, description `Add the line "tested by the
harness" at the end of README.md. Change nothing else. Commit it.`, assign `yes`.
4. Watch it in `Agents>agents`, read the diff in `Work>work`. **Do not merge it** — this is the
repository's own history. Cancel the task with `c` in `Board>board` instead, and confirm in
`git log` that nothing landed.
**Pass:** the panes read this repository's own tasks, its own worktree is created, the diff shows
only `README.md`, and cancelling removes it from the board without touching `main`.
---
## What to write down
For each step: what you pressed, what appeared, and anything that did not match. That is worth
more than a verdict, because it says where the interface and Paperclip disagree.

View File

@@ -24,6 +24,7 @@ it is a pointer and should be deleted or replaced.
| `docs/PLAN-INTERFACE.md` | this project | the plan: Paperclip object → screen, what exists, what is missing, and in what order |
| `docs/SESSIONS.md` | this project | the two kinds of session, where Pi's conversations are, and the plan for the junk TUIOS sessions |
| `docs/TEST-PLAN.md` | this project | the test plan: every step, every key, every expected result |
| `docs/CLEAN-TESTS.md` | this project | the two clean tests: a new project from nothing, and adopting an existing folder |
| `docs/RUNS-AND-MERGE.md` | this project | what a task, a run and a merge are, with the measured run counts |
| `docs/NEXT.md` | this project | what is left to build, in order, and what is still unproven |
| `docs/architecture.mmd` | this project | the system diagram in Mermaid: TUIOS panes, the commands, Paperclip, where work happens |