office: --new creates the Paperclip project, --remote adopts a folder on another machine

This commit is contained in:
Sam
2026-11-12 10:32:03 +11:00
parent 08a4b4e822
commit 9631cdda48
10 changed files with 780 additions and 20 deletions

4
.harness/NOTES.md Normal file
View File

@@ -0,0 +1,4 @@
# harness-repo
What this project is, what finished looks like, and anything a person
picking it up next week needs to know. Notes only: tasks live in Paperclip.

15
.harness/check.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/sh
# This project's own check, run by bin/merge before and after it puts a task's
# work on the base branch. Exit 0 means "the project still passes".
#
# It does not decide that a task is finished: an agent sets a task's status, and
# the review decides whether the change is good. This is the regression check,
# the same thing a CI pipeline would run.
#
# Leave it as it is while the project has no tests. bin/merge will say there is
# no check and let the review decide. Replace the body when tests exist:
#
# exec go test ./...
# exec make test
echo "this project has no check yet"
exit 0

14
.harness/harness.toml Normal file
View File

@@ -0,0 +1,14 @@
# Written by bin/office. One project, one folder, one machine.
# Paperclip owns the project, its tasks and its worktrees; this file only
# remembers where the work is and what to show.
session = "harness-repo"
watching = ""
[paperclip]
company = "d4921013-e5da-4d88-8016-57d5746e2d03"
project = "4e4bf84e-a0d6-4e40-94ae-ab2ac2fdc53c"
[machine]
host = "nixos-desktop"
folder = "/home/sam/paseo/projects/paperclip-harness"

View File

