493 lines
25 KiB
Markdown
493 lines
25 KiB
Markdown
# The plan, and how the interface sits on Paperclip
|
|
|
|
Written 2026-11-10, after a wrong turn: I split every workspace into three panes without
|
|
being asked, and it broke the working layout. It has been reverted. This document says what
|
|
exists, what is proposed, and which Paperclip endpoint each thing reads or writes. Nothing
|
|
here is invented: every endpoint below was called on this machine and answered.
|
|
|
|
## What is on screen today
|
|
|
|
Seven workspaces, one pane each: `Shell>shell`, `Board>board`, `Work>work`, `Reply>reply`,
|
|
`New task>new`, `Project>project`, `Repair>repair`. Inside a pane the program draws several
|
|
panels (Board draws three), and you switch focus with Tab. That is the state that works.
|
|
|
|
## Paperclip's objects, and where each one is seen
|
|
|
|
| Paperclip object | Endpoint, measured | Where it appears now |
|
|
|---|---|---|
|
|
| company | `GET /api/companies/{id}` | not shown; the id is in the project file |
|
|
| project | `GET /api/companies/{id}/projects` | `Project>project` |
|
|
| task | `GET /api/companies/{id}/issues`, `GET /api/issues/{id}` | `Board>board`, `Reply>reply` task panel |
|
|
| blockers of a task | `GET /api/issues/{id}/diagnostics/blockers` | `Board>board`, per row |
|
|
| comment thread | `GET /api/issues/{id}/comments` | `Reply>reply` |
|
|
| runs of a task | `GET /api/issues/{id}/runs` | `Work>work` |
|
|
| activity | `GET /api/issues/{id}/activity` | `Board>board` needs-you tab, `Work>work` |
|
|
| cost per task | `GET /api/issues/{id}/cost-summary` | `Board>board` detail, `Work>work` facts, `Project>project` costs |
|
|
| worktree and branch | the task's `currentExecutionWorkspace` | `Work>work` change and facts |
|
|
| agents | `GET /api/companies/{id}/agents` | `Project>project` facts and limits, by name and budget |
|
|
| **an agent's runs, company-wide** | `GET /api/companies/{id}/heartbeat-runs` | **nowhere yet** |
|
|
| **a run's log** | `GET /api/heartbeat-runs/{runId}/log` — 300 KB of JSON lines for one finished run | **nowhere yet** |
|
|
| **a run's events** | `GET /api/heartbeat-runs/{runId}/events` | **nowhere yet** |
|
|
| agent pause, resume, wake | `POST /api/agents/{id}/pause`, `/resume`, `/wakeup` | **nowhere yet** |
|
|
| agent settings | `PATCH /api/agents/{id}` — accepts `role`, `adapterConfig` (the model), `runtimeConfig` (heartbeat), `budgetMonthlyCents`, `status` | **nowhere yet** |
|
|
|
|
So the honest answer to "where do I see the Pi agents working": **you cannot, yet.** The data
|
|
is all there and the runs are already recorded — 281 of them on this instance — but no screen
|
|
shows them. That is the largest missing piece, and it is the next workspace.
|
|
|
|
## Missing: the Agents workspace
|
|
|
|
This is the one the person keeps asking for and it does not exist. Proposed as one pane, the
|
|
same shape as the others, drawing three panels with tabs:
|
|
|
|
```
|
|
Agents>agents
|
|
╭─ agents roster runs ╮
|
|
│ Campfire idle
|
|
│ ● Builder running AUD-163 started 14:12 1m 20s 1 cent
|
|
│ ● Hub idle last run 13:58
|
|
│ ● Documenter idle
|
|
╰───────────────────────────╯
|
|
```
|
|
|
|
- **roster** — every agent: name, state (`idle`, `running`, `needs input`, and Paperclip's
|
|
own status), current task if any, spend this month, budget. From
|
|
`GET /api/companies/{id}/agents`.
|
|
- **runs** — the company's run list, newest first: agent, task, state, what woke it, start,
|
|
duration, cost. From `GET /api/companies/{id}/heartbeat-runs` (281 today).
|
|
- **log** — the tail of the chosen run, from `GET /api/heartbeat-runs/{runId}/log`. This is
|
|
the closest thing to "watching Pi work": the log grows while the run is live, and
|
|
`lastOutputAt`/`lastOutputBytes` on the run say how fresh it is.
|
|
|
|
Actions, all with the user key, all reversible:
|
|
- `enter` on a run → its log in the log tab.
|
|
- `p` pause, `P` resume an agent (`POST /api/agents/{id}/pause|resume`).
|
|
- `w` wake an agent (`POST /api/agents/{id}/wakeup`).
|
|
- `e` open its settings (see below).
|
|
|
|
## Missing: working on an agent — role, model, cost
|
|
|
|
Paperclip owns these, so the interface edits Paperclip, never a local file. One more panel,
|
|
`Agents>settings`, or a tab inside `Agents>agents`:
|
|
|
|
| Field | Paperclip field | Endpoint |
|
|
|---|---|---|
|
|
| name and job title | `name`, `title` | `PATCH /api/agents/{id}` |
|
|
| role | `role` | same |
|
|
| who it reports to | `reportsTo` | same |
|
|
| model (the LLM) | `adapterConfig.model` | same, with `replaceAdapterConfig` care |
|
|
| heartbeat on/off, concurrency | `runtimeConfig.heartbeat` | same |
|
|
| monthly budget | `budgetMonthlyCents` | same |
|
|
| pause / resume | `POST /api/agents/{id}/pause`, `/resume` | separate calls |
|
|
|
|
Two rules that fall out of this and are not negotiable: a change to a model applies to that
|
|
agent's **next** run, never to one in flight; and a budget change is recorded with who
|
|
changed it, because Paperclip's audit trail is the only record we have.
|
|
|
|
## Tool panels: Lazygit, Hunk, a shell, the review
|
|
|
|
Both are installed on this machine and I verified the paths:
|
|
`/run/current-system/sw/bin/lazygit` and `/etc/profiles/per-user/sam/bin/hunk`.
|
|
|
|
They are **not** to be reimplemented. The proposal is one key in `Work>work`:
|
|
|
|
- `t` opens a chooser: `shell · lazygit · hunk · git log · ocr`.
|
|
- The chosen tool opens as a pane **in the current workspace**, beside the panel you were
|
|
reading, and takes focus.
|
|
- `q` or `esc` closes it and focus returns exactly where it was.
|
|
- Nothing is created until you ask, so the layout stays as it is today.
|
|
|
|
This is the answer to "I thought we had Lazygit and Hunk": they are installed, they are not
|
|
wired in, and wiring them in is one pane-opener plus a key.
|
|
|
|
## The review: ocr is installed and has already run
|
|
|
|
`ocr` is at `/home/sam/.local/bin/ocr`, version `open-code-review v1.13.6`. It is in the
|
|
project's `bin/merge` and `bin/review`, and it has blocked a real merge: on `AUD-165` it
|
|
reported a critical finding (`rm -rf "$HOME/tmp"` deleting `/tmp` when `HOME` is empty) and
|
|
the merge was refused. The Repair screen once said "not on the path" because a pane started
|
|
by TUIOS gets a smaller PATH than a shell; that was fixed by looking in the usual places.
|
|
|
|
Where it belongs in the interface: a **review panel inside `Work>work`**, showing the last
|
|
verdict for the chosen task, its findings, and the blocking ones in red. The merge stays a
|
|
command (`bin/merge`), because a merge is a decision with a lock, not a keystroke.
|
|
|
|
## Mouse-1 and Switch
|
|
|
|
Measured just now: **not installed** — no `mouse`, `mouse1` or `switch` binary on this
|
|
machine, and nothing obviously serving them locally. So nothing can be built on them yet
|
|
without adding software first.
|
|
|
|
Where they would fit if added: Mouse-1 is a small probability model that answers typed
|
|
questions; Switch turns a state into those questions. The honest use in this factory is
|
|
**routing and judgement that must be cheap and repeatable** — "is this task ready", "does
|
|
this comment answer the question", "which agent should take this" — rather than prose
|
|
generation. That is a later milestone, after agents and the review panel, and it needs a
|
|
decision about installing both, plus a measurement of whether they are better than the
|
|
existing cheap model already configured for agents (`omni/deepseek/deepseek-v4-flash`).
|
|
|
|
## The order I propose
|
|
|
|
1. **Agents workspace** — roster, runs, log. This is the missing view of Pi working, and it
|
|
is read-only, so it cannot break anything.
|
|
2. **Agent settings** — role, model, budget, pause/resume. First write surface aimed at
|
|
agents rather than tasks.
|
|
3. **Tool panels** — `t` opens Lazygit, Hunk, a shell, `ocr` in the current workspace.
|
|
4. **Review panel** in `Work>work` — the last verdict and its findings, beside the diff.
|
|
5. **Mouse-1 / Switch** — only after the above, and only after they are installed and
|
|
measured.
|
|
|
|
Each of the first four is one pane, one program, no change to the working layout. Nothing in
|
|
this list requires splitting workspaces again.
|
|
|
|
---
|
|
|
|
# Answers to the open questions, 2026-11-10
|
|
|
|
**Where settings are set.** `Agents>agents` has a fourth tab, **settings**, which edits the
|
|
chosen agent: role, job title, model, monthly budget, heartbeat. `enter` edits the field in
|
|
place, `esc` cancels, and `p` / `P` / `w` pause, resume and wake. Each save is one
|
|
`PATCH /api/agents/{id}` merged into that agent's existing configuration, so a model change
|
|
never wipes its folder or instructions. `Project>project` shows spend and limits read-only,
|
|
because Paperclip owns them and a second editable copy is how two screens start disagreeing.
|
|
|
|
**Spend.** Read from `cost-summary` per task (`Project>costs`, `Board>board`,
|
|
`Work>work`). The monthly budget is per agent, set in `Agents>agents` settings. There is no
|
|
company-level control on any screen yet.
|
|
|
|
**Skills for sub-agents.** Not in the interface. Paperclip has the endpoints —
|
|
`GET /api/agents/{id}/skills`, `POST /api/agents/{id}/skills/sync` with `add`, `remove` or
|
|
`replace` — so a read-only skills row is cheap and a full editor is a later step. The rule
|
|
worth keeping: an agent gets the skills its job needs and no more, which the `add`/`replace`
|
|
model already expresses.
|
|
|
|
**Where work is added.** `New task>new`, which writes a Paperclip task. A second place to
|
|
write tasks (Tuxedo, a notes file, a card board) would be a second owner for the same fact
|
|
and is exactly the failure the old project had. Personal notes are different from tasks: if
|
|
they are wanted, they belong in the project's own `.harness/NOTES.md`, and Tuxedo can read
|
|
it per project without pretending to be a task board.
|
|
|
|
**`office --host` from another machine.** Not implemented, and the runbook says why:
|
|
session creation needs a real terminal, so a person creates the session
|
|
(`tuios new --host nixos-desktop "new test project"`) and then runs `bin/office <folder>`
|
|
inside it, on the machine that owns the folder. `--host` today only records the host in the
|
|
project file. Driving `bin/office` on `.27` from `.13` would need ssh plus a remote
|
|
`bin/board`, which is a deliberate later step, not an accident.
|
|
|
|
**Seeing and switching projects.** Not built. Paperclip has the list
|
|
(`GET /api/companies/{id}/projects`); what it cannot know is which folder on which machine
|
|
each one lives in. The proposal: a small local registry of adopted projects
|
|
(`~/.config/paperclip-harness/projects.toml`: project id, folder, host, session), filled by
|
|
`bin/office`, and a `Project>projects` tab that lists them and switches by writing the
|
|
project into the current folder's `.harness/harness.toml`. A project on another machine
|
|
can only be switched to if the pane can reach it, so it would be shown as `on .27`, not
|
|
offered.
|
|
|
|
**Artifacts.** Paperclip work products: an uploaded file, a pull request, a preview URL, a
|
|
commit or a branch, attached to a task by an agent. They are inspectable records of what a
|
|
task produced. Nothing shows them yet; the natural home is a `Work>artifacts` tab listing
|
|
them with their links, read from the task's work products.
|
|
|
|
**"Workspaces" in Paperclip.** Paperclip has no workspaces. It has companies, projects,
|
|
issues (tasks), agents and runs. A *workspace* is TUIOS's word for a page; a *pane* is a
|
|
terminal inside it. When Paperclip says workspace it means a project's code folder
|
|
(`currentExecutionWorkspace`), which is the git worktree a task runs in.
|
|
|
|
**Charts.** TUIOS ships `plot` (Go), `loom` and TML. Go is the better fit here because the
|
|
panels are already Go and the data is already in memory: a spend-by-day chart in
|
|
`Project>costs` is a few dozen lines against `tuios.dev/plot`, where a TML surface would be
|
|
a second language and a second round trip. Worth doing once the functional tests pass.
|
|
|
|
**Mouse-1 and Switch.** Still not installed on this machine. Unchanged from the earlier
|
|
note: they would serve cheap repeatable judgement, later, after they are installed and
|
|
measured.
|
|
|
|
---
|
|
|
|
# Findings for the next round of decisions, 2026-11-10
|
|
|
|
Everything below was measured on this machine. Nothing here is proposed without saying so.
|
|
|
|
## Skills per agent — the API already models it
|
|
|
|
`GET /api/agents/{id}/skills` returns, for each agent:
|
|
|
|
```
|
|
mode: "persistent"
|
|
desiredSkills: ["paperclipai/paperclip/paperclip"]
|
|
entries: [
|
|
{ key: "company/<id>/obsidian-cli", runtimeName: "obsidian-cli--b74ae42966",
|
|
desired: false, managed: true, state: "stale",
|
|
sourcePath: "…/instances/default/skills/<id>/obsidian-cli",
|
|
targetPath: "/home/sam/.pi/agent/skills/obsidian-cli--b74ae42966" }
|
|
]
|
|
```
|
|
|
|
So Paperclip already models exactly what is wanted: a desired set per agent, a managed set
|
|
actually installed, and a state (`stale` today for `obsidian-cli` on `Builder`, which is
|
|
worth fixing on its own). `POST /api/agents/{id}/skills/sync` with `add`, `remove` or
|
|
`replace` sets the desired set; `replace` is the operation that means "this agent gets these
|
|
and nothing else", which is how a sub-agent's context is kept small.
|
|
|
|
Company level, there is more: `GET/POST /api/companies/{id}/skills` (the catalog),
|
|
`/skills/{id}/versions`, `/skills/{id}/audit`, and `GET/PUT /api/companies/{id}/skill-policy`
|
|
with `/skill-policy/evaluate`, which is a company-wide rule about which skills may be used.
|
|
|
|
Proposed in the interface: `Agents>agents` settings tab gains two rows — **skills** (the
|
|
desired set, read-only at first, with `add`/`remove` later) and **skill source** (company
|
|
catalog or the agent's own). A full skill browser is a later screen, not a panel.
|
|
|
|
## Memory — three different things wearing one word
|
|
|
|
| What | State here | What it does |
|
|
|---|---|---|
|
|
| **engram** | installed, `engram v1.16.1`, MCP server mode, no pi MCP entry yet | persistent memory for agents, over HTTP or MCP |
|
|
| **headroom** | running, `headroom-proxy v0.24.0`, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression enabled | compresses prompts on the way out; it is a proxy, not a store |
|
|
| **pi memctx** | in use in this session | the memory gateway that injects notes into a prompt |
|
|
|
|
They are not alternatives: engram stores, headroom compresses, memctx injects. For agents,
|
|
the only lever Paperclip gives us is per-agent configuration — `adapterConfig` (the folder,
|
|
the model, the instructions bundle) and `runtimeConfig` — so memory is set per agent by
|
|
pointing that agent at the proxy or the storage it should use, not by a global switch.
|
|
|
|
Proposed: a **memory** row in `Agents>agents` settings showing which of the three that agent
|
|
uses, read from its adapter configuration; and nothing more until one agent has been run
|
|
both ways and the difference measured.
|
|
|
|
## MOUSE-1
|
|
|
|
- `MOUSE_API_KEY` **is** set in `~/.config/environment.d/10-secrets.conf` (name checked, value
|
|
never printed). `JEV_API_KEY` is set as well.
|
|
- No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
|
- The previous project already wrote the policy, in
|
|
`~/paseo/projects/tuios_coding_harness/plan/*`: MOUSE-1 is **"triage only: label, score,
|
|
route, escalate. Never a gate, never a permit"**, and explicitly ruled out for deciding a
|
|
merge or allowing a tool call, because a cheap classifier that fails open on a network
|
|
error turns a green run into a lie.
|
|
|
|
That policy is right and should be adopted unchanged. Its place in this interface, if it is
|
|
added: `Board>board` needs-you could be ordered by a MOUSE-1 score, and `Work>review` could
|
|
use it to pre-sort findings. Never the merge, never an approval.
|
|
|
|
## Lazygit
|
|
|
|
Already wired: `t` in `Board>board` or `Work>work`, then choose Lazygit. It opens beside the
|
|
pane, in the same workspace, and `q` closes it. Hunk, Yazi, Neovim, fzf, a shell and ocr are
|
|
in the same chooser.
|
|
|
|
## The old `office` command, and what ours is missing
|
|
|
|
The previous project's `office` does four things, in order:
|
|
|
|
1. makes the folder and remembers the host in `<folder>/.harness/host`;
|
|
2. runs `new-project` to write the project scaffold — `settings.toml`, one file per role,
|
|
`verify.sh`, the per-screen notes — **writing only what is missing, never overwriting**;
|
|
3. refuses to continue if the TUIOS session does not exist, and prints the exact
|
|
`tuios new <session>` line to run;
|
|
4. runs its `board` to build or repair the pages, then prints how to attach.
|
|
|
|
Ours does 1, 3 and 4 (with a different file: `.harness/harness.toml`). It does **not** do 2:
|
|
there is no scaffold, no per-role file, no `verify.sh`, no page notes. That is a real gap and
|
|
the cheapest useful one to close.
|
|
|
|
## Dashboard — the API already answers it
|
|
|
|
`GET /api/companies/{id}/dashboard` returns 1.8 KB:
|
|
|
|
```
|
|
agents: {active: 6, running: 0, paused: 0, error: 0}
|
|
tasks: {open: 8, inProgress: 0, blocked: 4, done: 147}
|
|
costs: {monthSpendCents: 11, monthBudgetCents: 0, monthUtilizationPercent: 0}
|
|
pendingApprovals: 0
|
|
budgets: {activeIncidents: 0, pendingApprovals: 0, pausedAgents: 0, pausedProjects: 0}
|
|
runActivity: [14 entries]
|
|
```
|
|
|
|
That is a whole dashboard in one call, and it is cheap enough to poll. Proposal: a
|
|
`Project>overview` panel showing those four blocks and a sparkline of `runActivity`, drawn in
|
|
Go with `tuios.dev/plot` rather than embedding Paperclip's web dashboard.
|
|
|
|
## Not doing
|
|
|
|
Artifacts, as instructed. Nothing about them will be added.
|
|
|
|
---
|
|
|
|
# Pi agents: how their configuration actually resolves
|
|
|
|
Advice only — nothing here was built. Every fact below was read from the installed code, the
|
|
config files, or the API on this machine.
|
|
|
|
## Your picker, and what it really writes
|
|
|
|
`pi-config` is an extension with five commands: `/config-add`, `/config-remove`,
|
|
`/config-list`, `/config-show`, `/config-setup`. `picker.ts` is the overlay — a filtered list
|
|
of `~/.agents/skills` and `~/.agents/extensions` showing which are active in the project and
|
|
which are active globally. The commands write **JSON**, at:
|
|
|
|
```
|
|
<project>/.pi/settings.json ← project settings (the picker's "-l" mode)
|
|
~/.pi/agent/settings.json ← global settings
|
|
```
|
|
|
|
and the shape they manipulate is a `packages` array of sources and filters:
|
|
|
|
```json
|
|
{"packages": [
|
|
"npm:pi-memctx",
|
|
{"source": "git:https://gitea.lab.audasmedia.com.au/sam/pi-config",
|
|
"extensions": ["extensions/pi-config/index.ts", "extensions/tavily-search/index.ts"]},
|
|
{"source": "/home/sam/.agents", "skills": ["nixos-workflow"], "extensions": []}
|
|
]}
|
|
```
|
|
|
|
So yes: this is a stable JSON contract, and anything that can write a file can formulate an
|
|
agent's context the way the picker does. The question is not *whether* it can be written, but
|
|
*which one Pi actually reads on a Paperclip run*.
|
|
|
|
## What Pi reads, in order
|
|
|
|
From Pi's own documentation:
|
|
|
|
- global: `~/.pi/agent/skills/`, `~/.agents/skills/`
|
|
- **project, only after the project is trusted**: `.pi/skills/`, `.agents/skills/` in the
|
|
working directory and its ancestors up to the git root
|
|
- packages and the settings `skills` array
|
|
- command line: `--skill <path>`, additive even with `--no-skills`
|
|
|
|
Settings merge the same way: user settings, then `<cwd>/.pi/settings.json`.
|
|
|
|
## What Paperclip actually runs
|
|
|
|
From `@paperclipai/adapter-pi-local`, a run is:
|
|
|
|
```
|
|
pi --mode json
|
|
--append-system-prompt <rendered system prompt>
|
|
--provider <p> --model <m> --thinking <t>
|
|
--tools read,bash,edit,write,grep,find,ls
|
|
--session /home/sam/.pi/paperclips/<timestamp>-<agentId>.jsonl
|
|
--skill <a directory Paperclip builds from that agent's desired skills>
|
|
```
|
|
|
|
and before the run it symlinks the agent's desired skills into `~/.pi/agent/skills/<runtimeName>`.
|
|
|
|
Four consequences, and they matter:
|
|
|
|
1. **Skills are already per agent** — `desiredSkills` plus `POST /api/agents/{id}/skills/sync`.
|
|
That is the supported lever, and it is what the `--skill` directory is built from.
|
|
2. **The isolation is not complete.** Injected skills are symlinked into the *shared* global
|
|
directory and are not removed when another agent runs, and Paperclip does not pass
|
|
`--no-skills`. So a skill an agent once had can remain visible to another agent.
|
|
3. **The tool list is fixed** at `read,bash,edit,write,grep,find,ls`. An agent cannot gain a
|
|
tool by being given an extension unless the adapter is changed.
|
|
4. **Project-local `.pi/settings.json` is unlikely to be honoured for Paperclip runs.** Pi only
|
|
loads project settings from a trusted path. `~/.pi/agent/trust.json` holds 14 entries and none
|
|
of them is a Paperclip worktree or `~/paperclip-agents`. Worse, a worktree path changes with
|
|
every task (`…/worktrees/AUD-165-…`), so there is nothing stable to trust.
|
|
|
|
## So what is the honest advice
|
|
|
|
- **Agent identity, instructions, model, budget, and skills: Paperclip.** Those are per-agent
|
|
already and they are what a run uses. The instructions bundle at
|
|
`~/.paperclip/instances/default/companies/<co>/agents/<id>/instructions/AGENTS.md` is the
|
|
real per-agent context control, and it is editable through the API.
|
|
- **Extensions: one global set, not per agent.** There is no per-agent extension mechanism in
|
|
this adapter. Pretending otherwise would produce agents whose behaviour depends on which one
|
|
ran last.
|
|
- **Folder-level cleverness: keep out of the critical path.** Writing `.pi/settings.json` into a
|
|
project is useful for *you* when you open Pi in that folder by hand; it is not reliable
|
|
inside a Paperclip run, because of trust and because worktrees are new paths each time.
|
|
- **If per-agent extensions are genuinely wanted**, the change is in the adapter: pass a
|
|
per-agent config directory or `--no-skills` plus an explicit set, and remove stale links.
|
|
That is a Paperclip feature, not something our terminal can arrange from outside.
|
|
|
|
## History: yes, and it is richer than the run log
|
|
|
|
- `~/.pi/paperclips/*.jsonl` — **178 files** on this machine, one per run, named
|
|
`<timestamp>-<agentId>.jsonl`, and each is the full conversation (session start, model
|
|
changes, messages).
|
|
- `GET /api/agents/{id}/task-sessions` — maps a task to its session file and working directory.
|
|
- `GET /api/heartbeat-runs/{runId}/log` — the run log already shown in `Agents>agents`.
|
|
- `GET /api/agents/{id}/runtime-state` — the agent's current runtime state.
|
|
|
|
A history panel is therefore feasible without new plumbing: list an agent's sessions from
|
|
`task-sessions`, open one, and render the JSONL transcript. That is the natural next panel
|
|
after the functional tests, and it is read-only.
|
|
|
|
---
|
|
|
|
# Correction: per-agent skills are the design, not an accident
|
|
|
|
The section above gives the wrong impression. Here is the accurate version.
|
|
|
|
## Each agent has its own skill set, and that is stored in Paperclip
|
|
|
|
`GET /api/agents/{id}/skills` returns, per agent, `desiredSkills` and the entries actually
|
|
managed for it. `Builder` had its own list; `Documenter` has another. Setting it is one call:
|
|
|
|
```
|
|
POST /api/agents/{id}/skills/sync
|
|
{ "mode": "replace" | "add" | "remove",
|
|
"desiredSkills": ["company/<id>/nixos-workflow", "paperclipai/paperclip/paperclip"] }
|
|
```
|
|
|
|
`replace` means "this agent gets exactly these". At run time the adapter builds a directory
|
|
from **that agent's** desired set and passes it as `--skill`, and symlinks those skills into
|
|
`~/.pi/agent/skills/<runtimeName>` so the run can find them. So: different agents, different
|
|
skills, no problem — this is already the supported path and it needs no picker.
|
|
|
|
The caveat I over-stated is narrow: the symlinks stay in the shared global directory after a
|
|
run, and Paperclip does not pass `--no-skills`, so a skill an agent used once can remain
|
|
discoverable by another agent afterwards. That is a leak to know about (and a good argument
|
|
for `replace` plus a periodic clean), not "one set for everybody".
|
|
|
|
Where skills come from: `GET /api/skills/available`, the company list at
|
|
`GET /api/companies/{id}/skills`, and the catalog at `GET /api/skills/catalog`. A skill there
|
|
can be assigned to any agent with the call above.
|
|
|
|
## Extensions per agent: yes, through the command
|
|
|
|
The adapter's configuration document says the agent's command defaults to `pi` and can be set
|
|
per agent:
|
|
|
|
```
|
|
adapterConfig.command defaults to "pi"
|
|
adapterConfig.env KEY=VALUE pairs
|
|
```
|
|
|
|
So an agent can be given its own wrapper:
|
|
|
|
```
|
|
~/paperclip-agents/builder/pi-wrapper.sh:
|
|
|
|
#!/bin/sh
|
|
exec pi --extension npm:pi-memctx --extension git:https://gitea…/pi-config/extensions/tavily-search/index.ts "$@"
|
|
```
|
|
|
|
and `PATCH /api/agents/{id}` with `{"adapterConfig": {…, "command": "…/pi-wrapper.sh"}}`. The
|
|
adapter appends its own arguments (`--mode json`, `--session`, `--skill`, `--tools`,
|
|
`--model`) to whatever the command is, so the wrapper is additive and cannot break the run.
|
|
`env` is the same lever for environment variables.
|
|
|
|
That is how per-agent extensions become real today: one wrapper per agent role (`builder`,
|
|
`documenter`, `reviewer`), each listing the extensions that role may use. It also gives a
|
|
place to set `--no-skills` if strict isolation is wanted, and a place to keep the tool list
|
|
deliberately small.
|
|
|
|
## History: three options, in order of fidelity
|
|
|
|
1. **Open the real Pi session in a pane.** Paperclip writes every run to
|
|
`~/.pi/paperclips/<timestamp>-<agentId>.jsonl` and starts Pi with `--session <file>`. A
|
|
pane running `pi --session <that file>` gives the actual conversation, with Pi's own
|
|
interface, and can be continued. Highest fidelity, zero new code — a tool-pane entry that
|
|
takes a file path. Two writers on one session file is the risk, so this is for sessions
|
|
that are finished, or for a deliberate hand-over.
|
|
2. **A read-only transcript panel.** Parse the JSONL and draw the messages in `Agents>agents`
|
|
as a fourth tab. Integrated, safe, no second process; less faithful than the real thing.
|
|
3. **`pi --resume`** in a tool pane, and pick the session from Pi's own list. Simplest of all,
|
|
but it makes you find the session by eye.
|
|
|
|
`GET /api/agents/{id}/task-sessions` maps task → session file and working directory, so option
|
|
1 and 2 both have a reliable index and neither needs guessing.
|