office: worktrees when the folder is a repository, ask before making one, refuse a folder agents cannot see

This commit is contained in:
Sam
2026-11-12 18:09:05 +11:00
parent 55085ba40a
commit f7b77f370f
11 changed files with 1821 additions and 4 deletions

View File

@@ -89,3 +89,82 @@ Committed as `3ec960e`; `docs/NEXT.md` updated with what is done and what remain
- context: [[packs/paperclip-harness/20-context/config|.config]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|.config deployment operations]]
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|.config repository structure and configuration patterns]]
---
## Update (2026-11-12 06:19:59)
## Rich discovery update (2026-11-12 06:19:59)
Fixed, and your `security` project is now running.
## What the error was
Two things, and the first hid the second.
**1. The key is not in your shell on `.27`.** `PAPERCLIP_BOARD_KEY` lives in `~/.config/environment.d/10-secrets.conf`, which systemd's user manager reads. On `.13` the session inherits it; on `.27` your terminal is started by the desktop session, which does not import `environment.d`. So the file was right there and the variable was empty.
**2. Even with the key, `office` on `.27` was aiming at the wrong machine.** The default address was `http://127.0.0.1:3100`, and Paperclip runs on `.13`. `.27` can reach it — I checked, 200 — but nothing was asking that address.
Both are fixed in the code, on the Python commands and in the Go program, so it works from a shell and from inside a pane:
- the key, the company id and the API address are read from `~/.config/environment.d/*.conf` when the environment does not have them (read only; never printed);
- if `PAPERCLIP_API_URL` is not set and `127.0.0.1:3100` does not answer, the address becomes `http://192.168.20.13:3100`.
## A third problem your command would have hit
`~/SECURITY` is **not a git repository**, and `--new` always created a project with a branch per task in a worktree. A worktree needs a repository, so every run on that project would have failed. `--new` now checks, and for a folder that is not a repository it creates a `local_path` project: the folder stays in place and a task changes the files directly. It says so when it does that.
## It is created and running
```
project security 8b33e222-8b62-40a2-950d-dbc9a3a2ffcd
source local_path cwd /home/sam/SECURITY
policy none (no worktrees: not a git repository)
session security on .27, 8 panes
panes board · work · agents · reply · new · project · repair = harness
shell = a shell
```
Attach with `tuios attach security` on `.27`.
If you would rather have a branch per task for that folder, `git init` it and re-run `office ~/SECURITY --project security`; the project keeps the folder but you would need a new one to get the worktree policy, because the policy is set when the project is created.
## Two things I noticed on `.27` while doing this
- **`tuios.service` is in `activating (auto-restart)`** — the unit keeps failing to start, while a manually started daemon (pid 1603888) is what your sessions actually live on. That is why your sessions exist at all. After a reboot the manual daemon will not be there, so this is worth fixing before you rely on `.27` surviving a restart.
- The `.27` rebuild for `~/.local/bin` on `PATH` clearly took effect, since `office` resolved by name. **`.51` still needs its rebuild** if you have not done it yet:
```sh
sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad
```
## Committed
`paperclip-harness` → `55085ba`. The updated commands are also copied to `.27` and `.51` at `~/.local/share/paperclip-harness/bin/`, with `--help` working on both.
## Source paths observed
- `paperclip-harness/tui/paperclip`
- `home/sam/SECURITY`
- `HOME/.local/share/paperclip-harness/bin/office`
- `home/sam/SECURITY/.harness/harness.toml`
- `nix/store/m15fsh578q4yplc2hi12gp5xsyn6zkq2-tuios-0.12.1/bin/tuios`
- `etc/profiles/per-user/sam/bin/tuios`
- `home/sam/.config/paperclip-harness/projects.toml`
- `home/sam/SECURITY/.harness/check.sh`
- `home/sam/SECURITY/.harness/NOTES.md`
- `.config/environment.d/10-secrets.conf`
- `.local/share/paperclip-harness/bin`
## Evidence
- Confidence: 84%
- Reason: Update component/repository context with detailed discovered structure and configuration
## Related learned memories <!-- same-turn-2026-11-12 06:19:59 -->
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-config-2026-11-12-06-19-59|Rich discovery: .config 2026-11-12 06:19:59]]
- context: [[packs/paperclip-harness/20-context/config|.config]]
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|.config repository structure and configuration patterns]]

View File