@@ -612,3 +612,131 @@ Say which of 1, 2, 4, 5 you want (3 is half done), and I will write them in that
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-has-2026-11-11-08-20-35|Rich discovery: has 2026-11-11 08:20:35]] - session: [[packs/paperclip-harness/80-sessions/rich-discovery-has-2026-11-11-08-20-35|Rich discovery: has 2026-11-11 08:20:35]]
- context: [[packs/paperclip-harness/20-context/paperclip-harness|has]] - context: [[packs/paperclip-harness/20-context/paperclip-harness|has]]
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|has repository structure and configuration patterns]] - observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|has repository structure and configuration patterns]]
---
## Update (2026-11-11 22:37:01)
## Rich discovery update (2026-11-11 22:37:01)
Steps below, and the dry runs are done.
## Test 1 — a project that does not exist yet
```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"
```
Then **one command**:
```sh
cd ~/paseo/projects/paperclip-harness
bin/office ~/paseo/projects/test-alpha --new "test-alpha"
```
`--new` is new tonight: it creates the Paperclip project, its workspace and the task-worktree policy, then writes `.harness/`, creates the session and builds all eight panes. Expected:
```
project: test-alpha created (…)
folder: /home/sam/paseo/projects/test-alpha
session: test-alpha
wrote …/.harness/harness.toml
wrote …/.harness/check.sh
wrote …/.harness/NOTES.md
board created Board
… eight panes
```
Then, in TUIOS's session switcher (or `tuios attach test-alpha`):
1. `Repair>repair` — every check passes.
2. `Shell>shell` — the box says the folder is `…/test-alpha`.
3. `Board>board` — "no tasks in this project".
4. Press `R` once — all eight panes come back, still on `test-alpha`.
Then one task end to end: `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.`, no blocker, no command, assign `yes`. Watch it in `Board` then `Agents>agents` (`)` to runs, `↑`, `Enter` for the log). Then `Work>work`: `change` shows one file, `v` starts a review, `m` asks and then merges with `y`.
**Pass:** the file is on `main`, the task is `done`, the cost is in `Project>costs`, and nothing was typed into a terminal after step 2.
## Test 2 — a folder that already exists (this repository)
I created the Paperclip project for it already, so this is one command:
```sh
cd ~/paseo/projects/paperclip-harness
bin/office . --project harness-repo --session harness-repo
```
A separate session on purpose — the working session `paperclip-harness` shows the sandbox project and must not be rebuilt.
Then:
1. `git status --short` — **only new files under `.harness/`**. If anything existing shows as modified, stop and tell me.
2. `tuios attach harness-repo`.
3. `Project>project` → `projects` tab lists both `spike-2026-11-10` and `harness-repo` with folder and machine.
4. `Board>board` — empty; this project has no tasks.
5. 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`.
6. Watch it, read the diff in `Work>work`, and **do not merge it** — cancel it with `c` in `Board>board` and confirm with `git log` that `main` is untouched.
Both are written out in `docs/CLEAN-TESTS.md` with the expected output at each step.
## Dry runs on `.13` and `.27` for Pi
I copied `/etc/nixos` to `/tmp/nixos-dryrun`, updated the lock there, and evaluated — no system was touched.
| | locked nixpkgs | pi after update |
|---|---|---|
| `.13` | 2026-07-29 → 2026-11-07 | **1.5.0** |
| `.27` | 2026-07-29 → 2026-11-07 | **1.5.0** |
| `.51` today | 2026-09-26 | 0.87.1 |
Two things this tells us:
1. Bumping the lock does not give you 0.87.1 — it gives **1.5.0**, because nixpkgs has moved a long way.
2. On `.13` the dry-run build **fails** on a real migration:
```
programs.zsh.initExtra no longer has any effect; please remove it.
Use programs.zsh.initContent instead.
```
So aligning Pi is not a one-line change: it is a lock bump, a `home.nix` edit for the zsh option, and a rebuild with a session to test afterwards. `.51` is ahead because its nixpkgs pin is newer, which is also why it has 0.87.1.
Three options, my recommendation first:
1. **Leave `.13`/`.27` on 0.82.1 for now.** They work, and the harness is tested against them.
2. **Pin only Pi** to a newer version with a small overlay, leaving everything else alone — a contained change I can prepare and dry-run.
3. **Full lock bump plus the `initContent` fix**, tested on `.13` first. Biggest change, most churn.
Committed as `08a4b4e` and pushed. Which of the three for Pi, and do you want me to walk the tests with you as you run them?
## Source paths observed
- `nix-community/home-manager/82ce401aa350502897c3f2e85f384d61cd3b0b6d`
- `NixOS/nixpkgs/0954f7ee2f6bb3dc7d4e3d0d8bcb8fd4bde4cfc5`
- `NixOS/nixpkgs/f4a03c008967841f2a0b3cb7c436fc6fc31671f6`
- `nix/store/lslq5ihfblb905y8jazs15isad5zh97z-source/home.nix`
- `tmp/dryrun-alpha/.harness/harness.toml`
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
- `paseo/projects/test-alpha`
- `paseo/projects/paperclip-harness`
- `home/sam/paseo/projects/test-alpha`
## Evidence
- Confidence: 84%
- Reason: Update component/repository context with detailed discovered structure and configuration
## Related learned memories <!-- same-turn-2026-11-11 22:37:01 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin/office dry run still creates the TUIOS session and refuses on project-name mismatch]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|clean end-to-end acceptance tests for paperclip-harness (`docs/CLEAN-TESTS.md`)]]
- action: [[packs/paperclip-harness/40-actions/2026-11-11-paperclip-harness-added-new-onboarding-clean-test-doc-and-pi|paperclip-harness: added `--new` onboarding, clean-test doc, and Pi dry-run analysis; pushed 08a4b4e]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-new-existing-dry-runs-clean-test-plan-pi-v|paperclip-harness: --new/--existing dry runs, clean test plan, Pi version dry-run on .13/.27]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-root-2026-11-11-22-37-01|Rich discovery: root 2026-11-11 22:37:01]]
- context: [[packs/paperclip-harness/20-context/paperclip-harness|root]]

View File

@@ -0,0 +1,47 @@
---
type: action
id: action.paperclip-harness.paperclip-harness-added-new-onboarding-clean-test-doc-and-pi
title: paperclip-harness: added `--new` onboarding, clean-test doc, and Pi dry-run analysis; pushed 08a4b4e
status: active
source_of_truth: false
freshness: current
last_reviewed: 2026-11-11
tags:
- pack/paperclip-harness
- agent-memory/action
- paperclip-harness
- action
- commits
- dry-run
- nix
- pi
---
# paperclip-harness: added `--new` onboarding, clean-test doc, and Pi dry-run analysis; pushed 08a4b4e
Deliverables pushed to `https://gitea.lab.audasmedia.com.au/sam/paperclip-harness.git` main (`d2cf643..08a4b4e`):
- New `bin/office --new <name>` path that creates the Paperclip project, workspaces folder, workspace and task-worktree policy, writes `.harness/{harness.toml,check.sh,NOTES.md}`, creates the session and builds eight panes in one command.
- `docs/CLEAN-TESTS.md` with the two acceptance tests and expected output at each step (see related runbook).
- Dry-run validation done on scratch folders: syntax check passed, would-lines correct, leftover TUIOS sessions killed (`dryrun-alpha`, `fresh-project-2026-11-11`); confirmed dry run creates the session and that `--project` refuses unmatched names.
- Pi versioning dry-run on NixOS `/etc/nixos` copies for `.13`/`.27`: lock bump yields pi 1.5.0 and `.13` fails on `programs.zsh.initExtra` migration; `.51` already on 0.87.1.
Open follow-up (awaiting user): choose option 1 (leave .13/.27 on 0.82.1, recommended), 2 (Pi-only overlay pin), or 3 (full lock bump + `initContent` fix tested on .13); plus whether to walk the clean tests interactively.
## Evidence
- Confidence: 85%
- Reason: Completed, evidence-backed deliverable with commit range and explicit open follow-up.
## Related
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
## Related learned memories <!-- same-turn-2026-11-11 22:37:01 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin/office dry run still creates the TUIOS session and refuses on project-name mismatch]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|clean end-to-end acceptance tests for paperclip-harness (`docs/CLEAN-TESTS.md`)]]
- action: [[packs/paperclip-harness/40-actions/2026-11-11-paperclip-harness-added-new-onboarding-clean-test-doc-and-pi|paperclip-harness: added `--new` onboarding, clean-test doc, and Pi dry-run analysis; pushed 08a4b4e]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-new-existing-dry-runs-clean-test-plan-pi-v|paperclip-harness: --new/--existing dry runs, clean test plan, Pi version dry-run on .13/.27]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-root-2026-11-11-22-37-01|Rich discovery: root 2026-11-11 22:37:01]]
- context: [[packs/paperclip-harness/20-context/paperclip-harness|root]]

