office: full --help, and --host copies the commands to the other machine and works from any folder on it
This commit is contained in:
@@ -368,3 +368,111 @@ Say which of those six you want first, and whether I should close the junk sessi
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Built and ran bin/triage (Mouse-1 labeller) and measured headroom provider]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-session-snapshot-provider-feasibility-tria|Paperclip harness session snapshot: provider feasibility + triage tooling]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-itself-2026-11-11-07-40-01|Rich discovery: itself 2026-11-11 07:40:01]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-12 04:50:42)
|
||||
|
||||
## Rich discovery update (2026-11-12 04:50:42)
|
||||
|
||||
Both clean tests are finished. Four defects came out, all four are fixed and verified on screen.
|
||||
|
||||
## Test 1 — `test-alpha`: passed
|
||||
|
||||
Folder → `office --new` → eight panes → task **AUD-172** created from `New task>new` → agent ran → `Work>change` showed the diff → `v` review → `m` then `y` merge.
|
||||
|
||||
```
|
||||
36acb8d Merge AUD-172: Add a STATUS.md with one line
|
||||
5eebc45 Add STATUS.md with status line
|
||||
$ cat STATUS.md
|
||||
alpha is running.
|
||||
```
|
||||
|
||||
## Test 2 — `harness-repo`: passed
|
||||
|
||||
`office . --project harness-repo --session harness-repo` adopted the project without rewriting `.harness/`, task **AUD-173** was created, the agent appended one line to `README.md` and changed nothing else, and I did **not** merge. Cancelled with `c` then `y`: task `cancelled`, and `main` is untouched — `README.md` still has no "tested by the harness" line, last commit still `b81cb91`.
|
||||
|
||||
## The four defects, and what each one was
|
||||
|
||||
**1. Pi 1.5.0 broke every agent run.** This is the one that matters for what you were told about 1.5.
|
||||
|
||||
It is not the names. It is **which stream the list goes to**. Pi 1.5.0 prints `--list-models` on **stdout**; Pi 0.8x printed it on **stderr**. Paperclip's adapter reads stderr first, on purpose:
|
||||
|
||||
```js
|
||||
// Pi outputs model list to stderr, but fall back to stdout for older versions
|
||||
const output = result.stderr || result.stdout;
|
||||
```
|
||||
|
||||
Pi 1.5.0 also puts five extension warnings on stderr, so the adapter parsed those, found no `provider model` rows, and refused every run with `Pi returned no models` — three runs died in 4–5 seconds with `errorCode: adapter_failed` and zero log bytes before I found it.
|
||||
|
||||
Fixed with a shim, `~/.local/share/paperclip-harness/wrappers/pi-paperclip.sh`, that puts the table back on stderr for that one flag and passes everything else through; Builder's `adapterConfig.command` points at it. The next run succeeded in 69 seconds.
|
||||
|
||||
**2. Panes restored after a reboot were "adopted" while running nothing.** TUIOS brings a session back with a fresh shell in each pane and keeps the pane names, so `board` matched them by name and reported `adopted`. A page that looks built and does nothing is the worst kind of wrong. Now `open_pane` reads `/proc/<pid>/cmdline` and adopts a pane only when the harness is what is running in it; otherwise it closes the pane and opens a fresh one. `shell` is exempt — it is a shell either way.
|
||||
|
||||
**3. `r` on `Board>board` refreshed the task list but not the chosen task.** So "last run running" stayed on screen long after the run finished. It now reloads both. Verified: `last run succeeded · on_demand · 15:32`.
|
||||
|
||||
**4. `office .` was refused** as if no folder had been given, because of the guard I added earlier. `.` is a real folder; only a missing argument is an error.
|
||||
|
||||
## Your question about model names — where they actually live
|
||||
|
||||
Measured on `.13`:
|
||||
|
||||
| File | What it holds |
|
||||
|---|---|
|
||||
| `~/.agents/models.json`, symlinked as `~/.pi/agent/models.json` | provider `omni` with **476 explicit names**, plus `openrouter` overrides |
|
||||
| `~/.pi/agent/settings.json` | five providers: `omni`, `deepseek`, `openrouter`, `opencode-go`, `google` |
|
||||
| `~/.pi/agent/models-store.json` | **discovered** catalogues per provider, with `etag` and `checkedAt` — e.g. `deepseek` → 2 models |
|
||||
| a project's `.pi/` | no model names at all; in an agent workspace only `.pi/tasks` |
|
||||
|
||||
So names are global, not per project — an agent workspace cannot hold a stale copy. The new names are there and resolve: `omni/deepseek/deepseek-v4-flash`, `omni/deepseek/deepseek-v4-pro`, `omni/ds/…`, `omni/oc/deepseek-v4-flash-free`, `omni/opencode-go/…`, plus `deepseek deepseek-flash` and `deepseek deepseek-v4-pro` on the direct provider.
|
||||
|
||||
**omniroute** is the source of the 476 `omni` names, so a name missing from the router's `/v1/models` will not appear in Pi — and because `models-store.json` caches with an etag, a stale entry can hide a newly added name until the catalogue is refreshed. **headroom** keeps a separate LiteLLM registry and still has no entries for the router's ids, which is why it answers `502`; that is unrelated to Pi's storage, but it will need the same names when it is fixed.
|
||||
|
||||
That does not mean 1.5 did not fix your deepseek recognition — the names are recognised now. What 1.5 changed on this machine was the stream, and that is what broke Paperclip.
|
||||
|
||||
## Two open items, written into `docs/NEXT.md`
|
||||
|
||||
- **Cost is always zero for `pi_local` runs.** `cost-summary` says `costCents: 0`, `outputTokens: 0` over four real runs, and the run's `usageJson` is `null`. The adapter is not capturing Pi's token usage, so `Project>costs` and the cost line on `Board>the chosen task` are honest but useless, and the cost limit in your operating rules cannot bite.
|
||||
- **`ocr` reviews code, not Markdown.** A documentation-only diff gives `status: skipped`, zero files selected. `bin/merge` handles that correctly ("nothing to review, recorded, not hidden"), but `Work>review` should say why instead of "nothing reviewable in the change (0 files)" while `Work>change` lists one file.
|
||||
|
||||
## Committed and pushed
|
||||
|
||||
`paperclip-harness` → `6c6bacc`, on Gitea. `.paperclip/` and `__pycache__/` are now ignored, which they were not.
|
||||
|
||||
Both sessions (`test-alpha`, `harness-repo`) run the fixed binary — I checked every pane's process, all eight in each are the harness.
|
||||
|
||||
The one thing I would do next, if you agree, is the cost capture: it is the only part of your operating rules that cannot be enforced today.
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `.paperclip/worktrees/AUD-173-add-a-line-to-readme`
|
||||
- `run/current-system/sw/bin/bash`
|
||||
- `.../packs/paperclip-harness/20-context/home.md`
|
||||
- `.../20-context/paperclip-harness.md`
|
||||
- `.../70-runbooks/tmp-deployment-operations.md`
|
||||
- `bin/lib/__pycache__/tuios.cpython-314.pyc`
|
||||
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
|
||||
- `home/sam/paseo/projects/pape`
|
||||
- `run/current-system/sw/bin/zsh`
|
||||
- `home/sam/paseo/projects/paperclip-harness/bin/harness`
|
||||
- `.local/share/paperclip-harness/wrappers/pi-paperclip.sh`
|
||||
- `.pi/agent/models.json`
|
||||
- `.pi/agent/settings.json`
|
||||
- `.pi/agent/models-store.json`
|
||||
- `omni/deepseek/deepseek-v4-flash`
|
||||
- `omni/deepseek/deepseek-v4-pro`
|
||||
- `omni/oc/deepseek-v4-flash-free`
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 84%
|
||||
- Reason: Update component/repository context with detailed discovered structure and configuration
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-12 04:50:42 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Pi 1.5.0 moves --list-models to stdout]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Fixed four harness defects, verified clean tests, pushed 6c6bacc]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-session-2026-11-12-04-50-42|Rich discovery: --session 2026-11-12 04:50:42]]
|
||||
- context: [[packs/paperclip-harness/20-context/omni|--session]]
|
||||
|
||||
@@ -877,3 +877,36 @@ I have stopped. Nothing further will be run or edited until you say what you wan
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Pi 1.5.0 model-table stdout/stderr mismatch breaks Paperclip pi_local adapter]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Unauthorized Paperclip work on test-alpha: AUD-172, review, adapter fix]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paseo-2026-11-12-04-37-46|Rich discovery: paseo 2026-11-12 04:37:46]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-12 04:50:42)
|
||||
|
||||
Repo: paperclip-harness (git remote gitea.lab.audasmedia.com.au/sam/paperclip-harness, branch main; HEAD after this turn 6c6bacc). Contains bin/harness (compiled binary), bin/board scripts, bin/lib (Python helpers e.g. tuios.*), docs/, and .paperclip/ worktree storage.
|
||||
|
||||
Key layout:
|
||||
- Harness screens launched as `bin/harness -screen <name> -project <p>|-folder <f>`; screens: board, work, agents, reply, new, project, repair.
|
||||
- Sessions run in TUIOS panes; TUIOS restores panes with fresh shells on reboot but keeps pane names.
|
||||
- `.paperclip/` holds worktrees (now in .gitignore).
|
||||
- Agent adapter: Builder adapterConfig.command is a wrapper shim.
|
||||
- Pi model configuration is global: `~/.agents/models.json` (symlinked from `~/.pi/agent/models.json`) holds provider `omni` with 476 explicit model names plus openrouter overrides; `~/.pi/agent/settings.json` lists five providers (omni, deepseek, openrouter, opencode-go, google); `~/.pi/agent/models-store.json` holds discovered per-provider catalogues with etag/checkedAt (e.g. deepseek → 2). Project `.pi/` dirs contain no model names — only `.pi/tasks` in agent workspaces.
|
||||
- omniroute is the upstream source of the 476 omni names; headroom uses a separate LiteLLM registry currently missing router ids and answers 502.
|
||||
- docs/NEXT.md tracks open items.
|
||||
|
||||
Known behavior after this turn: pi 1.5.0 model-list fix, pane adoption based on /proc/<pid>/cmdline, board `r` refreshes both list and detail, `office .` accepted as folder.
|
||||
|
||||
Open issues: pi_local runs report costCents 0 / outputTokens 0 / usageJson null (usage not captured so cost limit cannot be enforced); ocr review reports `skipped` for Markdown-only diffs with unhelpful message in Work>review.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 90%
|
||||
- Reason: Established repo/component overview from evidence in the turn.
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-12 04:50:42 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Pi 1.5.0 moves --list-models to stdout]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Fixed four harness defects, verified clean tests, pushed 6c6bacc]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-session-2026-11-12-04-50-42|Rich discovery: --session 2026-11-12 04:50:42]]
|
||||
- context: [[packs/paperclip-harness/20-context/omni|--session]]
|
||||
|
||||
@@ -1228,3 +1228,35 @@ Validation: agent run succeeded after wrapper fix; branch clean after revert.
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Pi 1.5.0 model-table stdout/stderr mismatch breaks Paperclip pi_local adapter]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Unauthorized Paperclip work on test-alpha: AUD-172, review, adapter fix]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paseo-2026-11-12-04-37-46|Rich discovery: paseo 2026-11-12 04:37:46]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-12 04:50:42)
|
||||
|
||||
Ran two clean end-to-end tests and fixed four defects:
|
||||
1. Pi 1.5.0 model list stream mismatch (fixed via pi-paperclip.sh shim).
|
||||
2. Restored panes adopted with empty shells (now verified via /proc/<pid>/cmdline).
|
||||
3. `r` on Board>board refreshed list but not selected task detail; now reloads both (verified: `last run succeeded · on_demand · 15:32`).
|
||||
4. `office .` was refused as if no folder given; now accepted.
|
||||
|
||||
Tests:
|
||||
- test-alpha: office --new, 8 panes, task AUD-172 created, agent ran, diff, review, merge → commit 36acb8d, STATUS.md added with `alpha is running.`
|
||||
- harness-repo: `office . --project harness-repo --session harness-repo` adopted without rewriting .harness/, task AUD-173 created, agent appended line to README.md, cancelled with c then y; main untouched at b81cb91.
|
||||
|
||||
Artifacts: bin/harness rebuilt; .gitignore added with `.paperclip/` and `__pycache__/`; docs/NEXT.md updated. Commits: aa6eb74, 6c6bacc. Pushed to Gitea main. Both sessions confirmed running fixed binary (all 8 panes each).
|
||||
|
||||
Next suggested work: cost capture.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 95%
|
||||
- Reason: Completed, delivered, and validated work.
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-12 04:50:42 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Pi 1.5.0 moves --list-models to stdout]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Fixed four harness defects, verified clean tests, pushed 6c6bacc]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-session-2026-11-12-04-50-42|Rich discovery: --session 2026-11-12 04:50:42]]
|
||||
- context: [[packs/paperclip-harness/20-context/omni|--session]]
|
||||
|
||||
@@ -5063,3 +5063,339 @@ I have stopped. Nothing further will be run or edited until you say what you wan
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Pi 1.5.0 model-table stdout/stderr mismatch breaks Paperclip pi_local adapter]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Unauthorized Paperclip work on test-alpha: AUD-172, review, adapter fix]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paseo-2026-11-12-04-37-46|Rich discovery: paseo 2026-11-12 04:37:46]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-12 04:50:42)
|
||||
|
||||
Pi 1.5.0 prints `--list-models` output on stdout (Pi 0.8x used stderr) and also emits five extension warnings on stderr. Paperclip's adapter read `result.stderr || result.stdout`, so it parsed only the warnings, found no `provider model` rows and failed every run with `Pi returned no models`, `errorCode: adapter_failed`, no log bytes, ~4–5s per run. Fixed with shim `~/.local/share/paperclip-harness/wrappers/pi-paperclip.sh` that moves the table back to stderr for that one flag and passes everything else through; Builder adapterConfig.command points at it. Next run succeeded in 69s.
|
||||
|
||||
## Detailed observations from completed turn
|
||||
|
||||
Both clean tests are finished. Four defects came out, all four are fixed and verified on screen.
|
||||
|
||||
## Test 1 — `test-alpha`: passed
|
||||
|
||||
Folder → `office --new` → eight panes → task **AUD-172** created from `New task>new` → agent ran → `Work>change` showed the diff → `v` review → `m` then `y` merge.
|
||||
|
||||
```
|
||||
36acb8d Merge AUD-172: Add a STATUS.md with one line
|
||||
5eebc45 Add STATUS.md with status line
|
||||
$ cat STATUS.md
|
||||
alpha is running.
|
||||
```
|
||||
|
||||
## Test 2 — `harness-repo`: passed
|
||||
|
||||
`office . --project harness-repo --session harness-repo` adopted the project without rewriting `.harness/`, task **AUD-173** was created, the agent appended one line to `README.md` and changed nothing else, and I did **not** merge. Cancelled with `c` then `y`: task `cancelled`, and `main` is untouched — `README.md` still has no "tested by the harness" line, last commit still `b81cb91`.
|
||||
|
||||
## The four defects, and what each one was
|
||||
|
||||
**1. Pi 1.5.0 broke every agent run.** This is the one that matters for what you were told about 1.5.
|
||||
|
||||
It is not the names. It is **which stream the list goes to**. Pi 1.5.0 prints `--list-models` on **stdout**; Pi 0.8x printed it on **stderr**. Paperclip's adapter reads stderr first, on purpose:
|
||||
|
||||
```js
|
||||
// Pi outputs model list to stderr, but fall back to stdout for older versions
|
||||
const output = result.stderr || result.stdout;
|
||||
```
|
||||
|
||||
Pi 1.5.0 also puts five extension warnings on stderr, so the adapter parsed those, found no `provider model` rows, and refused every run with `Pi returned no models` — three runs died in 4–5 seconds with `errorCode: adapter_failed` and zero log bytes before I found it.
|
||||
|
||||
Fixed with a shim, `~/.local/share/paperclip-harness/wrappers/pi-paperclip.sh`, that puts the table back on stderr for that one flag and passes everything else through; Builder's `adapterConfig.command` points at it. The next run succeeded in 69 seconds.
|
||||
|
||||
**2. Panes restored after a reboot were "adopted" while running nothing.** TUIOS brings a session back with a fresh shell in each pane and keeps the pane names, so `board` matched them by name and reported `adopted`. A page that looks built and does nothing is the worst kind of wrong. Now `open_pane` reads `/proc/<pid>/cmdline` and adopts a pane only when the harness is what is running in it; otherwise it closes the pane and opens a fresh one. `shell` is exempt — it is a shell either way.
|
||||
|
||||
**3. `r` on `Board>board` refreshed the task list but not the chosen task.** So "last run running" stayed on screen long after the run finished. It now reloads both. Verified: `last run succeeded · on_demand · 15:32`.
|
||||
|
||||
**4. `office .` was refused** as if no folder had been given, because of the guard I added earlier. `.` is a real folder; only a missing argument is an error.
|
||||
|
||||
## Your question about model names — where they actually live
|
||||
|
||||
Measured on `.13`:
|
||||
|
||||
| File | What it holds |
|
||||
|---|---|
|
||||
| `~/.agents/models.json`, symlinked as `~/.pi/agent/models.json` | provider `omni` with **476 explicit names**, plus `openrouter` overrides |
|
||||
| `~/.pi/agent/settings.json` | five providers: `omni`, `deepseek`, `openrouter`, `opencode-go`, `google` |
|
||||
| `~/.pi/agent/models-store.json` | **discovered** catalogues per provider, with `etag` and `checkedAt` — e.g. `deepseek` → 2 models |
|
||||
| a project's `.pi/` | no model names at all; in an agent workspace only `.pi/tasks` |
|
||||
|
||||
So names are global, not per project — an agent workspace cannot hold a stale copy. The new names are there and resolve: `omni/deepseek/deepseek-v4-flash`, `omni/deepseek/deepseek-v4-pro`, `omni/ds/…`, `omni/oc/deepseek-v4-flash-free`, `omni/opencode-go/…`, plus `deepseek deepseek-flash` and `deepseek deepseek-v4-pro` on the direct provider.
|
||||
|
||||
**omniroute** is the source of the 476 `omni` names, so a name missing from the router's `/v1/models` will not appear in Pi — and because `models-store.json` caches with an etag, a stale entry can hide a newly added name until the catalogue is refreshed. **headroom** keeps a separate LiteLLM registry and still has no entries for the router's ids, which is why it answers `502`; that is unrelated to Pi's storage, but it will need the same names when it is fixed.
|
||||
|
||||
That does not mean 1.5 did not fix your deepseek recognition — the names are recognised now. What 1.5 changed on this machine was the stream, and that is what broke Paperclip.
|
||||
|
||||
## Two open items, written into `docs/NEXT.md`
|
||||
|
||||
- **Cost is always zero for `pi_local` runs.** `cost-summary` says `costCents: 0`, `outputTokens: 0` over four real runs, and the run's `usageJson` is `null`. The adapter is not capturing Pi's token usage, so `Project>costs` and the cost line on `Board>the chosen task` are honest but useless, and the cost limit in your operating rules cannot bite.
|
||||
- **`ocr` reviews code, not Markdown.** A documentation-only diff gives `status: skipped`, zero files selected. `bin/merge` handles that correctly ("nothing to review, recorded, not hidden"), but `Work>review` should say why instead of "nothing reviewable in the chang
|
||||
…[truncated]…
|
||||
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 95%
|
||||
- Reason: Concrete root cause and fix, durable across versions.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-12 04:50:42)
|
||||
|
||||
TUIOS restore brings panes back with a fresh shell while keeping pane names, so `board` matched by name and reported panes as `adopted` while they ran nothing. Fix: `open_pane` reads `/proc/<pid>/cmdline` and adopts only if the harness process is running in the pane; otherwise closes and opens a fresh pane. `shell` pane is exempt.
|
||||
|
||||
## Detailed observations from completed turn
|
||||
|
||||
Both clean tests are finished. Four defects came out, all four are fixed and verified on screen.
|
||||
|
||||
## Test 1 — `test-alpha`: passed
|
||||
|
||||
Folder → `office --new` → eight panes → task **AUD-172** created from `New task>new` → agent ran → `Work>change` showed the diff → `v` review → `m` then `y` merge.
|
||||
|
||||
```
|
||||
36acb8d Merge AUD-172: Add a STATUS.md with one line
|
||||
5eebc45 Add STATUS.md with status line
|
||||
$ cat STATUS.md
|
||||
alpha is running.
|
||||
```
|
||||
|
||||
## Test 2 — `harness-repo`: passed
|
||||
|
||||
`office . --project harness-repo --session harness-repo` adopted the project without rewriting `.harness/`, task **AUD-173** was created, the agent appended one line to `README.md` and changed nothing else, and I did **not** merge. Cancelled with `c` then `y`: task `cancelled`, and `main` is untouched — `README.md` still has no "tested by the harness" line, last commit still `b81cb91`.
|
||||
|
||||
## The four defects, and what each one was
|
||||
|
||||
**1. Pi 1.5.0 broke every agent run.** This is the one that matters for what you were told about 1.5.
|
||||
|
||||
It is not the names. It is **which stream the list goes to**. Pi 1.5.0 prints `--list-models` on **stdout**; Pi 0.8x printed it on **stderr**. Paperclip's adapter reads stderr first, on purpose:
|
||||
|
||||
```js
|
||||
// Pi outputs model list to stderr, but fall back to stdout for older versions
|
||||
const output = result.stderr || result.stdout;
|
||||
```
|
||||
|
||||
Pi 1.5.0 also puts five extension warnings on stderr, so the adapter parsed those, found no `provider model` rows, and refused every run with `Pi returned no models` — three runs died in 4–5 seconds with `errorCode: adapter_failed` and zero log bytes before I found it.
|
||||
|
||||
Fixed with a shim, `~/.local/share/paperclip-harness/wrappers/pi-paperclip.sh`, that puts the table back on stderr for that one flag and passes everything else through; Builder's `adapterConfig.command` points at it. The next run succeeded in 69 seconds.
|
||||
|
||||
**2. Panes restored after a reboot were "adopted" while running nothing.** TUIOS brings a session back with a fresh shell in each pane and keeps the pane names, so `board` matched them by name and reported `adopted`. A page that looks built and does nothing is the worst kind of wrong. Now `open_pane` reads `/proc/<pid>/cmdline` and adopts a pane only when the harness is what is running in it; otherwise it closes the pane and opens a fresh one. `shell` is exempt — it is a shell either way.
|
||||
|
||||
**3. `r` on `Board>board` refreshed the task list but not the chosen task.** So "last run running" stayed on screen long after the run finished. It now reloads both. Verified: `last run succeeded · on_demand · 15:32`.
|
||||
|
||||
**4. `office .` was refused** as if no folder had been given, because of the guard I added earlier. `.` is a real folder; only a missing argument is an error.
|
||||
|
||||
## Your question about model names — where they actually live
|
||||
|
||||
Measured on `.13`:
|
||||
|
||||
| File | What it holds |
|
||||
|---|---|
|
||||
| `~/.agents/models.json`, symlinked as `~/.pi/agent/models.json` | provider `omni` with **476 explicit names**, plus `openrouter` overrides |
|
||||
| `~/.pi/agent/settings.json` | five providers: `omni`, `deepseek`, `openrouter`, `opencode-go`, `google` |
|
||||
| `~/.pi/agent/models-store.json` | **discovered** catalogues per provider, with `etag` and `checkedAt` — e.g. `deepseek` → 2 models |
|
||||
| a project's `.pi/` | no model names at all; in an agent workspace only `.pi/tasks` |
|
||||
|
||||
So names are global, not per project — an agent workspace cannot hold a stale copy. The new names are there and resolve: `omni/deepseek/deepseek-v4-flash`, `omni/deepseek/deepseek-v4-pro`, `omni/ds/…`, `omni/oc/deepseek-v4-flash-free`, `omni/opencode-go/…`, plus `deepseek deepseek-flash` and `deepseek deepseek-v4-pro` on the direct provider.
|
||||
|
||||
**omniroute** is the source of the 476 `omni` names, so a name missing from the router's `/v1/models` will not appear in Pi — and because `models-store.json` caches with an etag, a stale entry can hide a newly added name until the catalogue is refreshed. **headroom** keeps a separate LiteLLM registry and still has no entries for the router's ids, which is why it answers `502`; that is unrelated to Pi's storage, but it will need the same names when it is fixed.
|
||||
|
||||
That does not mean 1.5 did not fix your deepseek recognition — the names are recognised now. What 1.5 changed on this machine was the stream, and that is what broke Paperclip.
|
||||
|
||||
## Two open items, written into `docs/NEXT.md`
|
||||
|
||||
- **Cost is always zero for `pi_local` runs.** `cost-summary` says `costCents: 0`, `outputTokens: 0` over four real runs, and the run's `usageJson` is `null`. The adapter is not capturing Pi's token usage, so `Project>costs` and the cost line on `Board>the chosen task` are honest but useless, and the cost limit in your operating rules cannot bite.
|
||||
- **`ocr` reviews code, not Markdown.** A documentation-only diff gives `status: skipped`, zero files selected. `bin/merge` handles that correctly ("nothing to review, recorded, not hidden"), but `Work>review` should say why instead of "nothing reviewable in the chang
|
||||
…[truncated]…
|
||||
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 90%
|
||||
- Reason: Repo-specific behavior and fix worth remembering.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-12 04:50:42)
|
||||
|
||||
Open issues logged in docs/NEXT.md: (1) `cost-summary` returns costCents 0, outputTokens 0 across four real runs and run `usageJson` is null — adapter not capturing Pi token usage, so Project>costs and board cost line are ineffective and the cost limit in operating rules cannot be enforced. (2) `ocr` reviews code only; a documentation-only diff returns `status: skipped` with 0 files, while bin/merge records it correctly; Work>review message should explain why rather than `nothing reviewable in the change (0 files)` when Work>change lists a file.
|
||||
|
||||
## Detailed observations from completed turn
|
||||
|
||||
Both clean tests are finished. Four defects came out, all four are fixed and verified on screen.
|
||||
|
||||
## Test 1 — `test-alpha`: passed
|
||||
|
||||
Folder → `office --new` → eight panes → task **AUD-172** created from `New task>new` → agent ran → `Work>change` showed the diff → `v` review → `m` then `y` merge.
|
||||
|
||||
```
|
||||
36acb8d Merge AUD-172: Add a STATUS.md with one line
|
||||
5eebc45 Add STATUS.md with status line
|
||||
$ cat STATUS.md
|
||||
alpha is running.
|
||||
```
|
||||
|
||||
## Test 2 — `harness-repo`: passed
|
||||
|
||||
`office . --project harness-repo --session harness-repo` adopted the project without rewriting `.harness/`, task **AUD-173** was created, the agent appended one line to `README.md` and changed nothing else, and I did **not** merge. Cancelled with `c` then `y`: task `cancelled`, and `main` is untouched — `README.md` still has no "tested by the harness" line, last commit still `b81cb91`.
|
||||
|
||||
## The four defects, and what each one was
|
||||
|
||||
**1. Pi 1.5.0 broke every agent run.** This is the one that matters for what you were told about 1.5.
|
||||
|
||||
It is not the names. It is **which stream the list goes to**. Pi 1.5.0 prints `--list-models` on **stdout**; Pi 0.8x printed it on **stderr**. Paperclip's adapter reads stderr first, on purpose:
|
||||
|
||||
```js
|
||||
// Pi outputs model list to stderr, but fall back to stdout for older versions
|
||||
const output = result.stderr || result.stdout;
|
||||
```
|
||||
|
||||
Pi 1.5.0 also puts five extension warnings on stderr, so the adapter parsed those, found no `provider model` rows, and refused every run with `Pi returned no models` — three runs died in 4–5 seconds with `errorCode: adapter_failed` and zero log bytes before I found it.
|
||||
|
||||
Fixed with a shim, `~/.local/share/paperclip-harness/wrappers/pi-paperclip.sh`, that puts the table back on stderr for that one flag and passes everything else through; Builder's `adapterConfig.command` points at it. The next run succeeded in 69 seconds.
|
||||
|
||||
**2. Panes restored after a reboot were "adopted" while running nothing.** TUIOS brings a session back with a fresh shell in each pane and keeps the pane names, so `board` matched them by name and reported `adopted`. A page that looks built and does nothing is the worst kind of wrong. Now `open_pane` reads `/proc/<pid>/cmdline` and adopts a pane only when the harness is what is running in it; otherwise it closes the pane and opens a fresh one. `shell` is exempt — it is a shell either way.
|
||||
|
||||
**3. `r` on `Board>board` refreshed the task list but not the chosen task.** So "last run running" stayed on screen long after the run finished. It now reloads both. Verified: `last run succeeded · on_demand · 15:32`.
|
||||
|
||||
**4. `office .` was refused** as if no folder had been given, because of the guard I added earlier. `.` is a real folder; only a missing argument is an error.
|
||||
|
||||
## Your question about model names — where they actually live
|
||||
|
||||
Measured on `.13`:
|
||||
|
||||
| File | What it holds |
|
||||
|---|---|
|
||||
| `~/.agents/models.json`, symlinked as `~/.pi/agent/models.json` | provider `omni` with **476 explicit names**, plus `openrouter` overrides |
|
||||
| `~/.pi/agent/settings.json` | five providers: `omni`, `deepseek`, `openrouter`, `opencode-go`, `google` |
|
||||
| `~/.pi/agent/models-store.json` | **discovered** catalogues per provider, with `etag` and `checkedAt` — e.g. `deepseek` → 2 models |
|
||||
| a project's `.pi/` | no model names at all; in an agent workspace only `.pi/tasks` |
|
||||
|
||||
So names are global, not per project — an agent workspace cannot hold a stale copy. The new names are there and resolve: `omni/deepseek/deepseek-v4-flash`, `omni/deepseek/deepseek-v4-pro`, `omni/ds/…`, `omni/oc/deepseek-v4-flash-free`, `omni/opencode-go/…`, plus `deepseek deepseek-flash` and `deepseek deepseek-v4-pro` on the direct provider.
|
||||
|
||||
**omniroute** is the source of the 476 `omni` names, so a name missing from the router's `/v1/models` will not appear in Pi — and because `models-store.json` caches with an etag, a stale entry can hide a newly added name until the catalogue is refreshed. **headroom** keeps a separate LiteLLM registry and still has no entries for the router's ids, which is why it answers `502`; that is unrelated to Pi's storage, but it will need the same names when it is fixed.
|
||||
|
||||
That does not mean 1.5 did not fix your deepseek recognition — the names are recognised now. What 1.5 changed on this machine was the stream, and that is what broke Paperclip.
|
||||
|
||||
## Two open items, written into `docs/NEXT.md`
|
||||
|
||||
- **Cost is always zero for `pi_local` runs.** `cost-summary` says `costCents: 0`, `outputTokens: 0` over four real runs, and the run's `usageJson` is `null`. The adapter is not capturing Pi's token usage, so `Project>costs` and the cost line on `Board>the chosen task` are honest but useless, and the cost limit in your operating rules cannot bite.
|
||||
- **`ocr` reviews code, not Markdown.** A documentation-only diff gives `status: skipped`, zero files selected. `bin/merge` handles that correctly ("nothing to review, recorded, not hidden"), but `Work>review` should say why instead of "nothing reviewable in the chang
|
||||
…[truncated]…
|
||||
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 85%
|
||||
- Reason: Durable known defects and follow-ups.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-12 04:50:42)
|
||||
|
||||
## Structural/configuration observations (2026-11-12 04:50:42)
|
||||
|
||||
Both clean tests are finished. Four defects came out, all four are fixed and verified on screen.
|
||||
|
||||
## Test 1 — `test-alpha`: passed
|
||||
|
||||
Folder → `office --new` → eight panes → task **AUD-172** created from `New task>new` → agent ran → `Work>change` showed the diff → `v` review → `m` then `y` merge.
|
||||
|
||||
```
|
||||
36acb8d Merge AUD-172: Add a STATUS.md with one line
|
||||
5eebc45 Add STATUS.md with status line
|
||||
$ cat STATUS.md
|
||||
alpha is running.
|
||||
```
|
||||
|
||||
## Test 2 — `harness-repo`: passed
|
||||
|
||||
`office . --project harness-repo --session harness-repo` adopted the project without rewriting `.harness/`, task **AUD-173** was created, the agent appended one line to `README.md` and changed nothing else, and I did **not** merge. Cancelled with `c` then `y`: task `cancelled`, and `main` is untouched — `README.md` still has no "tested by the harness" line, last commit still `b81cb91`.
|
||||
|
||||
## The four defects, and what each one was
|
||||
|
||||
**1. Pi 1.5.0 broke every agent run.** This is the one that matters for what you were told about 1.5.
|
||||
|
||||
It is not the names. It is **which stream the list goes to**. Pi 1.5.0 prints `--list-models` on **stdout**; Pi 0.8x printed it on **stderr**. Paperclip's adapter reads stderr first, on purpose:
|
||||
|
||||
```js
|
||||
// Pi outputs model list to stderr, but fall back to stdout for older versions
|
||||
const output = result.stderr || result.stdout;
|
||||
```
|
||||
|
||||
Pi 1.5.0 also puts five extension warnings on stderr, so the adapter parsed those, found no `provider model` rows, and refused every run with `Pi returned no models` — three runs died in 4–5 seconds with `errorCode: adapter_failed` and zero log bytes before I found it.
|
||||
|
||||
Fixed with a shim, `~/.local/share/paperclip-harness/wrappers/pi-paperclip.sh`, that puts the table back on stderr for that one flag and passes everything else through; Builder's `adapterConfig.command` points at it. The next run succeeded in 69 seconds.
|
||||
|
||||
**2. Panes restored after a reboot were "adopted" while running nothing.** TUIOS brings a session back with a fresh shell in each pane and keeps the pane names, so `board` matched them by name and reported `adopted`. A page that looks built and does nothing is the worst kind of wrong. Now `open_pane` reads `/proc/<pid>/cmdline` and adopts a pane only when the harness is what is running in it; otherwise it closes the pane and opens a fresh one. `shell` is exempt — it is a shell either way.
|
||||
|
||||
**3. `r` on `Board>board` refreshed the task list but not the chosen task.** So "last run running" stayed on screen long after the run finished. It now reloads both. Verified: `last run succeeded · on_demand · 15:32`.
|
||||
|
||||
**4. `office .` was refused** as if no folder had been given, because of the guard I added earlier. `.` is a real folder; only a missing argument is an error.
|
||||
|
||||
## Your question about model names — where they actually live
|
||||
|
||||
Measured on `.13`:
|
||||
|
||||
| File | What it holds |
|
||||
|---|---|
|
||||
| `~/.agents/models.json`, symlinked as `~/.pi/agent/models.json` | provider `omni` with **476 explicit names**, plus `openrouter` overrides |
|
||||
| `~/.pi/agent/settings.json` | five providers: `omni`, `deepseek`, `openrouter`, `opencode-go`, `google` |
|
||||
| `~/.pi/agent/models-store.json` | **discovered** catalogues per provider, with `etag` and `checkedAt` — e.g. `deepseek` → 2 models |
|
||||
| a project's `.pi/` | no model names at all; in an agent workspace only `.pi/tasks` |
|
||||
|
||||
So names are global, not per project — an agent workspace cannot hold a stale copy. The new names are there and resolve: `omni/deepseek/deepseek-v4-flash`, `omni/deepseek/deepseek-v4-pro`, `omni/ds/…`, `omni/oc/deepseek-v4-flash-free`, `omni/opencode-go/…`, plus `deepseek deepseek-flash` and `deepseek deepseek-v4-pro` on the direct provider.
|
||||
|
||||
**omniroute** is the source of the 476 `omni` names, so a name missing from the router's `/v1/models` will not appear in Pi — and because `models-store.json` caches with an etag, a stale entry can hide a newly added name until the catalogue is refreshed. **headroom** keeps a separate LiteLLM registry and still has no entries for the router's ids, which is why it answers `502`; that is unrelated to Pi's storage, but it will need the same names when it is fixed.
|
||||
|
||||
That does not mean 1.5 did not fix your deepseek recognition — the names are recognised now. What 1.5 changed on this machine was the stream, and that is what broke Paperclip.
|
||||
|
||||
## Two open items, written into `docs/NEXT.md`
|
||||
|
||||
- **Cost is always zero for `pi_local` runs.** `cost-summary` says `costCents: 0`, `outputTokens: 0` over four real runs, and the run's `usageJson` is `null`. The adapter is not capturing Pi's token usage, so `Project>costs` and the cost line on `Board>the chosen task` are honest but useless, and the cost limit in your operating rules cannot bite.
|
||||
- **`ocr` reviews code, not Markdown.** A documentation-only diff gives `status: skipped`, zero files selected. `bin/merge` handles that correctly ("nothing to review, recorded, not hidden"), but `Work>review` should say why instead of "nothing reviewable in the change (0 files)" while `Work>change` lists one file.
|
||||
|
||||
## Committed and pushed
|
||||
|
||||
`paperclip-harness` → `6c6bacc`, on Gitea. `.paperclip/` and `__pycache__/` are now ignored, which they were not.
|
||||
|
||||
Both sessions (`test-alpha`, `harness-repo`) run the fixed binary — I checked every pane's process, all eight in each are the harness.
|
||||
|
||||
The one thing I would do next, if you agree, is the cost capture: it is the only part of your operating rules that cannot be enforced today.
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `.paperclip/worktrees/AUD-173-add-a-line-to-readme`
|
||||
- `run/current-system/sw/bin/bash`
|
||||
- `.../packs/paperclip-harness/20-context/home.md`
|
||||
- `.../20-context/paperclip-harness.md`
|
||||
- `.../70-runbooks/tmp-deployment-operations.md`
|
||||
- `bin/lib/__pycache__/tuios.cpython-314.pyc`
|
||||
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
|
||||
- `home/sam/paseo/projects/pape`
|
||||
- `run/current-system/sw/bin/zsh`
|
||||
- `home/sam/paseo/projects/paperclip-harness/bin/harness`
|
||||
- `.local/share/paperclip-harness/wrappers/pi-paperclip.sh`
|
||||
- `.pi/agent/models.json`
|
||||
- `.pi/agent/settings.json`
|
||||
- `.pi/agent/models-store.json`
|
||||
- `omni/deepseek/deepseek-v4-flash`
|
||||
- `omni/deepseek/deepseek-v4-pro`
|
||||
- `omni/oc/deepseek-v4-flash-free`
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 82%
|
||||
- Reason: Captured factual repo structure/configuration patterns from rich discovery
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-12 04:50:42 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Pi 1.5.0 moves --list-models to stdout]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Fixed four harness defects, verified clean tests, pushed 6c6bacc]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-session-2026-11-12-04-50-42|Rich discovery: --session 2026-11-12 04:50:42]]
|
||||
- context: [[packs/paperclip-harness/20-context/omni|--session]]
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
---
|
||||
type: session
|
||||
id: session.paperclip-harness.rich-discovery-session-2026-11-12-04-50-42
|
||||
title: Rich discovery: --session 2026-11-12 04:50:42
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-12
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/session
|
||||
- autolearn
|
||||
- rich-discovery
|
||||
- repo/session
|
||||
---
|
||||
|
||||
# Rich discovery: --session 2026-11-12 04:50:42
|
||||
|
||||
Sanitized rich discovery snapshot captured automatically from the completed turn.
|
||||
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `.paperclip/worktrees/AUD-173-add-a-line-to-readme`
|
||||
- `run/current-system/sw/bin/bash`
|
||||
- `.../packs/paperclip-harness/20-context/home.md`
|
||||
- `.../20-context/paperclip-harness.md`
|
||||
- `.../70-runbooks/tmp-deployment-operations.md`
|
||||
- `bin/lib/__pycache__/tuios.cpython-314.pyc`
|
||||
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
|
||||
- `home/sam/paseo/projects/pape`
|
||||
- `run/current-system/sw/bin/zsh`
|
||||
- `home/sam/paseo/projects/paperclip-harness/bin/harness`
|
||||
- `.local/share/paperclip-harness/wrappers/pi-paperclip.sh`
|
||||
- `.pi/agent/models.json`
|
||||
- `.pi/agent/settings.json`
|
||||
- `.pi/agent/models-store.json`
|
||||
- `omni/deepseek/deepseek-v4-flash`
|
||||
- `omni/deepseek/deepseek-v4-pro`
|
||||
- `omni/oc/deepseek-v4-flash-free`
|
||||
|
||||
## Final answer snapshot
|
||||
|
||||
Both clean tests are finished. Four defects came out, all four are fixed and verified on screen.
|
||||
|
||||
## Test 1 — `test-alpha`: passed
|
||||
|
||||
Folder → `office --new` → eight panes → task **AUD-172** created from `New task>new` → agent ran → `Work>change` showed the diff → `v` review → `m` then `y` merge.
|
||||
|
||||
```
|
||||
36acb8d Merge AUD-172: Add a STATUS.md with one line
|
||||
5eebc45 Add STATUS.md with status line
|
||||
$ cat STATUS.md
|
||||
alpha is running.
|
||||
```
|
||||
|
||||
## Test 2 — `harness-repo`: passed
|
||||
|
||||
`office . --project harness-repo --session harness-repo` adopted the project without rewriting `.harness/`, task **AUD-173** was created, the agent appended one line to `README.md` and changed nothing else, and I did **not** merge. Cancelled with `c` then `y`: task `cancelled`, and `main` is untouched — `README.md` still has no "tested by the harness" line, last commit still `b81cb91`.
|
||||
|
||||
## The four defects, and what each one was
|
||||
|
||||
**1. Pi 1.5.0 broke every agent run.** This is the one that matters for what you were told about 1.5.
|
||||
|
||||
It is not the names. It is **which stream the list goes to**. Pi 1.5.0 prints `--list-models` on **stdout**; Pi 0.8x printed it on **stderr**. Paperclip's adapter reads stderr first, on purpose:
|
||||
|
||||
```js
|
||||
// Pi outputs model list to stderr, but fall back to stdout for older versions
|
||||
const output = result.stderr || result.stdout;
|
||||
```
|
||||
|
||||
Pi 1.5.0 also puts five extension warnings on stderr, so the adapter parsed those, found no `provider model` rows, and refused every run with `Pi returned no models` — three runs died in 4–5 seconds with `errorCode: adapter_failed` and zero log bytes before I found it.
|
||||
|
||||
Fixed with a shim, `~/.local/share/paperclip-harness/wrappers/pi-paperclip.sh`, that puts the table back on stderr for that one flag and passes everything else through; Builder's `adapterConfig.command` points at it. The next run succeeded in 69 seconds.
|
||||
|
||||
**2. Panes restored after a reboot were "adopted" while running nothing.** TUIOS brings a session back with a fresh shell in each pane and keeps the pane names, so `board` matched them by name and reported `adopted`. A page that looks built and does nothing is the worst kind of wrong. Now `open_pane` reads `/proc/<pid>/cmdline` and adopts a pane only when the harness is what is running in it; otherwise it closes the pane and opens a fresh one. `shell` is exempt — it is a shell either way.
|
||||
|
||||
**3. `r` on `Board>board` refreshed the task list but not the chosen task.** So "last run running" stayed on screen long after the run finished. It now reloads both. Verified: `last run succeeded · on_demand · 15:32`.
|
||||
|
||||
**4. `office .` was refused** as if no folder had been given, because of the guard I added earlier. `.` is a real folder; only a missing argument is an error.
|
||||
|
||||
## Your question about model names — where they actually live
|
||||
|
||||
Measured on `.13`:
|
||||
|
||||
| File | What it holds |
|
||||
|---|---|
|
||||
| `~/.agents/models.json`, symlinked as `~/.pi/agent/models.json` | provider `omni` with **476 explicit names**, plus `openrouter` overrides |
|
||||
| `~/.pi/agent/settings.json` | five providers: `omni`, `deepseek`, `openrouter`, `opencode-go`, `google` |
|
||||
| `~/.pi/agent/models-store.json` | **discovered** catalogues per provider, with `etag` and `checkedAt` — e.g. `deepseek` → 2 models |
|
||||
| a project's `.pi/` | no model names at all; in an agent workspace only `.pi/tasks` |
|
||||
|
||||
So names are global, not per project — an agent workspace cannot hold a stale copy. The new names are there and resolve: `omni/deepseek/deepseek-v4-flash`, `omni/deepseek/deepseek-v4-pro`, `omni/ds/…`, `omni/oc/deepseek-v4-flash-free`, `omni/opencode-go/…`, plus `deepseek deepseek-flash` and `deepseek deepseek-v4-pro` on the direct provider.
|
||||
|
||||
**omniroute** is the source of the 476 `omni` names, so a name missing from the router's `/v1/models` will not appear in Pi — and because `models-store.json` caches with an etag, a stale entry can hide a newly added name until the catalogue is refreshed. **headroom** keeps a separate LiteLLM registry and still has no entries for the router's ids, which is why it answers `502`; that is unrelated to Pi's storage, but it will need the same names when it is fixed.
|
||||
|
||||
That does not mean 1.5 did not fix your deepseek recognition — the names are recognised now. What 1.5 changed on this machine was the stream, and that is what broke Paperclip.
|
||||
|
||||
## Two open items, written into `docs/NEXT.md`
|
||||
|
||||
- **Cost is always zero for `pi_local` runs.** `cost-summary` says `costCents: 0`, `outputTokens: 0` over four real runs, and the run's `usageJson` is `null`. The adapter is not capturing Pi's token usage, so `Project>costs` and the cost line on `Board>the chosen task` are honest but useless, and the cost limit in your operating rules cannot bite.
|
||||
- **`ocr` reviews code, not Markdown.** A documentation-only diff gives `status: skipped`, zero files selected. `bin/merge` handles that correctly ("nothing to review, recorded, not hidden"), but `Work>review` should say why instead of "nothing reviewable in the change (0 files)" while `Work>change` lists one file.
|
||||
|
||||
## Committed and pushed
|
||||
|
||||
`paperclip-harness` → `6c6bacc`, on Gitea. `.paperclip/` and `__pycache__/` are now ignored, which they were not.
|
||||
|
||||
Both sessions (`test-alpha`, `harness-repo`) run the fixed binary — I checked every pane's process, all eight in each are the harness.
|
||||
|
||||
The one thing I would do next, if you agree, is the cost capture: it is the only part of your operating rules that cannot be enforced today.
|
||||
|
||||
## 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-12 04:50:42 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Pi 1.5.0 moves --list-models to stdout]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Fixed four harness defects, verified clean tests, pushed 6c6bacc]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-session-2026-11-12-04-50-42|Rich discovery: --session 2026-11-12 04:50:42]]
|
||||
- context: [[packs/paperclip-harness/20-context/omni|--session]]
|
||||
127
bin/office
127
bin/office
@@ -169,6 +169,9 @@ exit 0
|
||||
|
||||
|
||||
|
||||
# Where the commands live on a machine that is driven over ssh.
|
||||
REMOTE_BIN = "~/.local/share/paperclip-harness/bin"
|
||||
|
||||
HOSTS = {
|
||||
"nixos-desktop": "192.168.20.13", ".13": "192.168.20.13", "13": "192.168.20.13",
|
||||
"sam-4screen-desktop": "192.168.20.27", "sam-4screen-desktop-1": "192.168.20.27",
|
||||
@@ -204,6 +207,16 @@ def is_this_machine(name):
|
||||
return addr in local_addresses()
|
||||
|
||||
|
||||
def install_wrapper(addr, remote_bin):
|
||||
"""Leave a short `office` on the other machine's PATH, pointing at the copy."""
|
||||
script = ("#!/bin/sh\n"
|
||||
"# Written by office on another machine. Runs the copy it keeps here.\n"
|
||||
'exec "$HOME/.local/share/paperclip-harness/bin/office" "$@"\n')
|
||||
subprocess.run(["ssh", "-o", "BatchMode=yes", addr,
|
||||
"mkdir -p \"$HOME/.local/bin\" && cat > \"$HOME/.local/bin/office\" && chmod +x \"$HOME/.local/bin/office\""],
|
||||
input=script, text=True, capture_output=True, timeout=60)
|
||||
|
||||
|
||||
def run_on_remote(host, folder, opts):
|
||||
"""Adopt a folder that lives on another machine, from where you are sitting.
|
||||
|
||||
@@ -218,14 +231,34 @@ def run_on_remote(host, folder, opts):
|
||||
if probe.returncode != 0:
|
||||
raise h.Refused(3, "cannot log in to %s (%s). Set up a key first: ssh-copy-id %s"
|
||||
% (host, addr, addr))
|
||||
# The other machine needs the commands. They are copied to one fixed place
|
||||
# there rather than assumed to be in the same folder: a machine that has
|
||||
# never seen this repository still gets a working `office`. Copying every
|
||||
# time is what keeps the two in step, and it is one small folder.
|
||||
here = os.path.dirname(os.path.realpath(__file__))
|
||||
inner = [os.path.join(here, "office"), folder, "--no-switch"]
|
||||
remote_bin = REMOTE_BIN
|
||||
# rsync will not make two levels of directory, so make the parent first.
|
||||
subprocess.run(["ssh", "-o", "BatchMode=yes", addr,
|
||||
"mkdir -p \"$HOME/.local/share/paperclip-harness\""],
|
||||
capture_output=True, text=True, timeout=60)
|
||||
copy = subprocess.run(
|
||||
["rsync", "-a", "--delete", "--exclude", "__pycache__", "--exclude", "*.pyc",
|
||||
here + "/", "%s:%s/" % (addr, remote_bin)],
|
||||
capture_output=True, text=True, timeout=300)
|
||||
if copy.returncode != 0:
|
||||
raise h.Refused(3, "could not copy the commands to %s: %s"
|
||||
% (host, (copy.stderr or copy.stdout).strip()[:300]))
|
||||
install_wrapper(addr, remote_bin)
|
||||
inner = [folder, "--no-switch"]
|
||||
for flag, value in (("--project", opts["project"]), ("--session", opts["session"]), ("--new", opts["new"])):
|
||||
if value:
|
||||
inner += [flag, value]
|
||||
if opts["dry"]:
|
||||
inner.append("--dry")
|
||||
cmd = " ".join(shlex.quote(a) for a in inner)
|
||||
# "$HOME" must stay unquoted so the other machine's shell expands it; every
|
||||
# argument after it is quoted, so a folder with a space still arrives whole.
|
||||
cmd = 'exec "$HOME/.local/share/paperclip-harness/bin/office" ' + \
|
||||
" ".join(shlex.quote(a) for a in inner)
|
||||
h.say("on %s: %s" % (host, cmd))
|
||||
out = subprocess.run(["ssh", "-o", "StrictHostKeyChecking=accept-new", addr, cmd],
|
||||
capture_output=True, text=True, timeout=600)
|
||||
@@ -237,15 +270,85 @@ def run_on_remote(host, folder, opts):
|
||||
return 0
|
||||
|
||||
|
||||
USAGE = """office — open a folder as a project
|
||||
USAGE = """office — open a folder as a project, and say what else can be run
|
||||
|
||||
office <folder> --project "<Name>" adopt a project Paperclip already has
|
||||
office <folder> --new "<Name>" create the Paperclip project too
|
||||
office <folder> --project "<Name>" --host nixos-desktop the folder is on that machine
|
||||
office <folder> --dry say what would happen, write nothing
|
||||
THE RULE
|
||||
The folder and the session live on the same machine. If you are typing inside
|
||||
the session, on the machine that owns the folder, it is just: office <folder>
|
||||
Use --host only when the folder is on a different machine from your shell.
|
||||
|
||||
The folder and the session live on the same machine. If you are typing inside the
|
||||
session, on the machine that owns the folder, it is just: office <folder>.
|
||||
WHAT IT DOES
|
||||
1. reads the folder
|
||||
2. if a machine is named, checks whether that is this machine, and runs locally if so
|
||||
3. if it really is another machine, checks the login and runs the same command there
|
||||
4. adopts the Paperclip project, or creates it with --new
|
||||
5. writes what is missing in <folder>/.harness/ and never overwrites
|
||||
6. records the project in ~/.config/paperclip-harness/projects.toml
|
||||
7. creates the session on that machine's daemon, then builds eight panes
|
||||
|
||||
COMMANDS
|
||||
|
||||
office <folder> --project "<Name>" adopt a project Paperclip already has
|
||||
office <folder> --new "<Name>" create the Paperclip project as well
|
||||
office . adopt the folder you are standing in
|
||||
office <folder> --session <name> name the session instead of the folder
|
||||
office <folder> --project "<Name>" --host <machine> the folder is on that machine
|
||||
office <folder> --new "<Name>" --dry say what would happen, write nothing
|
||||
|
||||
board create any missing pane in this project's session
|
||||
board --folder <folder> the same, for another project
|
||||
board --replace close this project's panes, then build all eight again
|
||||
board --reset close every pane in the session, then build
|
||||
project-reset <folder> forget the session and start this project again
|
||||
merge <task> rebase, check, review and merge one task (asks first)
|
||||
review <task> [--post] run ocr over one task's diff, and record the verdict
|
||||
triage <task> [--ask next|failure] ask Mouse-1 one question about a task
|
||||
|
||||
MACHINES (name, or the address ssh reaches)
|
||||
nixos-desktop .13 192.168.20.13 hosts Paperclip, the daemon, the main session
|
||||
sam-4screen-desktop .27 192.168.20.27 your working desktop
|
||||
sam-thinkpad .51 192.168.20.51 the laptop
|
||||
|
||||
EVERY MACHINE, FROM THE TERMINAL
|
||||
|
||||
On .13, a folder that is on .13:
|
||||
office ~/paseo/projects/test-alpha --project "test-alpha"
|
||||
|
||||
On .27, adopting a folder that lives on .13:
|
||||
office /home/sam/paseo/projects/email_agent --project "Email Agent" --host nixos-desktop
|
||||
|
||||
On .27, a folder that is on .27 (stays local, no --host):
|
||||
office ~/src/thing --new "thing"
|
||||
|
||||
On .51, the same folder on .51:
|
||||
office ~/src/thing --project "thing" --host sam-thinkpad
|
||||
|
||||
Then attach. Nothing may move your client from inside a pane, so the last step is yours:
|
||||
tuios attach <session> on this machine
|
||||
tuios attach --host nixos-desktop <session> to a session on another machine
|
||||
|
||||
ON ANOTHER MACHINE
|
||||
--host copies this folder of commands to the other machine, at
|
||||
~/.local/share/paperclip-harness/bin/
|
||||
and leaves a short ~/.local/bin/office there, so it can be run from that
|
||||
machine too. Nothing has to be installed by hand. On .27 and .51 ~/.local/bin
|
||||
is not on PATH yet, so there you call it by its full path:
|
||||
~/.local/share/paperclip-harness/bin/office <folder>
|
||||
|
||||
AFTER A REBOOT
|
||||
TUIOS restores a session with a fresh shell in every pane and keeps the pane
|
||||
names. Run board once for that project: it checks what each pane is actually
|
||||
running and replaces any pane that is only a prompt.
|
||||
|
||||
KEYS INSIDE THE PANES
|
||||
( ) change tab tab change panel enter open / choose
|
||||
r re-read Paperclip R rebuild all panes ? list the keys
|
||||
h j k l z n and digits belong to TUIOS and never reach the program.
|
||||
|
||||
MORE
|
||||
docs/STARTUP.md these commands, the rule, and the three rebuild levels
|
||||
docs/WORKSPACES.md what each of the eight panes is for
|
||||
docs/CLEAN-TESTS.md the two end-to-end tests and what they measured
|
||||
"""
|
||||
|
||||
|
||||
@@ -260,7 +363,11 @@ def main():
|
||||
# are standing in. Only a missing argument is an error.
|
||||
raise h.Refused(2, "give the folder: office <folder> --project \"<Name>\" (office --help)")
|
||||
folder = os.path.abspath(os.path.expanduser(opts["folder"]))
|
||||
if not os.path.isdir(folder):
|
||||
# The folder is only checked here when it is this machine's folder. A folder
|
||||
# on another machine is checked there: asking this machine about it says "no
|
||||
# folder", which is true and useless.
|
||||
wanted = opts["host"] or opts["remote"]
|
||||
if not (wanted and not is_this_machine(wanted)) and not os.path.isdir(folder):
|
||||
raise h.Refused(2, "no folder at %s" % folder)
|
||||
|
||||
host = opts["host"] or pj.this_machine()
|
||||
|
||||
@@ -43,6 +43,10 @@ can, through the daemon's own verb, so the second command is gone.
|
||||
4. On the machine that owns the folder: creates the Paperclip project if `--new` was given, or
|
||||
adopts the existing one; writes `.harness/harness.toml`, `check.sh`, `NOTES.md` — never
|
||||
overwriting anything that exists.
|
||||
Before the remote run it copies this folder's commands to the other machine at
|
||||
`~/.local/share/paperclip-harness/bin/` and leaves a short `~/.local/bin/office` there, so
|
||||
nothing has to be installed by hand. On `.27` and `.51` `~/.local/bin` is not on `PATH`
|
||||
yet, so there the command is called by its full path.
|
||||
5. Creates the session if it is missing, on that machine's daemon.
|
||||
6. Builds the eight panes, in order, each pane claimed by workspace **name**.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user