@@ -1104,3 +1104,185 @@ Backups kept next to each file: `flake.nix.bak-pi2`, `home/sam/home.nix.bak-pi2`
- session: [[packs/paperclip-harness/80-sessions/pi-1-5-0-alignment-across-three-nixos-hosts-via-pinned-nixpk|Pi 1.5.0 alignment across three NixOS hosts via pinned nixpkgs-pi input]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-nixos-2026-11-12-03-29-14|Rich discovery: NixOS 2026-11-12 03:29:14]]
- context: [[packs/paperclip-harness/20-context/home|NixOS]]
---
## Update (2026-11-12 06:28:29)
## Rich discovery update (2026-11-12 06:28:28)
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — TUIOS, its panes, and `office` inside them. Measured: the user manager holds the `PAPERCLIP` variables, and so does the shell.
**On `.27`:** your terminal is started by the desktop (ghostty from the graphical session), which is not systemd's user manager, so the file is never read on that path. Measured on `.27`:
```
systemd user manager PAPERCLIP vars : 1 ← the file was read
your shell's PAPERCLIP vars : 0 ← but the shell did not inherit it
```
The file is right there and correct. The shell simply never saw it.
**Why it never bit you before:** you had only ever run these commands on `.13` — the machine that starts terminals through systemd — or inside a TUIOS pane, which is also systemd. `.27` is the first place you typed `office` into a desktop terminal, so it is the first time the difference mattered. Nothing changed; a path you had never taken did.
Three ways to close the gap, and I have already put the least intrusive one in the code:
1. **What I did:** the commands read the secrets file themselves when the variable is missing. Works from any terminal, on any machine, with no rebuild. The Go program does the same, so panes behave too.
2. Explicit, if you prefer shells to carry it: add `source ~/.config/environment.d/10-secrets.conf` to `~/.zshrc`. Simple, but it puts secrets in every shell's environment, including child processes you may not intend.
3. Make the desktop import the user manager's environment at login (`systemctl --user import-environment` from the session start, which most compositors support declaring). This is the "proper" fix and keeps one source of truth, but it is a session-startup change on each machine.
You can check any machine in one line:
```sh
systemctl --user show-environment | grep -c PAPERCLIP # what systemd knows
env | grep -c PAPERCLIP # what your shell knows
```
If the first is non-zero and the second is zero, only the inheritance is missing.
## 4. TUIOS on `.27` — it is one daemon, plus one unit that cannot start
You read it correctly, and here is exactly what is happening.
- A daemon is **running**: PID 1603888, started **4 November at 22:49 from a ghostty terminal**, and it holds your **11 sessions**.
- The systemd user unit `tuios.service` is **enabled and tries to start a daemon every 5 seconds**. It finds the hand-started one and exits with status 1:
```
tuios[226383]: a daemon is already running (PID 1603888). Stop it with 'tuios kill-server' first, or use it as it is
tuios.service: Scheduled restart job, restart counter is at 141.
```
- So there is **one daemon and eleven sessions**, not two of anything. The unit has never succeeded — 141 attempts.
On `.13` the unit is `active` with 0 restarts, which is why the two machines behave differently: there the daemon is supervised, so it comes back after a reboot and TUIOS restores the sessions. On `.27` the daemon is not supervised — it only survives because it detached from that terminal.
**This needs no rebuild.** It needs one decision, at a moment when losing the sessions is acceptable:
```sh
tuios list-sessions # see what you would lose (11 today)
tuios kill-server # stop the hand-started daemon
systemctl --user restart tuios.service
systemctl --user status tuios.service # should be active, restarts 0
```
After that the unit owns the daemon, it starts at login, and the retry loop stops. Do it when you are not in the middle of something on `.27` — the `security` session I just created lives in that daemon and will go away with it.
The rebuilds you still owe are unrelated:
```sh
# .51 only, if you have not done it yet
sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad
```
`.27` is already on the new generation, since `office` resolved by name there.
I have changed nothing since the last commit except the code you already have (`55085ba`). Say which of these you want done and I will do only that.
## Source paths observed
- `run/current-system/sw/bin/bash`
- `run/wrappers/bin`
- `home/sam/.nix-profile/bin`
- `home/sam/.config/systemd/user/tuios.service`
- `nix/store/m15fsh578q4yplc2hi12gp5xsyn6zkq2-tuios-0.12.1/bin/tuios`
- `user.slice/user-1000.slice/session-1233.scope`
- `user.slice/user-1000.slice/user`
- `1000.service/app.slice/app-ghostty-surface-transient-4128995.scope`
- `home/sam/SECURITY`
- `home/sam/paperclip-agents/researcher`
- `home/sam/paperclip-agents/builder`
- `home/sam/paperclip-agents`
- `.local/share/paperclip-harness/bin`
- `folder/.paperclip/worktrees/AUD-172-`
- `folder/.paperclip/worktrees/AUD-173-`
- `.config/environment.d/10-secrets.conf`
## Evidence
- Confidence: 84%
- Reason: Update component/repository context with detailed discovered structure and configuration
## Related learned memories <!-- same-turn-2026-11-12 06:28:29 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|TUIOS on .27: hand-started daemon (PID 1603888, 11 sessions) vs retrying systemd unit]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|TUIOS .27: hand daemon → systemd-supervised daemon (no rebuild)]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip project folders should live on .13; non-git folders use local_path; commands self-read secrets …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-multi-machine-setup-program-delivery-git-w|Paperclip harness multi-machine setup: program delivery, git worktrees vs local_path, env var inheritance …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-cannot-2026-11-12-06-28-28|Rich discovery: cannot 2026-11-12 06:28:28]]
- context: [[packs/paperclip-harness/20-context/home|cannot]]

View File