View File

@@ -3768,3 +3768,267 @@ Committed as `d2cf643` and pushed to Gitea.
- 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]] - 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]] - 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.]] - context: [[packs/paperclip-harness/20-context/home|link.]]
---
## Update (2026-11-11 22:37:01)
Observed behavior of `bin/office` dry runs in `~/paseo/projects/paperclip-harness`:
- A dry run is not fully side-effect free: it **creates the TUIOS session** (`session: dryrun-alpha (created; switch to it with TUIOS's session switcher)`), so it must be cleaned up afterwards (`tuios` kill, output `Killed session 'dryrun-alpha'.`). The session also shows in the session list with 0 windows, detached.
- It refuses when the Paperclip project name passed/derived does not match an existing project: `refused: no Paperclip project matches '(dry run)'`. So dry runs against an unknown name need a resolvable project or `--new`.
- Planned actions are printed as `would ...` lines (create Paperclip project, write `<folder>/.harness/harness.toml`, create or reuse session and build eight panes) and end with `dry run: nothing was written`.
- Script syntax was verified with a plain syntax check (`syntax ok`) before running.
Caveat for future agents: do not assume dry run == no session created; check and kill leftover sessions.
## Evidence
- Confidence: 85%
- Reason: Factual, evidence-backed caveats about dry-run side effects and refusal behavior.
---
## Update (2026-11-11 22:37:01)
Dry-run evaluation of `/etc/nixos` on the NixOS hosts (copied to `/tmp/nixos-dryrun`, no system touched):
| host | locked nixpkgs | pi after lock update | pi today |
|---|---|---|---|
| `.13` | 2026-07-29 → 2026-11-07 | 1.5.0 | 0.82.1 (stated as current) |
| `.27` | 2026-07-29 → 2026-11-07 | 1.5.0 | 0.82.1 |
| `.51` | 2026-09-26 | — | 0.87.1 |
Conclusions: bumping the lock does not reproduce .51's 0.87.1 — nixpkgs jumps straight to pi 1.5.0. `.51` is ahead because its nixpkgs pin is newer. On `.13` the dry-run build additionally **fails** on the zsh option migration: `programs.zsh.initExtra no longer has any effect; please remove it. Use programs.zsh.initContent instead.` So aligning Pi requires a lock bump, a `home.nix` edit for the zsh option, and a rebuild plus a session to test afterwards — not a one-line change.
## Detailed observations from completed turn
Steps below, and the dry runs are done.
## Test 1 — a project that does not exist yet
```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"
```
Then **one command**:
```sh
cd ~/paseo/projects/paperclip-harness
bin/office ~/paseo/projects/test-alpha --new "test-alpha"
```
`--new` is new tonight: it creates the Paperclip project, its workspace and the task-worktree policy, then writes `.harness/`, creates the session and builds all eight panes. Expected:
```
project: test-alpha created (…)
folder: /home/sam/paseo/projects/test-alpha
session: test-alpha
wrote …/.harness/harness.toml
wrote …/.harness/check.sh
wrote …/.harness/NOTES.md
board created Board
… eight panes
```
Then, in TUIOS's session switcher (or `tuios attach test-alpha`):
1. `Repair>repair` — every check passes.
2. `Shell>shell` — the box says the folder is `…/test-alpha`.
3. `Board>board` — "no tasks in this project".
4. Press `R` once — all eight panes come back, still on `test-alpha`.
Then one task end to end: `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.`, no blocker, no command, assign `yes`. Watch it in `Board` then `Agents>agents` (`)` to runs, `↑`, `Enter` for the log). Then `Work>work`: `change` shows one file, `v` starts a review, `m` asks and then merges with `y`.
**Pass:** the file is on `main`, the task is `done`, the cost is in `Project>costs`, and nothing was typed into a terminal after step 2.
## Test 2 — a folder that already exists (this repository)
I created the Paperclip project for it already, so this is one command:
```sh
cd ~/paseo/projects/paperclip-harness
bin/office . --project harness-repo --session harness-repo
```
A separate session on purpose — the working session `paperclip-harness` shows the sandbox project and must not be rebuilt.
Then:
1. `git status --short` — **only new files under `.harness/`**. If anything existing shows as modified, stop and tell me.
2. `tuios attach harness-repo`.
3. `Project>project` → `projects` tab lists both `spike-2026-11-10` and `harness-repo` with folder and machine.
4. `Board>board` — empty; this project has no tasks.
5. 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`.
6. Watch it, read the diff in `Work>work`, and **do not merge it** — cancel it with `c` in `Board>board` and confirm with `git log` that `main` is untouched.
Both are written out in `docs/CLEAN-TESTS.md` with the expected output at each step.
## Dry runs on `.13` and `.27` for Pi
I copied `/etc/nixos` to `/tmp/nixos-dryrun`, updated the lock there, and evaluated — no system was touched.
| | locked nixpkgs | pi after update |
|---|---|---|
| `.13` | 2026-07-29 → 2026-11-07 | **1.5.0** |
| `.27` | 2026-07-29 → 2026-11-07 | **1.5.0** |
| `.51` today | 2026-09-26 | 0.87.1 |
Two things this tells us:
1. Bumping the lock does not give you 0.87.1 — it gives **1.5.0**, because nixpkgs has moved a long way.
2. On `.13` the dry-run build **fails** on a real migration:
```
programs.zsh.initExtra no longer has any effect; please remove it.
Use programs.zsh.initContent instead.
```
So aligning Pi is not a one-line change: it is a lock bump, a `home.nix` edit for the zsh option, and a rebuild with a session to test afterwards. `.51` is ahead because its nixpkgs pin is newer, which is also why it has 0.87.1.
Three options, my recommendation first:
1. **Leave `.13`/`.27` on 0.82.1 for now.** They work, and the harness is tested against them.
2. **Pin only Pi** to a newer version with a small overlay, leaving everything else alone — a contained change I can prepare and dry-run.
3. **Full lock bump plus the `initContent` fix**, tested on `.13` first. Biggest change, most churn.
Committed as `08a4b4e` and pushed. Which of the three for Pi, and do you want me to walk the tests with you as you run them?
## Evidence
- Confidence: 80%
- Reason: Concrete host versions, exact migration error, and non-obvious conclusion about what a lock bump yields.; enriched with final-answer detail because persistence should be reusable
---
## Update (2026-11-11 22:37:01)
## Structural/configuration observations (2026-11-11 22:37:01)
Steps below, and the dry runs are done.
## Test 1 — a project that does not exist yet
```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"
```
Then **one command**:
```sh
cd ~/paseo/projects/paperclip-harness
bin/office ~/paseo/projects/test-alpha --new "test-alpha"
```
`--new` is new tonight: it creates the Paperclip project, its workspace and the task-worktree policy, then writes `.harness/`, creates the session and builds all eight panes. Expected:
```
project: test-alpha created (…)
folder: /home/sam/paseo/projects/test-alpha
session: test-alpha
wrote …/.harness/harness.toml
wrote …/.harness/check.sh
wrote …/.harness/NOTES.md
board created Board
… eight panes
```
Then, in TUIOS's session switcher (or `tuios attach test-alpha`):
1. `Repair>repair` — every check passes.
2. `Shell>shell` — the box says the folder is `…/test-alpha`.
3. `Board>board` — "no tasks in this project".
4. Press `R` once — all eight panes come back, still on `test-alpha`.
Then one task end to end: `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.`, no blocker, no command, assign `yes`. Watch it in `Board` then `Agents>agents` (`)` to runs, `↑`, `Enter` for the log). Then `Work>work`: `change` shows one file, `v` starts a review, `m` asks and then merges with `y`.
**Pass:** the file is on `main`, the task is `done`, the cost is in `Project>costs`, and nothing was typed into a terminal after step 2.
## Test 2 — a folder that already exists (this repository)
I created the Paperclip project for it already, so this is one command:
```sh
cd ~/paseo/projects/paperclip-harness
bin/office . --project harness-repo --session harness-repo
```
A separate session on purpose — the working session `paperclip-harness` shows the sandbox project and must not be rebuilt.
Then:
1. `git status --short` — **only new files under `.harness/`**. If anything existing shows as modified, stop and tell me.
2. `tuios attach harness-repo`.
3. `Project>project` → `projects` tab lists both `spike-2026-11-10` and `harness-repo` with folder and machine.
4. `Board>board` — empty; this project has no tasks.
5. 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`.
6. Watch it, read the diff in `Work>work`, and **do not merge it** — cancel it with `c` in `Board>board` and confirm with `git log` that `main` is untouched.
Both are written out in `docs/CLEAN-TESTS.md` with the expected output at each step.
## Dry runs on `.13` and `.27` for Pi
I copied `/etc/nixos` to `/tmp/nixos-dryrun`, updated the lock there, and evaluated — no system was touched.
| | locked nixpkgs | pi after update |
|---|---|---|
| `.13` | 2026-07-29 → 2026-11-07 | **1.5.0** |
| `.27` | 2026-07-29 → 2026-11-07 | **1.5.0** |
| `.51` today | 2026-09-26 | 0.87.1 |
Two things this tells us:
1. Bumping the lock does not give you 0.87.1 — it gives **1.5.0**, because nixpkgs has moved a long way.
2. On `.13` the dry-run build **fails** on a real migration:
```
programs.zsh.initExtra no longer has any effect; please remove it.
Use programs.zsh.initContent instead.
```
So aligning Pi is not a one-line change: it is a lock bump, a `home.nix` edit for the zsh option, and a rebuild with a session to test afterwards. `.51` is ahead because its nixpkgs pin is newer, which is also why it has 0.87.1.
Three options, my recommendation first:
1. **Leave `.13`/`.27` on 0.82.1 for now.** They work, and the harness is tested against them.
2. **Pin only Pi** to a newer version with a small overlay, leaving everything else alone — a contained change I can prepare and dry-run.
3. **Full lock bump plus the `initContent` fix**, tested on `.13` first. Biggest change, most churn.
Committed as `08a4b4e` and pushed. Which of the three for Pi, and do you want me to walk the tests with you as you run them?
## Source paths observed
- `nix-community/home-manager/82ce401aa350502897c3f2e85f384d61cd3b0b6d`
- `NixOS/nixpkgs/0954f7ee2f6bb3dc7d4e3d0d8bcb8fd4bde4cfc5`
- `NixOS/nixpkgs/f4a03c008967841f2a0b3cb7c436fc6fc31671f6`
- `nix/store/lslq5ihfblb905y8jazs15isad5zh97z-source/home.nix`
- `tmp/dryrun-alpha/.harness/harness.toml`
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
- `paseo/projects/test-alpha`
- `paseo/projects/paperclip-harness`
- `home/sam/paseo/projects/test-alpha`
## Evidence
- Confidence: 82%
- Reason: Captured factual repo structure/configuration patterns from rich discovery
## Related learned memories <!-- same-turn-2026-11-11 22:37:01 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin/office dry run still creates the TUIOS session and refuses on project-name mismatch]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|clean end-to-end acceptance tests for paperclip-harness (`docs/CLEAN-TESTS.md`)]]
- action: [[packs/paperclip-harness/40-actions/2026-11-11-paperclip-harness-added-new-onboarding-clean-test-doc-and-pi|paperclip-harness: added `--new` onboarding, clean-test doc, and Pi dry-run analysis; pushed 08a4b4e]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-new-existing-dry-runs-clean-test-plan-pi-v|paperclip-harness: --new/--existing dry runs, clean test plan, Pi version dry-run on .13/.27]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-root-2026-11-11-22-37-01|Rich discovery: root 2026-11-11 22:37:01]]
- context: [[packs/paperclip-harness/20-context/paperclip-harness|root]]

View File

@@ -1296,3 +1296,42 @@ Committed as `d2cf643` and pushed to Gitea.
- 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]] - 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]] - 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.]] - context: [[packs/paperclip-harness/20-context/home|link.]]
---
## Update (2026-11-11 22:37:01)
Trigger: verifying a fresh install/offboarding of the paperclip-harness office after changes to `bin/office`.
Working dir: `~/paseo/projects/paperclip-harness`. Full script with expected outputs: `docs/CLEAN-TESTS.md`.
Test 1 — new project:
1. `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"`
2. `cd ~/paseo/projects/paperclip-harness && bin/office ~/paseo/projects/test-alpha --new "test-alpha"` — expect `project: test-alpha created`, `session: test-alpha`, and `wrote .../.harness/{harness.toml,check.sh,NOTES.md}` plus eight panes.
3. `tuios attach test-alpha` (or the session switcher): Repair>repair all pass; Shell>shell shows `.../test-alpha`; Board>board says no tasks; press `R` once and confirm all eight panes return still on test-alpha.
4. One task end to end: New task>new with 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.`, no blocker, no command, assign yes. Watch in Board>board then Agents>agents (`)` runs, `↑`, Enter for log). Work>work: `change` shows one file, `v` = review, `m` then `y` = merge.
Pass for Test 1: STATUS.md on `main`, task `done`, cost visible in Project>costs, nothing typed into a terminal after step 2.
Test 2 — existing repo (`paperclip-harness` itself, project already created as `harness-repo`):
1. `bin/office . --project harness-repo --session harness-repo` (separate session on purpose; do not rebuild the working `paperclip-harness` session).
2. `git status --short` — only new files under `.harness/`; anything modified existing = stop.
3. `tuios attach harness-repo`; Project>project → `projects` tab lists `spike-2026-11-10` and `harness-repo` with folder and machine; Board>board empty.
4. Task `Add a line to README`: `Add the line "tested by the harness" at the end of README.md. Change nothing else. Commit it.`, assign yes. Watch it, read diff in Work>work, then **cancel with `c` in Board>board — do not merge** — and confirm with `git log` that `main` is untouched.
Caveat: `bin/office` dry runs create the TUIOS session and need manual kill (see observation on dry-run side effects).
## Evidence
- Confidence: 80%
- Reason: Repeatable, precise validation procedure with commands, expected outputs, and pass criteria.
## Related learned memories <!-- same-turn-2026-11-11 22:37:01 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin/office dry run still creates the TUIOS session and refuses on project-name mismatch]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|clean end-to-end acceptance tests for paperclip-harness (`docs/CLEAN-TESTS.md`)]]
- action: [[packs/paperclip-harness/40-actions/2026-11-11-paperclip-harness-added-new-onboarding-clean-test-doc-and-pi|paperclip-harness: added `--new` onboarding, clean-test doc, and Pi dry-run analysis; pushed 08a4b4e]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-new-existing-dry-runs-clean-test-plan-pi-v|paperclip-harness: --new/--existing dry runs, clean test plan, Pi version dry-run on .13/.27]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-root-2026-11-11-22-37-01|Rich discovery: root 2026-11-11 22:37:01]]
- context: [[packs/paperclip-harness/20-context/paperclip-harness|root]]

View File

@@ -0,0 +1,50 @@
---
type: session
id: session.paperclip-harness.paperclip-harness-new-existing-dry-runs-clean-test-plan-pi-v
title: paperclip-harness: --new/--existing dry runs, clean test plan, Pi version dry-run on .13/.27
status: active
source_of_truth: false
freshness: current
last_reviewed: 2026-11-11
tags:
- pack/paperclip-harness
- agent-memory/session
- paperclip-harness
- bin/office
- dry-run
- tuios
- clean-tests
- nix
- pi
- nixos
---
# paperclip-harness: --new/--existing dry runs, clean test plan, Pi version dry-run on .13/.27
Discovery snapshot from a rich turn on the paperclip-harness repo (path `~/paseo/projects/paperclip-harness`, remote `https://gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`, pushed as commit `08a4b4e`, prior `d2cf643`).
Harness CLI: `bin/office <folder> --new <name>` (new tonight) creates a Paperclip project, its workspace and task-worktree policy, writes `.harness/`, creates a TUIOS session and builds eight panes. `bin/office . --project <name> --session <name>` attaches an existing project without creating one. Eight panes named: board, agents, work, new, project, shell, repair, and one more per the panel list shown in the walkthrough.
Dry-run behavior discovered: a dry run still creates the TUIOS session (it appeared in the session list and had to be killed with `Killed session 'dryrun-alpha'`), and it refused when the Paperclip project name did not match: `refused: no Paperclip project matches '(dry run)'`. Dry-run output lines: `would create a Paperclip project ...`, `would write /tmp/dryrun-alpha/.harness/harness.toml`, `would create or reuse session 'dryrun-alpha' and build eight panes there`, `dry run: nothing was written`.
Test plan written to `docs/CLEAN-TESTS.md`: Test 1 = brand-new folder (`git init -b main`, README, commit, then `bin/office ~/paseo/projects/test-alpha --new test-alpha`); pass = Repair all pass, Shell shows the right folder, Board empty, `R` restores all eight panes, then a task end-to-end producing STATUS.md on main, task done, cost visible in Project>costs, nothing typed into a terminal after step 2. Test 2 = existing repo attached as `harness-repo` in its own session (must not rebuild the working `paperclip-harness` session); pass = only new files under `.harness/`, both projects listed in Project>project, board empty, create a README task, review the diff and cancel with `c` without merging, `git log` proves main untouched.
Pi version investigation (no system touched; `/etc/nixos` copied to `/tmp/nixos-dryrun`): host `.13` nixpkgs lock 2026-07-29 → 2026-11-07 yields pi **1.5.0**; same for `.27`; host `.51` is on a 2026-09-26 pin and has pi 0.87.1, so .51 is ahead, not a target to copy. Bumping the lock does not give 0.87.1. On `.13` the dry-run build fails on a real migration: `programs.zsh.initExtra no longer has any effect; please remove it. Use programs.zsh.initContent instead.` Options presented: (1, recommended) leave .13/.27 on 0.82.1 since they work and the harness is tested against them; (2) pin only Pi to a newer version via a small overlay, contained and dry-runnable; (3) full lock bump plus `initContent` fix tested on .13 first. Open question awaiting the user: which option, and whether to walk the clean tests together.
## Evidence
- Confidence: 85%
- Reason: Rich discovery snapshot with concrete CLI behavior, test plan, host versions, and an open decision; useful context for a future agent.
## Related
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
## Related learned memories <!-- same-turn-2026-11-11 22:37:01 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin/office dry run still creates the TUIOS session and refuses on project-name mismatch]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|clean end-to-end acceptance tests for paperclip-harness (`docs/CLEAN-TESTS.md`)]]
- action: [[packs/paperclip-harness/40-actions/2026-11-11-paperclip-harness-added-new-onboarding-clean-test-doc-and-pi|paperclip-harness: added `--new` onboarding, clean-test doc, and Pi dry-run analysis; pushed 08a4b4e]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-new-existing-dry-runs-clean-test-plan-pi-v|paperclip-harness: --new/--existing dry runs, clean test plan, Pi version dry-run on .13/.27]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-root-2026-11-11-22-37-01|Rich discovery: root 2026-11-11 22:37:01]]
- context: [[packs/paperclip-harness/20-context/paperclip-harness|root]]