@@ -524,3 +524,28 @@ Alternatives considered: bumping the shared system nixpkgs (rejected — broke `
- session: [[packs/paperclip-harness/80-sessions/pi-1-5-0-alignment-across-three-nixos-hosts-via-pinned-nixpk|Pi 1.5.0 alignment across three NixOS hosts via pinned nixpkgs-pi input]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-nixos-2026-11-12-03-29-14|Rich discovery: NixOS 2026-11-12 03:29:14]]
- context: [[packs/paperclip-harness/20-context/home|NixOS]]
---
## Update (2026-11-12 06:28:29)
Decision: (a) Keep Paperclip project folders on `.13`, the machine that serves Paperclip and runs pi agents; other machines are for viewing sessions via `office --host`. (b) `--new` now chooses `local_path` projects when the target folder is not a git repository (was previously always worktree, which would fail at first step); worktree remains the right choice for parallel/review/merge. (c) Harness commands and the Go program read the secrets file themselves when PAPERCLIP env vars are absent, so behavior is identical across systemd-launched and desktop-launched terminals.
Context: user asked whether harness should be on other machines; found `/home/Sam/SECURITY` on `.27` broke agent tasks on `.13`; env inheritance differed per machine.
Alternatives considered: second Paperclip on `.27` (deferred, real project); sshfs/NFS mount (rejected as extra moving part that fails quietly); sourcing secrets in `.zshrc` (rejected: leaks secrets into every child); `systemctl --user import-environment` at session start (deferred, per-machine session change).
Consequences: panes and agent work agree on `.13`; non-git folders work in single-task mode but lose diff/review/merge; secrets file read adds a fallback path.
Follow-up: consider making `office` warn/refuse when folder's machine != Paperclip machine; decide the `.27` TUIOS supervision switch separately.
## Evidence
- Confidence: 85%
- Reason: Explicit architectural choices with rationale and alternatives that shape future project setup.
## Related learned memories <!-- same-turn-2026-11-12 06:28:29 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|TUIOS on .27: hand-started daemon (PID 1603888, 11 sessions) vs retrying systemd unit]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|TUIOS .27: hand daemon → systemd-supervised daemon (no rebuild)]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip project folders should live on .13; non-git folders use local_path; commands self-read secrets …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-multi-machine-setup-program-delivery-git-w|Paperclip harness multi-machine setup: program delivery, git worktrees vs local_path, env var inheritance …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-cannot-2026-11-12-06-28-28|Rich discovery: cannot 2026-11-12 06:28:28]]
- context: [[packs/paperclip-harness/20-context/home|cannot]]

View File

@@ -5609,3 +5609,501 @@ Backups kept as `home/sam/home.nix.bak-path` on both, if you want to see the exa
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Rebuild .27 and .51 after adding ~/.local/bin to home-manager PATH]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Added ~/.local/bin to PATH on .27/.51 and committed; .13 untouched]]
- session: [[packs/paperclip-harness/80-sessions/nixos-fleet-path-fix-rollout-27-and-51-need-home-rebuild-13-|NixOS fleet PATH fix rollout: .27 and .51 need home rebuild, .13 already correct]]
---
## Update (2026-11-12 06:19:59)
## Structural/configuration observations (2026-11-12 06:19:59)
Fixed, and your `security` project is now running.
## What the error was
Two things, and the first hid the second.
**1. The key is not in your shell on `.27`.** `PAPERCLIP_BOARD_KEY` lives in `~/.config/environment.d/10-secrets.conf`, which systemd's user manager reads. On `.13` the session inherits it; on `.27` your terminal is started by the desktop session, which does not import `environment.d`. So the file was right there and the variable was empty.
**2. Even with the key, `office` on `.27` was aiming at the wrong machine.** The default address was `http://127.0.0.1:3100`, and Paperclip runs on `.13`. `.27` can reach it — I checked, 200 — but nothing was asking that address.
Both are fixed in the code, on the Python commands and in the Go program, so it works from a shell and from inside a pane:
- the key, the company id and the API address are read from `~/.config/environment.d/*.conf` when the environment does not have them (read only; never printed);
- if `PAPERCLIP_API_URL` is not set and `127.0.0.1:3100` does not answer, the address becomes `http://192.168.20.13:3100`.
## A third problem your command would have hit
`~/SECURITY` is **not a git repository**, and `--new` always created a project with a branch per task in a worktree. A worktree needs a repository, so every run on that project would have failed. `--new` now checks, and for a folder that is not a repository it creates a `local_path` project: the folder stays in place and a task changes the files directly. It says so when it does that.
## It is created and running
```
project security 8b33e222-8b62-40a2-950d-dbc9a3a2ffcd
source local_path cwd /home/sam/SECURITY
policy none (no worktrees: not a git repository)
session security on .27, 8 panes
panes board · work · agents · reply · new · project · repair = harness
shell = a shell
```
Attach with `tuios attach security` on `.27`.
If you would rather have a branch per task for that folder, `git init` it and re-run `office ~/SECURITY --project security`; the project keeps the folder but you would need a new one to get the worktree policy, because the policy is set when the project is created.
## Two things I noticed on `.27` while doing this
- **`tuios.service` is in `activating (auto-restart)`** — the unit keeps failing to start, while a manually started daemon (pid 1603888) is what your sessions actually live on. That is why your sessions exist at all. After a reboot the manual daemon will not be there, so this is worth fixing before you rely on `.27` surviving a restart.
- The `.27` rebuild for `~/.local/bin` on `PATH` clearly took effect, since `office` resolved by name. **`.51` still needs its rebuild** if you have not done it yet:
```sh
sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad
```
## Committed
`paperclip-harness` → `55085ba`. The updated commands are also copied to `.27` and `.51` at `~/.local/share/paperclip-harness/bin/`, with `--help` working on both.
## Source paths observed
- `paperclip-harness/tui/paperclip`
- `home/sam/SECURITY`
- `HOME/.local/share/paperclip-harness/bin/office`
- `home/sam/SECURITY/.harness/harness.toml`
- `nix/store/m15fsh578q4yplc2hi12gp5xsyn6zkq2-tuios-0.12.1/bin/tuios`
- `etc/profiles/per-user/sam/bin/tuios`
- `home/sam/.config/paperclip-harness/projects.toml`
- `home/sam/SECURITY/.harness/check.sh`
- `home/sam/SECURITY/.harness/NOTES.md`
- `.config/environment.d/10-secrets.conf`
- `.local/share/paperclip-harness/bin`
## Evidence
- Confidence: 82%
- Reason: Captured factual repo structure/configuration patterns from rich discovery
## Related learned memories <!-- same-turn-2026-11-12 06:19:59 -->
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-config-2026-11-12-06-19-59|Rich discovery: .config 2026-11-12 06:19:59]]
- context: [[packs/paperclip-harness/20-context/config|.config]]
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|.config repository structure and configuration patterns]]
---
## Update (2026-11-12 06:28:29)
On `.27`, TUIOS is running as a hand-started daemon: PID 1603888, started Wed Nov 4 22:49:36 2026 from a ghostty terminal, cgroup `/user.slice/user-1000.slice/user@1000.service/app.slice/app-ghostty-surface-transient-4128995.scope`, holds 11 sessions. The systemd user unit `~/.config/systemd/user/tuios.service` is enabled and ExecStart=`/nix/store/...-tuios-0.12.1/bin/tuios daemon`; it retries every ~5s and always fails with 'a daemon is already running (PID 1603888)' → status 1, restart counter 141, never succeeded. Sessions currently in that daemon include the `security` session created today. On `.13` the same unit is `active` with 0 restarts — supervised, restores sessions after reboot — which is why the two machines behave differently.
## Detailed observations from completed turn
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — T
…[truncated]…
## Evidence
- Confidence: 90%
- Reason: Concrete state observation future agents should know before touching tuios on .27.; enriched with final-answer detail because persistence should be reusable
---
## Update (2026-11-12 06:28:29)
Agents run on `.13` inside `/home/sam/paperclip-agents/<name>` (builder cwd `/home/sam/paperclip-agents/builder`, researcher cwd `/home/sam/paperclip-agents/researcher`, Hub cwd None). `/home/sam/SECURITY` exists on `.27` but not on `.13` (`ls /home/sam/SECURITY` on .13 → nothing). A project whose folder is on `.27` shows panes correctly but agent tasks are pointed at a nonexistent path → panes work, work does not. Also: `/home/sam/SECURITY` is not a git repository (`git rev-parse --is-inside-work-tree` → fatal). The `security` Paperclip project was created today as `local_path` (was going to be worktree but folder isn't a repo). Paperclip API reachability from .13 was not confirmed (grep/command exited 1 with 0 matches).
## Detailed observations from completed turn
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — T
…[truncated]…
## Evidence
- Confidence: 85%
- Reason: Factual cross-machine gap plus repo-state detail that will affect future project creation and agent task runs.; enriched with final-answer detail because persistence should be reusable
---
## Update (2026-11-12 06:28:29)
Vars in `~/.config/environment.d/*.conf` are read by the systemd user manager and inherited by everything it starts (TUIOS service, panes, commands run inside panes). A terminal launched by the desktop session (e.g. ghostty on `.27`) is NOT a child of the user manager and does not read the file. Measured: on `.13`, user manager and shell both have PAPERCLIP vars; on `.27`, user manager has 1, shell has 0 — file is fine, inheritance path is missing. Symptom only appeared on `.27` because previous use had all been on `.13` or inside TUIOS panes. Mitigation chosen: commands read the secrets file directly when the env var is absent (Go program does too). Diagnostic: `systemctl --user show-environment | grep -c PAPERCLIP` vs `env | grep -c PAPERCLIP`.
## Detailed observations from completed turn
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — T
…[truncated]…
## Evidence
- Confidence: 90%
- Reason: Durable diagnostic and root cause for a real, recurring class of bug; explains user-visible missing-keys surprise.; enriched with final-answer detail because persistence should be reusable
---
## Update (2026-11-12 06:28:29)
## Structural/configuration observations (2026-11-12 06:28:28)
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — TUIOS, its panes, and `office` inside them. Measured: the user manager holds the `PAPERCLIP` variables, and so does the shell.
**On `.27`:** your terminal is started by the desktop (ghostty from the graphical session), which is not systemd's user manager, so the file is never read on that path. Measured on `.27`:
```
systemd user manager PAPERCLIP vars : 1 ← the file was read
your shell's PAPERCLIP vars : 0 ← but the shell did not inherit it
```
The file is right there and correct. The shell simply never saw it.
**Why it never bit you before:** you had only ever run these commands on `.13` — the machine that starts terminals through systemd — or inside a TUIOS pane, which is also systemd. `.27` is the first place you typed `office` into a desktop terminal, so it is the first time the difference mattered. Nothing changed; a path you had never taken did.
Three ways to close the gap, and I have already put the least intrusive one in the code:
1. **What I did:** the commands read the secrets file themselves when the variable is missing. Works from any terminal, on any machine, with no rebuild. The Go program does the same, so panes behave too.
2. Explicit, if you prefer shells to carry it: add `source ~/.config/environment.d/10-secrets.conf` to `~/.zshrc`. Simple, but it puts secrets in every shell's environment, including child processes you may not intend.
3. Make the desktop import the user manager's environment at login (`systemctl --user import-environme
…[truncated]…
## Source paths observed
- `run/current-system/sw/bin/bash`
- `run/wrappers/bin`
- `home/sam/.nix-profile/bin`
- `home/sam/.config/systemd/user/tuios.service`
- `nix/store/m15fsh578q4yplc2hi12gp5xsyn6zkq2-tuios-0.12.1/bin/tuios`
- `user.slice/user-1000.slice/session-1233.scope`
- `user.slice/user-1000.slice/user`
- `1000.service/app.slice/app-ghostty-surface-transient-4128995.scope`
- `home/sam/SECURITY`
- `home/sam/paperclip-agents/researcher`
- `home/sam/paperclip-agents/builder`
- `home/sam/paperclip-agents`
- `.local/share/paperclip-harness/bin`
- `folder/.paperclip/worktrees/AUD-172-`
- `folder/.paperclip/worktrees/AUD-173-`
- `.config/environment.d/10-secrets.conf`
## Evidence
- Confidence: 82%
- Reason: Captured factual repo structure/configuration patterns from rich discovery
## Related learned memories <!-- same-turn-2026-11-12 06:28:29 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|TUIOS on .27: hand-started daemon (PID 1603888, 11 sessions) vs retrying systemd unit]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|TUIOS .27: hand daemon → systemd-supervised daemon (no rebuild)]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip project folders should live on .13; non-git folders use local_path; commands self-read secrets …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-multi-machine-setup-program-delivery-git-w|Paperclip harness multi-machine setup: program delivery, git worktrees vs local_path, env var inheritance …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-cannot-2026-11-12-06-28-28|Rich discovery: cannot 2026-11-12 06:28:28]]
- context: [[packs/paperclip-harness/20-context/home|cannot]]

View File

@@ -1680,3 +1680,427 @@ Troubleshooting: if `office` still isn't found, confirm wrapper exists at ~/.loc
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Rebuild .27 and .51 after adding ~/.local/bin to home-manager PATH]]
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Added ~/.local/bin to PATH on .27/.51 and committed; .13 untouched]]
- session: [[packs/paperclip-harness/80-sessions/nixos-fleet-path-fix-rollout-27-and-51-need-home-rebuild-13-|NixOS fleet PATH fix rollout: .27 and .51 need home rebuild, .13 already correct]]
---
## Update (2026-11-12 06:28:29)
Trigger: systemd user unit `tuios.service` on `.27` looping `activating (auto-restart)`, status 1, restart counter climbing (141+); a hand-started daemon (PID 1603888) is holding sessions instead.
Prerequisites: user is NOT mid-task on `.27`; accept losing sessions currently in the hand daemon (11 today, including the `security` session). No rebuild required — this is a state/ownership fix, not a code change.
Procedure:
1. `tuios list-sessions` — review what will be lost.
2. `tuios kill-server` — stop the hand-started daemon.
3. `systemctl --user restart tuios.service`.
4. `systemctl --user status tuios.service` — expect `active`, restarts 0.
Result: unit owns the daemon, starts at login, retry loop stops, sessions restore via service.
Rollback/caveat: sessions in the old daemon are gone once killed — recover from TUIOS's own session store if present; otherwise recreate. Unrelated rebuild still outstanding (only if not yet done): `sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad` on `.51`; `.27` already on new generation.
## Detailed procedure from completed turn
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — TUIOS, its panes, and `office` inside them. Measured: the user manager holds the `PAPERCLIP` variables, and so does the shell.
**On `.27`:** your terminal is started by the desktop (ghostty from the graphical session), which is not systemd's user manager, so the file is never read on that path. Measured on `.27`:
```
systemd user manager PAPERCLIP vars : 1 ← the file was read
your shell's PAPERCLIP vars : 0 ← but the shell did not inherit it
```
The file is right there and correct. The shell simply never saw it.
**Why it never bit you before:** you had only ever run these commands on `.13` — the machine that starts terminals through systemd — or inside a TUIOS pane, which is also systemd. `.27` is the first place you typed `office` into a desktop terminal, so it is the first time the difference mattered. Nothing changed; a path you had never taken did.
Three ways to close the gap, and I have already put the least intrusive one in the code:
1. **What I did:** the commands read the secrets file themselves when the variable is missing. Works from any terminal, on any machine, with no rebuild. The Go program does the same, so panes behave too.
2. Explicit, if you prefer shells to carry it: add `source ~/.config/environment.d/10-secrets.conf` to `~/.zshrc`. Simple, but it puts secrets in every shell's environment, including child processes you may not intend.
3. Make the desktop import the user manager's environment at login (`systemctl --user import-environment` from the session start, which most compositors support declaring). This is the "proper" fix and keeps one source of truth, but it is a session-startup change on each machine.
You can check any machine in one line:
```sh
systemctl --user show-environment | grep -c PAPERCLIP # what systemd knows
env | grep -c PAPERCLIP # what your shell knows
```
If the first is non-zero and the second is zero, only the inheritance is missing.
## 4. TUIOS on `.27` — it is one daemon, plus one unit that cannot start
You read it correctly, and here is exactly what is happening.
- A daemon is **running**: PID 1603888, started **4 November at 22:49 from a ghostty terminal**, and it holds your **11 sessions**.
- The systemd user unit `tuios.service` is **enabled and tries to start a daemon every 5 seconds**. It finds the hand-started one and exits with status 1:
```
tuios[226383]: a daemon is already running (PID 1603888). Stop it with 'tuios kill-server' first, or
…[truncated]…
## Evidence
- Confidence: 90%
- Reason: Concrete repeatable procedure with explicit safe/dangerous steps and caveats.; enriched with final-answer detail because persistence should be reusable
---
## Update (2026-11-12 06:28:29)
Trigger: want Work>change / Work>review / Work>merge flows and parallel-safe tasks for a folder Paperclip created as `local_path`.
Background: workwork is a git feature; `local_path` projects edit folder files directly (no isolation, diff, or merge). Project policy is fixed at creation, so you cannot edit an existing project's policy — recreate it.
Procedure:
1. `cd ~/SECURITY` (or target folder).
2. `git init -b main`.
3. `git add -A && git commit -m "security notes as they stand"`.
4. Remove/replace the existing `local_path` project; recreate with `--new` so Paperclip assigns the worktree policy.
After creation, tasks get `folder/.paperclip/worktrees/<TASK>` on branch `<TASK>` off `main`.
Prerequisite: folder must live on `.13` (machine serving Paperclip), not `.27`, or agents will point at a nonexistent path.
Fallback for one-task-at-a-time notes folders: keep `local_path` — honest and fine.
## Detailed procedure from completed turn
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — TUIOS, its panes, and `office` inside them. Measured: the user manager holds the `PAPERCLIP` variables, and so does the shell.
**On `.27`:** your terminal is started by the desktop (ghostty from the graphical session), which is not systemd's user manager, so the file is never read on that path. Measured on `.27`:
```
systemd user manager PAPERCLIP vars : 1 ← the file was read
your shell's PAPERCLIP vars : 0 ← but the shell did not inherit it
```
The file is right there and correct. The shell simply never saw it.
**Why it never bit you before:** you had only ever run these commands on `.13` — the machine that starts terminals through systemd — or inside a TUIOS pane, which is also systemd. `.27` is the first place you typed `office` into a desktop terminal, so it is the first time the difference mattered. Nothing changed; a path you had never taken did.
Three ways to close the gap, and I have already put the least intrusive one in the code:
1. **What I did:** the commands read the secrets file themselves when the variable is missing. Works from any terminal, on any machine, with no rebuild. The Go program does the same, so panes behave too.
2. Explicit, if you prefer shells to carry it: add `source ~/.config/environment.d/10-secrets.conf` to `~/.zshrc`. Simple, but it puts secrets in every shell's environment, including child processes you may not intend.
3. Make the desktop import the user manager's environment at login (`systemctl --user import-environment` from the session start, which most compositors support declaring). This is the "proper" fix and keeps one source of truth, but it is a session-startup change on each machine.
You can check any machine in one line:
```sh
systemctl --user show-environment | grep -c PAPERCLIP # what systemd knows
env | grep -c PAPERCLIP # what your shell knows
```
If the first is non-zero and the second is zero, only the inheritance is missing.
## 4. TUIOS on `.27` — it is one daemon, plus one unit that cannot start
You read it correctly, and here is exactly what is happening.
- A daemon is **running**: PID 1603888, started **4 November at 22:49 from a ghostty terminal**, and it holds your **11 sessions**.
- The systemd user unit `tuios.service` is **enabled and tries to start a daemon every 5 seconds**. It finds the hand-started one and exits with status 1:
```
tuios[226383]: a daemon is already running (PID 1603888). Stop it with 'tuios kill-server' first, or
…[truncated]…
## Evidence
- Confidence: 85%
- Reason: Actionable procedure specific to this repo/paperclip behavior, derived from a real user issue.; enriched with final-answer detail because persistence should be reusable
---
## Update (2026-11-12 06:28:29)
Trigger: command works in one terminal/machine but not another, or 'keys not in terminal'.
Steps:
1. On the affected machine: `systemctl --user show-environment | grep -c PAPERCLIP` (what systemd's user manager knows) and `env | grep -c PAPERCLIP` (what your shell knows).
2. If first non-zero, second zero: the file was read but not inherited — terminal launched by desktop, not user manager.
3. Confirm shell origin if needed: inspect parent PIDs / cgroup (ssh session scope vs `app-ghostty-*.scope`).
Remediation options (least → most invasive):
- (default, already in code) harness commands + Go program self-read the secrets file when var is missing — preferred, no rebuild.
- add `source ~/.config/environment.d/10-secrets.conf` to `~/.zshrc` — leaks secrets to every child shell.
- `systemctl --user import-environment` from session/compositor startup — proper single-source fix, per-machine change.
## Detailed procedure from completed turn
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — TUIOS, its panes, and `office` inside them. Measured: the user manager holds the `PAPERCLIP` variables, and so does the shell.
**On `.27`:** your terminal is started by the desktop (ghostty from the graphical session), which is not systemd's user manager, so the file is never read on that path. Measured on `.27`:
```
systemd user manager PAPERCLIP vars : 1 ← the file was read
your shell's PAPERCLIP vars : 0 ← but the shell did not inherit it
```
The file is right there and correct. The shell simply never saw it.
**Why it never bit you before:** you had only ever run these commands on `.13` — the machine that starts terminals through systemd — or inside a TUIOS pane, which is also systemd. `.27` is the first place you typed `office` into a desktop terminal, so it is the first time the difference mattered. Nothing changed; a path you had never taken did.
Three ways to close the gap, and I have already put the least intrusive one in the code:
1. **What I did:** the commands read the secrets file themselves when the variable is missing. Works from any terminal, on any machine, with no rebuild. The Go program does the same, so panes behave too.
2. Explicit, if you prefer shells to carry it: add `source ~/.config/environment.d/10-secrets.conf` to `~/.zshrc`. Simple, but it puts secrets in every shell's environment, including child processes you may not intend.
3. Make the desktop import the user manager's environment at login (`systemctl --user import-environment` from the session start, which most compositors support declaring). This is the "proper" fix and keeps one source of truth, but it is a session-startup change on each machine.
You can check any machine in one line:
```sh
systemctl --user show-environment | grep -c PAPERCLIP # what systemd knows
env | grep -c PAPERCLIP # what your shell knows
```
If the first is non-zero and the second is zero, only the inheritance is missing.
## 4. TUIOS on `.27` — it is one daemon, plus one unit that cannot start
You read it correctly, and here is exactly what is happening.
- A daemon is **running**: PID 1603888, started **4 November at 22:49 from a ghostty terminal**, and it holds your **11 sessions**.
- The systemd user unit `tuios.service` is **enabled and tries to start a daemon every 5 seconds**. It finds the hand-started one and exits with status 1:
```
tuios[226383]: a daemon is already running (PID 1603888). Stop it with 'tuios kill-server' first, or
…[truncated]…
## Evidence
- Confidence: 85%
- Reason: Compact reusable diagnostic + remediation ladder for a recurring env-inheritance class of issue.; enriched with final-answer detail because persistence should be reusable
## Related learned memories <!-- same-turn-2026-11-12 06:28:29 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|TUIOS on .27: hand-started daemon (PID 1603888, 11 sessions) vs retrying systemd unit]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|TUIOS .27: hand daemon → systemd-supervised daemon (no rebuild)]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip project folders should live on .13; non-git folders use local_path; commands self-read secrets …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-multi-machine-setup-program-delivery-git-w|Paperclip harness multi-machine setup: program delivery, git worktrees vs local_path, env var inheritance …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-cannot-2026-11-12-06-28-28|Rich discovery: cannot 2026-11-12 06:28:28]]
- context: [[packs/paperclip-harness/20-context/home|cannot]]

View File

@@ -0,0 +1,69 @@
---
type: session
id: session.paperclip-harness.paperclip-harness-multi-machine-setup-program-delivery-git-w
title: Paperclip harness multi-machine setup: program delivery, git worktrees vs local_path, env var inheritance …[truncated]…
status: active
source_of_truth: false
freshness: current
last_reviewed: 2026-11-12
tags:
- pack/paperclip-harness
- agent-memory/session
- paperclip-harness
- tuios
- systemd
- environment.d
- git-worktree
- local_path
- multi-machine
- pi-agents
---
# Paperclip harness multi-machine setup: program delivery, git worktrees vs local_path, env var inheritance …[truncated]…
Discovery from user Q&A about paperclip-harness across machines (.13 = sam-4screen-desktop, .27 = ?, .51 = sam-thinkpad).
Architecture split:
- Harness CODE lives in one place only: `.13`. Single checkout, single history, no drift.
- Harness PROGRAM (built bin/ + Go binary) must be present on every machine that *shows* panes, because a pane runs on the machine owning the folder.
- Paperclip + pi agents live on `.13`. Paperclip spawns `pi` locally in `/home/sam/paperclip-agents/<agent>`.
Program delivery to laptop/other hosts: `office ... --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` and places a short `office` shim on PATH. Copy refreshes on every use, no manual install. DO NOT keep a second editable checkout on the laptop — treat `~/.local/share` copy as delivery-only, not a workspace. To change harness from laptop: clone, edit, push; next `--host` run picks up new build.
Gotcha / limitation: `/home/sam/SECURITY` exists only on `.27`, NOT on `.13`. Paperclip agents run on `.13` (builder cwd=`/home/sam/paperclip-agents/builder`, researcher cwd=`/home/sam/paperclip-agents/researcher`), so a project folder on `.27` shows panes but agent tasks point at a nonexistent `.13` path. Mitigation options ranked: (1) keep project folders on `.13` (simplest, current pattern), (2) keep folder on `.13` and ssh-edit from `.27`, (3) sshfs/NFS mount .27 home onto .13, (4) run second Paperclip on `.27`. Planned guard: make `office` warn or refuse when project folder's machine != machine serving Paperclip.
Git worktrees vs local_path:
- Paperclip worktree projects create per-task dirs `folder/.paperclip/worktrees/<TASK>` on branch `<TASK>` under folder root `main` branch. Enables parallel tasks, diffs (Work>change), review (ocr), Work>merge.
- Worktree is a git feature; a non-git folder (`~/SECURITY` — `git rev-parse --is-inside-work-tree` fails) can't have one.
- `--new` previously requested worktree projects unconditionally → would fail. It now creates a `local_path` project for non-repos: files edited directly, no isolation, no diff, no merge. Fine for single-task notes folders; use a git repo if you need review/merge.
- To upgrade SECURITY: `cd ~/SECURITY && git init -b main && git add -A && git commit -m ...`, then recreate project with `--new` (policy is fixed at creation; existing project can't just be edited).
Environment variable inheritance:
- Env vars belong to the process that started your shell. `~/.config/environment.d/*.conf` is read by systemd's user manager; children (TUIOS, its panes) inherit; a desktop-launched terminal (ghostty from graphical session on `.27`) does NOT, so shell has 0 PAPERCLIP vars while user manager has 1.
- On `.13` terminals are started by TUIOS (systemd user service) so inheritance works; `.27` desktop terminal was the first non-systemd path used → first time noticed. Nothing changed.
- Fixes: (1) implemented — commands and Go program read the secrets file directly when env var missing (works any terminal/machine, no rebuild); (2) add `source ~/.config/environment.d/10-secrets.conf` to `~/.zshrc` (leaks secrets into every shell's children); (3) `systemctl --user import-environment` at session start (proper fix, per-machine session-startup change).
- Diagnostic one-liners: `systemctl --user show-environment | grep -c PAPERCLIP` (what systemd knows) vs `env | grep -c PAPERCLIP` (what shell knows). Non-zero then zero = only inheritance missing.
TUIOS on `.27`:
- Real daemon PID 1603888 started 4 Nov 22:49 from a ghostty terminal, cgroup `app-ghostty-surface-transient-*.scope`, holds 11 sessions.
- systemd user unit `tuios.service` is enabled and retrying every 5s; fails because daemon already running (`a daemon is already running (PID 1603888)`) → exit status 1, restart counter at 141, never succeeded.
- On `.13` unit is `active`, 0 restarts (supervised; restores sessions after reboot). `.27` daemon only survives because detached from terminal.
- No rebuild needed; needs one decision at a safe moment, procedure under runbook.
## Evidence
- Confidence: 90%
- Reason: Turn contains many durable architecture/architecture-gotcha details spanning delivery model, worktree semantics, env inheritance, and TUIOS supervision state; worth a session snapshot.
## Related
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
## Related learned memories <!-- same-turn-2026-11-12 06:28:29 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|TUIOS on .27: hand-started daemon (PID 1603888, 11 sessions) vs retrying systemd unit]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|TUIOS .27: hand daemon → systemd-supervised daemon (no rebuild)]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip project folders should live on .13; non-git folders use local_path; commands self-read secrets …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-multi-machine-setup-program-delivery-git-w|Paperclip harness multi-machine setup: program delivery, git worktrees vs local_path, env var inheritance …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-cannot-2026-11-12-06-28-28|Rich discovery: cannot 2026-11-12 06:28:28]]
- context: [[packs/paperclip-harness/20-context/home|cannot]]

View File

@@ -0,0 +1,201 @@
---
type: session
id: session.paperclip-harness.rich-discovery-cannot-2026-11-12-06-28-28
title: Rich discovery: cannot 2026-11-12 06:28:28
status: active
source_of_truth: false
freshness: current
last_reviewed: 2026-11-12
tags:
- pack/paperclip-harness
- agent-memory/session
- autolearn
- rich-discovery
- repo/cannot
---
# Rich discovery: cannot 2026-11-12 06:28:28
Sanitized rich discovery snapshot captured automatically from the completed turn.
## Source paths observed
- `run/current-system/sw/bin/bash`
- `run/wrappers/bin`
- `home/sam/.nix-profile/bin`
- `home/sam/.config/systemd/user/tuios.service`
- `nix/store/m15fsh578q4yplc2hi12gp5xsyn6zkq2-tuios-0.12.1/bin/tuios`
- `user.slice/user-1000.slice/session-1233.scope`
- `user.slice/user-1000.slice/user`
- `1000.service/app.slice/app-ghostty-surface-transient-4128995.scope`
- `home/sam/SECURITY`
- `home/sam/paperclip-agents/researcher`
- `home/sam/paperclip-agents/builder`
- `home/sam/paperclip-agents`
- `.local/share/paperclip-harness/bin`
- `folder/.paperclip/worktrees/AUD-172-`
- `folder/.paperclip/worktrees/AUD-173-`
- `.config/environment.d/10-secrets.conf`
## Final answer snapshot
## 1. Should the harness be on the other machines?
There are three separate things, and it helps to keep them apart.
| Thing | Where it must be | Why |
|---|---|---|
| The **code** (this repository) | one place: `.13` | one copy to edit, one history, no drift |
| The **program** (the built commands + the Go binary) | on every machine that must *show* panes | a pane runs on the machine that owns the folder, so the program must be there |
| **Paperclip** and the **agents** | `.13` | Paperclip spawns `pi` locally, in `/home/sam/paperclip-agents/<name>` |
So for the laptop: **yes, a copy of the program — and it already arrives by itself.** `office … --host sam-thinkpad` copies `bin/` to `~/.local/share/paperclip-harness/bin/` there and leaves a short `office` on `PATH`. Nothing to install by hand, and the copy is refreshed on every use, so it cannot drift.
What you should *not* do is keep a second editable checkout on the laptop. If you want to change the harness while sitting on the laptop, clone the repository, edit, push, and the next `--host` run copies the new build out. The copy on `~/.local/share` is a delivery, not a workspace.
**But there is a limit I have to be straight about, and it affects the `security` project I just made.** Agents run on `.13`. `/home/sam/SECURITY` does not exist on `.13`:
```
.13: ls /home/sam/SECURITY → nothing
Builder runs in → /home/sam/paperclip-agents/builder
```
A project whose folder is on `.27` will show its eight panes on `.27` correctly, but when you assign a task, the agent on `.13` is pointed at `/home/sam/SECURITY` and finds nothing there. So the panes work and the work does not. Four ways out, in the order I would consider them:
1. **Keep project folders on `.13`.** Then panes and agents agree, and `--host` is only for looking at a session that lives on another machine. This is the simplest and matches how the system already works.
2. Put the folder on `.13` and reach it from `.27` over ssh when you want to edit by hand.
3. Mount `.27`'s home on `.13` (sshfs or NFS) so Paperclip can see the path. One more moving part, and a mount that disappears breaks the agent quietly.
4. Run a second Paperclip on `.27`. That is a real project, not a flag.
If you want, I can make `office` refuse — or loudly warn — when the folder's machine is not the machine serving Paperclip, which is the check that would have caught this before the project was made.
## 2. The git issue, and what worktrees are actually for
A worktree is how two tasks avoid standing on each other. Paperclip gives each task its own directory and its own branch, taken from the same repository:
```
folder/ main
folder/.paperclip/worktrees/AUD-172-… branch AUD-172-…
folder/.paperclip/worktrees/AUD-173-… branch AUD-173-…
```
Each agent edits its own copy on its own branch. Nothing collides, you can look at the diff, review it, and merge one branch at a time. That is the whole flow your `Work>change`, `Work>review` and `Work>merge` panes are built around.
**A worktree is a git feature. A folder that is not a git repository cannot have one.** `~/SECURITY` is not a repository:
```
$ cd ~/SECURITY && git rev-parse --is-inside-work-tree
fatal: not a git repository
```
Before today, `--new` asked Paperclip for a worktree project anyway, so every run would have failed at the first step. It now creates a `local_path` project instead: the folder stays where it is, and a task edits those files directly.
What that costs you:
| | worktree project | `local_path` project |
|---|---|---|
| two tasks at once | isolated, no collision | can overwrite each other |
| diff to read | yes, `Work>change` | nothing to show |
| review with `ocr` | yes | nothing to review |
| merge | yes, one at a time | nothing to merge; changes are already in the folder |
So: **Pi agents do not need worktrees to run. They need them to run several tasks at once without colliding, and to give you a diff to approve.** For a notes folder where you run one task at a time, `local_path` is honest and fine. For anything you want reviewed and merged, it needs to be a repository.
If you want SECURITY done properly:
```sh
cd ~/SECURITY
git init -b main
git add -A && git commit -m "security notes as they stand"
```
and then create the project again with `--new` so it gets the worktree policy. A project's policy is set when it is created, so the existing `security` project would need replacing rather than editing.
## 3. Why the keys are in one terminal and not another
An environment variable belongs to the **process that started your shell**. Nothing more. So the question is always "who started this terminal", and the answer differs per machine.
**On `.13`:** your terminals are started by TUIOS, and TUIOS's daemon is a systemd user service. When systemd starts your user manager it reads `~/.config/environment.d/*.conf` and keeps those variables. Everything the manager starts inherits them — TUIOS, its panes, and `office` inside them. Measured: the user manager holds the `PAPERCLIP` variables, and so does the shell.
**On `.27`:** your terminal is started by the desktop (ghostty from the graphical session), which is not systemd's user manager, so the file is never read on that path. Measured on `.27`:
```
systemd user manager PAPERCLIP vars : 1 ← the file was read
your shell's PAPERCLIP vars : 0 ← but the shell did not inherit it
```
The file is right there and correct. The shell simply never saw it.
**Why it never bit you before:** you had only ever run these commands on `.13` — the machine that starts terminals through systemd — or inside a TUIOS pane, which is also systemd. `.27` is the first place you typed `office` into a desktop terminal, so it is the first time the difference mattered. Nothing changed; a path you had never taken did.
Three ways to close the gap, and I have already put the least intrusive one in the code:
1. **What I did:** the commands read the secrets file themselves when the variable is missing. Works from any terminal, on any machine, with no rebuild. The Go program does the same, so panes behave too.
2. Explicit, if you prefer shells to carry it: add `source ~/.config/environment.d/10-secrets.conf` to `~/.zshrc`. Simple, but it puts secrets in every shell's environment, including child processes you may not intend.
3. Make the desktop import the user manager's environment at login (`systemctl --user import-environment` from the session start, which most compositors support declaring). This is the "proper" fix and keeps one source of truth, but it is a session-startup change on each machine.
You can check any machine in one line:
```sh
systemctl --user show-environment | grep -c PAPERCLIP # what systemd knows
env | grep -c PAPERCLIP # what your shell knows
```
If the first is non-zero and the second is zero, only the inheritance is missing.
## 4. TUIOS on `.27` — it is one daemon, plus one unit that cannot start
You read it correctly, and here is exactly what is happening.
- A daemon is **running**: PID 1603888, started **4 November at 22:49 from a ghostty terminal**, and it holds your **11 sessions**.
- The systemd user unit `tuios.service` is **enabled and tries to start a daemon every 5 seconds**. It finds the hand-started one and exits with status 1:
```
tuios[226383]: a daemon is already running (PID 1603888). Stop it with 'tuios kill-server' first, or use it as it is
tuios.service: Scheduled restart job, restart counter is at 141.
```
- So there is **one daemon and eleven sessions**, not two of anything. The unit has never succeeded — 141 attempts.
On `.13` the unit is `active` with 0 restarts, which is why the two machines behave differently: there the daemon is supervised, so it comes back after a reboot and TUIOS restores the sessions. On `.27` the daemon is not supervised — it only survives because it detached from that terminal.
**This needs no rebuild.** It needs one decision, at a moment when losing the sessions is acceptable:
```sh
tuios list-sessions # see what you would lose (11 today)
tuios kill-server # stop the hand-started daemon
systemctl --user restart tuios.service
systemctl --user status tuios.service # should be active, restarts 0
```
After that the unit owns the daemon, it starts at login, and the retry loop stops. Do it when you are not in the middle of something on `.27` — the `security` session I just created lives in that daemon and will go away with it.
The rebuilds you still owe are unrelated:
```sh
# .51 only, if you have not done it yet
sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad
```
`.27` is already on the new generation, since `office` resolved by name there.
I have changed nothing since the last commit except the code you already have (`55085ba`). Say which of these you want done and I will do only that.
## 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 06:28:29 -->
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|TUIOS on .27: hand-started daemon (PID 1603888, 11 sessions) vs retrying systemd unit]]
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|TUIOS .27: hand daemon → systemd-supervised daemon (no rebuild)]]
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Paperclip project folders should live on .13; non-git folders use local_path; commands self-read secrets …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-multi-machine-setup-program-delivery-git-w|Paperclip harness multi-machine setup: program delivery, git worktrees vs local_path, env var inheritance …[truncated]…]]
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-cannot-2026-11-12-06-28-28|Rich discovery: cannot 2026-11-12 06:28:28]]
- context: [[packs/paperclip-harness/20-context/home|cannot]]

View File

@@ -0,0 +1,98 @@
---
type: session
id: session.paperclip-harness.rich-discovery-config-2026-11-12-06-19-59
title: Rich discovery: .config 2026-11-12 06:19:59
status: active
source_of_truth: false
freshness: current
last_reviewed: 2026-11-12
tags:
- pack/paperclip-harness
- agent-memory/session
- autolearn
- rich-discovery
- repo/config
---
# Rich discovery: .config 2026-11-12 06:19:59
Sanitized rich discovery snapshot captured automatically from the completed turn.
## Source paths observed
- `paperclip-harness/tui/paperclip`
- `home/sam/SECURITY`
- `HOME/.local/share/paperclip-harness/bin/office`
- `home/sam/SECURITY/.harness/harness.toml`
- `nix/store/m15fsh578q4yplc2hi12gp5xsyn6zkq2-tuios-0.12.1/bin/tuios`
- `etc/profiles/per-user/sam/bin/tuios`
- `home/sam/.config/paperclip-harness/projects.toml`
- `home/sam/SECURITY/.harness/check.sh`
- `home/sam/SECURITY/.harness/NOTES.md`
- `.config/environment.d/10-secrets.conf`
- `.local/share/paperclip-harness/bin`
## Final answer snapshot
Fixed, and your `security` project is now running.
## What the error was
Two things, and the first hid the second.
**1. The key is not in your shell on `.27`.** `PAPERCLIP_BOARD_KEY` lives in `~/.config/environment.d/10-secrets.conf`, which systemd's user manager reads. On `.13` the session inherits it; on `.27` your terminal is started by the desktop session, which does not import `environment.d`. So the file was right there and the variable was empty.
**2. Even with the key, `office` on `.27` was aiming at the wrong machine.** The default address was `http://127.0.0.1:3100`, and Paperclip runs on `.13`. `.27` can reach it — I checked, 200 — but nothing was asking that address.
Both are fixed in the code, on the Python commands and in the Go program, so it works from a shell and from inside a pane:
- the key, the company id and the API address are read from `~/.config/environment.d/*.conf` when the environment does not have them (read only; never printed);
- if `PAPERCLIP_API_URL` is not set and `127.0.0.1:3100` does not answer, the address becomes `http://192.168.20.13:3100`.
## A third problem your command would have hit
`~/SECURITY` is **not a git repository**, and `--new` always created a project with a branch per task in a worktree. A worktree needs a repository, so every run on that project would have failed. `--new` now checks, and for a folder that is not a repository it creates a `local_path` project: the folder stays in place and a task changes the files directly. It says so when it does that.
## It is created and running
```
project security 8b33e222-8b62-40a2-950d-dbc9a3a2ffcd
source local_path cwd /home/sam/SECURITY
policy none (no worktrees: not a git repository)
session security on .27, 8 panes
panes board · work · agents · reply · new · project · repair = harness
shell = a shell
```
Attach with `tuios attach security` on `.27`.
If you would rather have a branch per task for that folder, `git init` it and re-run `office ~/SECURITY --project security`; the project keeps the folder but you would need a new one to get the worktree policy, because the policy is set when the project is created.
## Two things I noticed on `.27` while doing this
- **`tuios.service` is in `activating (auto-restart)`** — the unit keeps failing to start, while a manually started daemon (pid 1603888) is what your sessions actually live on. That is why your sessions exist at all. After a reboot the manual daemon will not be there, so this is worth fixing before you rely on `.27` surviving a restart.
- The `.27` rebuild for `~/.local/bin` on `PATH` clearly took effect, since `office` resolved by name. **`.51` still needs its rebuild** if you have not done it yet:
```sh
sudo nixos-rebuild switch --flake /etc/nixos#sam-thinkpad
```
## Committed
`paperclip-harness` → `55085ba`. The updated commands are also copied to `.27` and `.51` at `~/.local/share/paperclip-harness/bin/`, with `--help` working on both.
## 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 06:19:59 -->
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-config-2026-11-12-06-19-59|Rich discovery: .config 2026-11-12 06:19:59]]
- context: [[packs/paperclip-harness/20-context/config|.config]]
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|.config repository structure and configuration patterns]]