View File

@@ -0,0 +1,147 @@
---
type: session
id: session.paperclip-harness.rich-discovery-root-2026-11-11-22-37-01
title: Rich discovery: root 2026-11-11 22:37:01
status: active
source_of_truth: false
freshness: current
last_reviewed: 2026-11-11
tags:
- pack/paperclip-harness
- agent-memory/session
- autolearn
- rich-discovery
- repo/root
---
# Rich discovery: root 2026-11-11 22:37:01
Sanitized rich discovery snapshot captured automatically from the completed turn.
## Source paths observed
- `nix-community/home-manager/82ce401aa350502897c3f2e85f384d61cd3b0b6d`
- `NixOS/nixpkgs/0954f7ee2f6bb3dc7d4e3d0d8bcb8fd4bde4cfc5`
- `NixOS/nixpkgs/f4a03c008967841f2a0b3cb7c436fc6fc31671f6`
- `nix/store/lslq5ihfblb905y8jazs15isad5zh97z-source/home.nix`
- `tmp/dryrun-alpha/.harness/harness.toml`
- `gitea.lab.audasmedia.com.au/sam/paperclip-harness.git`
- `paseo/projects/test-alpha`
- `paseo/projects/paperclip-harness`
- `home/sam/paseo/projects/test-alpha`
## Final answer snapshot
Steps below, and the dry runs are done.
## Test 1 — a project that does not exist yet
```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"
```
Then **one command**:
```sh
cd ~/paseo/projects/paperclip-harness
bin/office ~/paseo/projects/test-alpha --new "test-alpha"
```
`--new` is new tonight: it creates the Paperclip project, its workspace and the task-worktree policy, then writes `.harness/`, creates the session and builds all eight panes. Expected:
```
project: test-alpha created (…)
folder: /home/sam/paseo/projects/test-alpha
session: test-alpha
wrote …/.harness/harness.toml
wrote …/.harness/check.sh
wrote …/.harness/NOTES.md
board created Board
… eight panes
```
Then, in TUIOS's session switcher (or `tuios attach test-alpha`):
1. `Repair>repair` — every check passes.
2. `Shell>shell` — the box says the folder is `…/test-alpha`.
3. `Board>board` — "no tasks in this project".
4. Press `R` once — all eight panes come back, still on `test-alpha`.
Then one task end to end: `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.`, no blocker, no command, assign `yes`. Watch it in `Board` then `Agents>agents` (`)` to runs, `↑`, `Enter` for the log). Then `Work>work`: `change` shows one file, `v` starts a review, `m` asks and then merges with `y`.
**Pass:** the file is on `main`, the task is `done`, the cost is in `Project>costs`, and nothing was typed into a terminal after step 2.
## Test 2 — a folder that already exists (this repository)
I created the Paperclip project for it already, so this is one command:
```sh
cd ~/paseo/projects/paperclip-harness
bin/office . --project harness-repo --session harness-repo
```
A separate session on purpose — the working session `paperclip-harness` shows the sandbox project and must not be rebuilt.
Then:
1. `git status --short` — **only new files under `.harness/`**. If anything existing shows as modified, stop and tell me.
2. `tuios attach harness-repo`.
3. `Project>project` → `projects` tab lists both `spike-2026-11-10` and `harness-repo` with folder and machine.
4. `Board>board` — empty; this project has no tasks.
5. 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`.
6. Watch it, read the diff in `Work>work`, and **do not merge it** — cancel it with `c` in `Board>board` and confirm with `git log` that `main` is untouched.
Both are written out in `docs/CLEAN-TESTS.md` with the expected output at each step.
## Dry runs on `.13` and `.27` for Pi
I copied `/etc/nixos` to `/tmp/nixos-dryrun`, updated the lock there, and evaluated — no system was touched.
| | locked nixpkgs | pi after update |
|---|---|---|
| `.13` | 2026-07-29 → 2026-11-07 | **1.5.0** |
| `.27` | 2026-07-29 → 2026-11-07 | **1.5.0** |
| `.51` today | 2026-09-26 | 0.87.1 |
Two things this tells us:
1. Bumping the lock does not give you 0.87.1 — it gives **1.5.0**, because nixpkgs has moved a long way.
2. On `.13` the dry-run build **fails** on a real migration:
```
programs.zsh.initExtra no longer has any effect; please remove it.
Use programs.zsh.initContent instead.
```
So aligning Pi is not a one-line change: it is a lock bump, a `home.nix` edit for the zsh option, and a rebuild with a session to test afterwards. `.51` is ahead because its nixpkgs pin is newer, which is also why it has 0.87.1.
Three options, my recommendation first:
1. **Leave `.13`/`.27` on 0.82.1 for now.** They work, and the harness is tested against them.
2. **Pin only Pi** to a newer version with a small overlay, leaving everything else alone — a contained change I can prepare and dry-run.
3. **Full lock bump plus the `initContent` fix**, tested on `.13` first. Biggest change, most churn.
Committed as `08a4b4e` and pushed. Which of the three for Pi, and do you want me to walk the tests with you as you run them?
## 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 22:37:01 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin/office dry run still creates the TUIOS session and refuses on project-name mismatch]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|clean end-to-end acceptance tests for paperclip-harness (`docs/CLEAN-TESTS.md`)]]
- action: [[packs/paperclip-harness/40-actions/2026-11-11-paperclip-harness-added-new-onboarding-clean-test-doc-and-pi|paperclip-harness: added `--new` onboarding, clean-test doc, and Pi dry-run analysis; pushed 08a4b4e]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-new-existing-dry-runs-clean-test-plan-pi-v|paperclip-harness: --new/--existing dry runs, clean test plan, Pi version dry-run on .13/.27]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-root-2026-11-11-22-37-01|Rich discovery: root 2026-11-11 22:37:01]]
- context: [[packs/paperclip-harness/20-context/paperclip-harness|root]]

View File

@@ -2,12 +2,19 @@
"""Open a folder as a project: adopt it, remember it, build its pages. """Open a folder as a project: adopt it, remember it, build its pages.
bin/office <folder> [--project <id|urlKey|name>] [--session NAME] [--dry] bin/office <folder> [--project <id|urlKey|name>] [--session NAME] [--dry]
bin/office . # the folder you are in bin/office . # the folder you are in
bin/office <folder> --new "Name" # create the Paperclip project too
bin/office --remote <ssh-host> <folder> --project "Name" # the folder is on another machine
Adopting writes one file, <folder>/.harness/harness.toml, and nothing else. An Adopting writes <folder>/.harness/ (the project file, check.sh, NOTES.md) and
existing folder is never overwritten: what is already there stays, and only the nothing else. An existing file is never overwritten. With --new, Paperclip gets
missing file is written. Paperclip's project record is read, never created — a project for the folder, with the per-task worktree policy set; without it,
bin/office adopts a project that exists, it does not invent one. --project adopts a project that already exists.
A session is created on the daemon of the machine that runs this command, and
the panes run on that machine. A program cannot move your client to the new
session: TUIOS refuses that from a pane. Switch with TUIOS's session switcher,
or `tuios attach --host <machine> <session>`.
The machine is remembered, so the flag is stated once. Running the same command The machine is remembered, so the flag is stated once. Running the same command
on a machine that is not the recorded one is refused rather than silently on a machine that is not the recorded one is refused rather than silently
@@ -16,6 +23,7 @@ producing a second copy of the same project.
import json import json
import os import os
import shlex
import subprocess import subprocess
import sys import sys
@@ -27,21 +35,34 @@ import tuios # noqa: E402
def parse(argv): def parse(argv):
opts = {"folder": ".", "project": "", "session": "", "dry": "--dry" in argv, """Read the flags, then take what is left as the folder.
"host": "", "no_switch": "--no-switch" in argv, "new": ""}
for i, a in enumerate(argv): A flag's value is not a folder. The first version of this treated the value
if a == "--new" and i + 1 < len(argv): of --remote as the folder, which is exactly the kind of bug that only shows
opts["new"] = argv[i + 1] up when someone uses the flag.
args = [a for a in argv if not a.startswith("--")] """
if args: opts = {"folder": ".", "project": "", "session": "", "dry": False,
opts["folder"] = args[0] "host": "", "no_switch": False, "new": "", "remote": ""}
for i, a in enumerate(argv): positional = []
if a == "--project" and i + 1 < len(argv): i = 0
opts["project"] = argv[i + 1] while i < len(argv):
if a == "--session" and i + 1 < len(argv): a = argv[i]
opts["session"] = argv[i + 1] if a in ("--project", "--session", "--host", "--new", "--remote"):
if a == "--host" and i + 1 < len(argv): if i + 1 < len(argv):
opts["host"] = argv[i + 1] opts[a[2:]] = argv[i + 1]
i += 2
continue
i += 1
continue
if a == "--dry":
opts["dry"] = True
elif a == "--no-switch":
opts["no_switch"] = True
elif not a.startswith("-"):
positional.append(a)
i += 1
if positional:
opts["folder"] = positional[0]
return opts return opts
@@ -145,6 +166,34 @@ exit 0
return written return written
def run_on_remote(host, folder, opts):
"""Adopt a folder that lives on another machine, from where you are sitting.
The session has to be made by the daemon that will hold the panes, and the
panes have to run on the machine that owns the folder. So the work is done
over ssh on that machine, and only the last step — showing the session — is
the client's own business.
"""
here = os.path.dirname(os.path.abspath(__file__))
inner = [os.path.join(here, "office"), 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)
h.say("on %s: %s" % (host, cmd))
out = subprocess.run(["ssh", "-o", "StrictHostKeyChecking=accept-new", host, cmd],
capture_output=True, text=True, timeout=600)
sys.stdout.write(out.stdout)
if out.returncode != 0:
raise h.Refused(3, "the other machine refused: %s" % (out.stderr or out.stdout).strip()[:300])
h.say("")
h.say("switch to it: tuios attach --host %s %s" % (host, opts["session"] or os.path.basename(folder)))
return 0
def main(): def main():
opts = parse(sys.argv[1:]) opts = parse(sys.argv[1:])
folder = os.path.abspath(os.path.expanduser(opts["folder"])) folder = os.path.abspath(os.path.expanduser(opts["folder"]))
@@ -168,6 +217,9 @@ def main():
# so one command takes a person from a folder to a working layout. TUIOS has # 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 verb for exactly this; asking the person to run `tuios new` first was
# the step everyone forgot. # the step everyone forgot.
if opts["remote"]:
return run_on_remote(opts["remote"], folder, opts)
if opts["dry"]: if opts["dry"]:
h.say("would create a Paperclip project %r for %s" % (opts["new"] or opts["project"], folder)) 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 write %s" % os.path.join(folder, ".harness", "harness.toml"))