Project>project overview from the dashboard endpoint; tools chooser drawn in Board>board; docs for Shell and t
This commit is contained in:
@@ -309,3 +309,133 @@ Committed as `7f18c54`. Say which item you want first and I will build only that
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-reverted-pane-split-interface-gap-discover|Paperclip-harness — reverted pane split, interface gap discovery, and PLAN-INTERFACE roadmap]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-home-2026-11-10-05-41-48|Rich discovery: home 2026-11-10 05:41:48]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|home]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 10:01:16)
|
||||
|
||||
## Rich discovery update (2026-11-10 10:01:16)
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `home/sam/.local/bin/engram`
|
||||
- `home/sam/.config/environment.d/10-secrets.conf`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/paperclip-harness-reverted-pane-split-interface-gap-discover.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-tmp-2026-11-10-07-35-38.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-home-2026-11-10-05-41-48.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/20-context/home.md`
|
||||
- `github.com/Gentleman-Programming/engram/cmd/engram`
|
||||
- `api/skills/available`
|
||||
- `api/skills/catalog`
|
||||
- `api/skills/index`
|
||||
- `paperclipai/paperclip/paperclip`
|
||||
- `company/d4921013-e5da-4d88-8016-57d5746e2d03/obsidian-cli`
|
||||
- `home/sam/.paperclip/instances/default/skills/d4921013-e5da-4d88-8016-57d5746e2d03/obsidian-cli`
|
||||
- `home/sam/.pi/agent/skills/obsidian-`
|
||||
- `dir/.harness/host`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/82-control-room.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/83-interface.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/80-forked-plan.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/91-paperclip-or-oma.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/50-open-work.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/skills/graphify/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/skills/system-architect/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/extensions/pi-graphify/skills/graphify/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/node_modules`
|
||||
- `google/genai/dist/node/index.cjs`
|
||||
- `google/genai/dist/node/node.d.ts`
|
||||
- `home/sam/.config/systemd/user/lan-mouse.service`
|
||||
- `home/sam/.config/lan-mouse`
|
||||
- `home/sam/.config/lan-mouse/lan-mouse.pem`
|
||||
- `home/sam/.cache/lan-mouse`
|
||||
- `home/sam/.local/bin/lan-mouse-011`
|
||||
- `home/sam/.pi/agent/auth.json`
|
||||
- `home/sam/.pi/agent/mcp-cache.json`
|
||||
- `home/sam/.pi/agent/mcp.json`
|
||||
- `home/sam/.pi/agent/models.json`
|
||||
- `home/sam/.pi/agent/models-store.json`
|
||||
- `home/sam/.pi/agent/settings.json`
|
||||
- `home/sam/.pi/agent/trust.json`
|
||||
- `home/sam/.local/bin/codebase-memory-mcp`
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 84%
|
||||
- Reason: Update component/repository context with detailed discovered structure and configuration
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 10:01:16 -->
|
||||
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip per-agent skills state and sync semantics]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Adopt an existing folder into the harness with `office` (and its known scaffold gap)]]
|
||||
- decision: [[packs/paperclip-harness/50-decisions/mouse-1-restricted-to-triage-never-a-gate-or-permit|MOUSE-1 restricted to triage; never a gate or permit]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Recorded interface plan for Paperclip + TUIOS harness in docs/PLAN-INTERFACE.md]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-tuios-interface-discovery-skills-api-memory-stack-|Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tuios-harness-sam-s-coding-harness-office-board-wo|Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclipai-2026-11-10-10-01-16|Rich discovery: paperclipai 2026-11-10 10:01:16]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|paperclipai]]
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
type: context
|
||||
id: context.paperclip-harness.paperclip-tuios-harness-sam-s-coding-harness-office-board-wo
|
||||
title: Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-10
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/context
|
||||
- paperclip
|
||||
- tuios
|
||||
- harness
|
||||
- architecture
|
||||
- paths
|
||||
---
|
||||
|
||||
# Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)
|
||||
|
||||
The user's coding harness is a TUIOS-based multi-screen workspace over the Paperclip API, with old source in /home/sam/paseo/projects/tuios_coding_harness (scripts `office`, `new-project`, `board`; plan/ docs 50-open-work, 80-forked-plan, 82-control-room, 83-interface, 91-paperclip-or-oma).
|
||||
|
||||
Screens/proposals: Agents>agents (skills rows + skill source, memory row), Project>overview (dashboard summary + Go sparkline via tuios.dev/plot), Board>board (needs-you list, `t` → Lazygit), Work>work (review/findings, `t` → Lazygit).
|
||||
|
||||
`office <dir> --session <name>`: detects/remembers host in .harness/host, dry-run flag, refuses when the TUIOS session does not exist (non-interactive session creation impossible) and prints `tuios new <session>`; then invokes board to build pages. Old version additionally ran new-project to write scaffold only-what-is-missing; current version lacks this scaffold step (known gap). Attach: `tuios-gpui attach <session>` (graphical) or `tuios attach <session>`, remote via `tuios-gpui attach --host <host> <session>`.
|
||||
|
||||
Paperclip company id in this instance: d4921013-e5da-4d88-8016-57d5746e2d03; agent adapterType pi_local, mode persistent, skills materialized under /home/sam/.paperclip/instances/default/skills/<companyId>/ and targeted at /home/sam/.pi/agent/skills/. Per-agent config levers: adapterConfig, runtimeConfig. Paperclip state at discovery: 6 active agents, 8 open / 4 blocked / 147 done tasks, 0 pending approvals, month spend 11 cents.
|
||||
|
||||
Local MCP: codebase-memory and graphify-vault. Pi config repo: /home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config (skills graphify, system-architect; extension pi-graphify). Also present: ~/.config/systemd/user/lan-mouse.service, /home/sam/.local/bin/codebase-memory-mcp, relay-graphify-mcp; ~/.pi/agent/{auth,mcp,models,settings,trust}.json.
|
||||
|
||||
Artifacts feature: dropped per instruction. Last commit at time of planning: 3d31243.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 85%
|
||||
- Reason: Durable component overview with paths, environment split, screens, and integration points for the existing harness.
|
||||
|
||||
## Related
|
||||
|
||||
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 10:01:16 -->
|
||||
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip per-agent skills state and sync semantics]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Adopt an existing folder into the harness with `office` (and its known scaffold gap)]]
|
||||
- decision: [[packs/paperclip-harness/50-decisions/mouse-1-restricted-to-triage-never-a-gate-or-permit|MOUSE-1 restricted to triage; never a gate or permit]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Recorded interface plan for Paperclip + TUIOS harness in docs/PLAN-INTERFACE.md]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-tuios-interface-discovery-skills-api-memory-stack-|Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tuios-harness-sam-s-coding-harness-office-board-wo|Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclipai-2026-11-10-10-01-16|Rich discovery: paperclipai 2026-11-10 10:01:16]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|paperclipai]]
|
||||
@@ -371,3 +371,92 @@ Also field-verified that per-agent settings PATCH merges into existing config (c
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|tmp]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|tmp deployment operations]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|tmp repository structure and configuration patterns]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 10:01:16)
|
||||
|
||||
Deliverable: `docs/PLAN-INTERFACE.md` (commit `3d31243`) capturing the full interface plan: skills rows in Agents>agents (desired set + skill source, backed by existing /api/agents/{id}/skills + sync), memory row (engram/headroom/memctx), MOUSE-1 limited to triage, Project>overview panel built from /api/companies/{id}/dashboard with tuios.dev/plot sparkline, and adopting the old office scaffold (settings.toml, per-role file, verify.sh, per-screen notes) as the cheapest real gap. Lazygit confirmed already wired (`t` in Board>board / Work>work). Artifacts dropped. Validation: tree clean, eight workspaces running, no half-changes. Follow-ups: fix stale obsidian-cli on Builder; implement scaffold step in office; optionally register engram in mcp.json.
|
||||
|
||||
## Detailed deliverable from completed turn
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 90%
|
||||
- Reason: Completed deliverable with artifact path, commit, validation, and follow-ups.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 10:01:16 -->
|
||||
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip per-agent skills state and sync semantics]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Adopt an existing folder into the harness with `office` (and its known scaffold gap)]]
|
||||
- decision: [[packs/paperclip-harness/50-decisions/mouse-1-restricted-to-triage-never-a-gate-or-permit|MOUSE-1 restricted to triage; never a gate or permit]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Recorded interface plan for Paperclip + TUIOS harness in docs/PLAN-INTERFACE.md]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-tuios-interface-discovery-skills-api-memory-stack-|Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tuios-harness-sam-s-coding-harness-office-board-wo|Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclipai-2026-11-10-10-01-16|Rich discovery: paperclipai 2026-11-10 10:01:16]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|paperclipai]]
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
type: decision
|
||||
id: decision.paperclip-harness.mouse-1-restricted-to-triage-never-a-gate-or-permit
|
||||
title: MOUSE-1 restricted to triage; never a gate or permit
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-10
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/decision
|
||||
- mouse-1
|
||||
- policy
|
||||
- triage
|
||||
- board
|
||||
- review
|
||||
---
|
||||
|
||||
# MOUSE-1 restricted to triage; never a gate or permit
|
||||
|
||||
Adopted the existing note policy unchanged: MOUSE-1 is triage only — label, score, route, escalate; never a gate, never a permit. Rationale: it is an external service (key + network hop, unproven product) and fails open on network errors, so a green run would be misleading if it gated merges or approvals. Permitted future uses: ordering Board>board's needs-you list, pre-sorting findings in Work>review. Consequences: no MOUSE-1 calls in merge/approval/tool-permission paths; MOUSE_API_KEY/JEV_API_KEY env names exist but no mouse/jev/switch binaries installed. Review caveat: revisit only after measured reliability evidence.
|
||||
|
||||
## Detailed decision context from completed turn
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 90%
|
||||
- Reason: Architectural/policy convention with rationale and explicit boundaries.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
## Related
|
||||
|
||||
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 10:01:16 -->
|
||||
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip per-agent skills state and sync semantics]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Adopt an existing folder into the harness with `office` (and its known scaffold gap)]]
|
||||
- decision: [[packs/paperclip-harness/50-decisions/mouse-1-restricted-to-triage-never-a-gate-or-permit|MOUSE-1 restricted to triage; never a gate or permit]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Recorded interface plan for Paperclip + TUIOS harness in docs/PLAN-INTERFACE.md]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-tuios-interface-discovery-skills-api-memory-stack-|Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tuios-harness-sam-s-coding-harness-office-board-wo|Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclipai-2026-11-10-10-01-16|Rich discovery: paperclipai 2026-11-10 10:01:16]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|paperclipai]]
|
||||
@@ -1304,3 +1304,188 @@ Committed as `7b12b45`. Say go and I run that list end to end and report each re
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|tmp]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|tmp deployment operations]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|tmp repository structure and configuration patterns]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 10:01:16)
|
||||
|
||||
`GET /api/agents/{id}/skills` returns supported/mode, desiredSkills + desiredSkillEntries (key/versionId), and entries[] with key, runtimeName, versionId, currentVersionId, desired, managed, state, sourcePath, targetPath.
|
||||
|
||||
Observed on agent Builder (adapterType pi_local, mode persistent): desired=[`paperclipai/paperclip/paperclip`]; entry `company/d4921013-e5da-4d88-8016-57d5746e2d03/obsidian-cli` has desired=false, managed=true, state=`stale`, runtimeName `obsidian-cli--b74ae42966`, sourcePath under /home/sam/.paperclip/instances/default/skills/<companyId>/obsidian-cli, targetPath under /home/sam/.pi/agent/skills/.
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` supports add / remove / replace; `replace` gives an exclusive skill set (keeps sub-agent context small).
|
||||
|
||||
Company-level skill management surface: /api/companies/{companyId}/skills (GET,POST, /{skillId} GET/PATCH/DELETE), versions (GET,POST, /{versionId}), files, audit, comments, fork + fork-precheck, rename, reset, star, install-update, update-status, test-inputs, test-runs (+cancel), categories, import, install-catalog, scan-projects, browse-project; skill-policy GET/PUT/DELETE + /evaluate; skill-test-run-templates. Public: /api/skills/{index,available,catalog,catalogId,skillName}; invite-scoped /api/invites/{token}/skills/...
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 90%
|
||||
- Reason: Factual API/state discovery likely to be reused when implementing skills UI or fixing stale skills.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 10:01:16)
|
||||
|
||||
`GET /api/companies/{id}/dashboard` returns (observed 1.8 KB): agents {active, running, paused, error} = 6/0/0/0; tasks {open, inProgress, blocked, done} = 8/0/4/147; costs {monthSpendCents, monthBudgetCents, monthUtilizationPercent} = 11/0/0; pendingApprovals 0; budgets {activeIncidents, pendingApprovals, pausedAgents, pausedProjects} all 0; runActivity list of 14. Proposed UI: a Project>overview panel rendering these blocks with a Go sparkline (tuios.dev/plot) instead of embedding the web dashboard.
|
||||
|
||||
## Detailed observations from completed turn
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 90%
|
||||
- Reason: Concrete endpoint shape and counts support future Project>overview implementation.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 10:01:16)
|
||||
|
||||
Three complementary memory mechanisms: (a) engram v1.16.1 installed in MCP mode but NOT registered in ~/.pi/agent/mcp.json; (b) headroom prompt-compression proxy v0.24.0 healthy at 192.168.20.13:8787 with memory backend disabled (memory check enabled=false, backend null) and compression on; (c) pi memctx, which injects notes into a prompt. Registered MCP servers at discovery: only codebase-memory and graphify-vault (both lifecycle lazy). Paperclip exposes only adapterConfig and runtimeConfig per agent, so memory choice is expressed by pointing an agent at the desired proxy/store. Proposal: a memory row in Agents>agents showing which mechanism an agent uses, pending measurement.
|
||||
|
||||
## Detailed observations from completed turn
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 85%
|
||||
- Reason: Durable operational facts about memory components and configuration gaps.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 10:01:16 -->
|
||||
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip per-agent skills state and sync semantics]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Adopt an existing folder into the harness with `office` (and its known scaffold gap)]]
|
||||
- decision: [[packs/paperclip-harness/50-decisions/mouse-1-restricted-to-triage-never-a-gate-or-permit|MOUSE-1 restricted to triage; never a gate or permit]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Recorded interface plan for Paperclip + TUIOS harness in docs/PLAN-INTERFACE.md]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-tuios-interface-discovery-skills-api-memory-stack-|Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tuios-harness-sam-s-coding-harness-office-board-wo|Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclipai-2026-11-10-10-01-16|Rich discovery: paperclipai 2026-11-10 10:01:16]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|paperclipai]]
|
||||
|
||||
@@ -101,3 +101,305 @@ Committed as `7b12b45`. Say go and I run that list end to end and report each re
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|tmp]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|tmp deployment operations]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|tmp repository structure and configuration patterns]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 10:01:16)
|
||||
|
||||
Trigger: bringing an existing git repo or folder into the TUIOS harness.
|
||||
|
||||
Procedure (`office <dir> [--session <name>] [--dry]`):
|
||||
1. Resolve host: read/write `<dir>/.harness/host`; mkdir `<dir>/.harness` if missing (dry-run prints planned actions and exits).
|
||||
2. Detect whether project is 'adopting (writing what is missing)' vs 'already a harness project'.
|
||||
3. Ensure TUIOS session exists: `timeout 20 tuios list-sessions` (strip ANSI, parse column 2) must contain the session. If absent, office prints `tuios new <session>` and exits 2 — TUIOS cannot create sessions non-interactively in this build ('Standard output is not a terminal').
|
||||
4. Run `board` with HARNESS_REPO and HARNESS_SESSION set to build/repair pages.
|
||||
5. Print attach commands: `tuios-gpui attach <session>`, `tuios attach <session>`, remote `tuios-gpui attach --host <hostname> <session>`.
|
||||
|
||||
Known gap: old office also ran `new-project` to write scaffold (settings.toml, one file per role, verify.sh, per-screen notes) only when missing; current office skips this. Safe: office/new-project never overwrite existing files. Troubleshooting: 'office: new-project failed' or 'office: board failed' indicate the respective step; re-run is idempotent.
|
||||
|
||||
## Detailed procedure from completed turn
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 85%
|
||||
- Reason: Repeatable procedure with prerequisites, exit codes, safe behavior, and the known-scaffold caveat.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 10:01:16)
|
||||
|
||||
Trigger: desired skill set for an agent changed, or a skill shows `stale`.
|
||||
|
||||
1. Inspect: `GET /api/agents/{id}/skills` — read desiredSkills, desiredSkillEntries, and entries[] (desired, managed, state, runtimeName, sourcePath, targetPath).
|
||||
2. Decide mode: `POST /api/agents/{id}/skills/sync` with add / remove, or `replace` for an exclusive set (recommended for sub-agents to keep context small).
|
||||
3. For company-level operations use `/api/companies/{companyId}/skills/...` (import, install-catalog, scan-projects, versions, audit, fork, install-update). Policy checks: `GET/PUT /api/companies/{companyId}/skill-policy` and `POST .../skill-policy/evaluate`.
|
||||
4. Verify after sync that entries show desired=true and state not `stale`.
|
||||
|
||||
Caveats: managed skills materialize from /home/sam/.paperclip/instances/default/skills/<companyId>/ into /home/sam/.pi/agent/skills/; a `stale` managed skill (e.g. obsidian-cli on Builder) needs reset/install-update, not just add. Avoid `replace` on the top-level orchestrator agent, which intentionally carries the `paperclipai/paperclip/paperclip` skill.
|
||||
|
||||
## Detailed procedure from completed turn
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 80%
|
||||
- Reason: Actionable procedure derived from concrete API behavior and observed stale state.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 10:01:16)
|
||||
|
||||
## Deployment/runbook details discovered (2026-11-10 10:01:16)
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `home/sam/.local/bin/engram`
|
||||
- `home/sam/.config/environment.d/10-secrets.conf`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/paperclip-harness-reverted-pane-split-interface-gap-discover.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-tmp-2026-11-10-07-35-38.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-home-2026-11-10-05-41-48.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/20-context/home.md`
|
||||
- `github.com/Gentleman-Programming/engram/cmd/engram`
|
||||
- `api/skills/available`
|
||||
- `api/skills/catalog`
|
||||
- `api/skills/index`
|
||||
- `paperclipai/paperclip/paperclip`
|
||||
- `company/d4921013-e5da-4d88-8016-57d5746e2d03/obsidian-cli`
|
||||
- `home/sam/.paperclip/instances/default/skills/d4921013-e5da-4d88-8016-57d5746e2d03/obsidian-cli`
|
||||
- `home/sam/.pi/agent/skills/obsidian-`
|
||||
- `dir/.harness/host`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/82-control-room.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/83-interface.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/80-forked-plan.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/91-paperclip-or-oma.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/50-open-work.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/skills/graphify/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/skills/system-architect/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/extensions/pi-graphify/skills/graphify/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/node_modules`
|
||||
- `google/genai/dist/node/index.cjs`
|
||||
- `google/genai/dist/node/node.d.ts`
|
||||
- `home/sam/.config/systemd/user/lan-mouse.service`
|
||||
- `home/sam/.config/lan-mouse`
|
||||
- `home/sam/.config/lan-mouse/lan-mouse.pem`
|
||||
- `home/sam/.cache/lan-mouse`
|
||||
- `home/sam/.local/bin/lan-mouse-011`
|
||||
- `home/sam/.pi/agent/auth.json`
|
||||
- `home/sam/.pi/agent/mcp-cache.json`
|
||||
- `home/sam/.pi/agent/mcp.json`
|
||||
- `home/sam/.pi/agent/models.json`
|
||||
- `home/sam/.pi/agent/models-store.json`
|
||||
- `home/sam/.pi/agent/settings.json`
|
||||
- `home/sam/.pi/agent/trust.json`
|
||||
- `home/sam/.local/bin/codebase-memory-mcp`
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 83%
|
||||
- Reason: Extracted repeatable deploy/configuration procedure from rich discovery
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 10:01:16 -->
|
||||
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip per-agent skills state and sync semantics]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Adopt an existing folder into the harness with `office` (and its known scaffold gap)]]
|
||||
- decision: [[packs/paperclip-harness/50-decisions/mouse-1-restricted-to-triage-never-a-gate-or-permit|MOUSE-1 restricted to triage; never a gate or permit]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Recorded interface plan for Paperclip + TUIOS harness in docs/PLAN-INTERFACE.md]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-tuios-interface-discovery-skills-api-memory-stack-|Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tuios-harness-sam-s-coding-harness-office-board-wo|Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclipai-2026-11-10-10-01-16|Rich discovery: paperclipai 2026-11-10 10:01:16]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|paperclipai]]
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
type: session
|
||||
id: session.paperclip-harness.paperclip-tuios-interface-discovery-skills-api-memory-stack-
|
||||
title: Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-10
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/session
|
||||
- paperclip
|
||||
- tuios
|
||||
- skills-api
|
||||
- memory
|
||||
- mouse-1
|
||||
- dashboard
|
||||
- office-scaffold
|
||||
---
|
||||
|
||||
# Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold
|
||||
|
||||
Discovery pass recorded in `docs/PLAN-INTERFACE.md`, last commit `3d31243`.
|
||||
|
||||
1) Skills per agent: `GET /api/agents/{id}/skills` returns desired/managed sets + per-skill state. Builder currently: desired=[paperclipai/paperclip/paperclip]; company/<id>/obsidian-cli desired=false, managed=true, state="stale" (runtimeName obsidian-cli--b74ae42966, currentVersionId cf41ba39-..., sourcePath /home/sam/.paperclip/instances/default/skills/<companyId>/obsidian-cli). `POST /api/agents/{id}/skills/sync` accepts add/remove/replace (`replace` = exclusive set, keeps sub-agent context small). Full skills API surface: company skills CRUD/import/install-catalog/scan-projects/browse-project, versions, audit, comments, files, fork + fork-precheck, rename, reset, star, test-inputs, test-runs(+cancel), install-update, update-status, `GET/PUT/DELETE /api/companies/{id}/skill-policy` + `/evaluate`, skill-test-run-templates, `/api/skills/{index,available,catalog,...}`, invite-scoped skill index. Proposal: two rows in Agents>agents settings — skills (desired set, read-only first) and skill source; full browser later; fix stale obsidian-cli.
|
||||
|
||||
2) Memory is three distinct things: engram (v1.16.1 installed, MCP mode, NOT registered in ~/.pi/agent/mcp.json), headroom (v0.24.0 proxy at 192.168.20.13:8787, healthy, memory backend disabled, compression on — not a store), and pi memctx (injects notes into prompt). Only mcp servers registered: codebase-memory (/home/sam/.local/bin/codebase-memory-mcp), graphify-vault (/home/sam/.local/bin/relay-graphify-mcp), both lazy. Paperclip per-agent levers are adapterConfig/runtimeConfig. Proposal: a memory row in Agents>agents showing which of the three an agent uses, nothing more until measured.
|
||||
|
||||
3) MOUSE-1: MOUSE_API_KEY and JEV_API_KEY env names present (values not inspected); no mouse/mouse1/jev/switch binary installed. Existing notes state policy: "triage only: label, score, route, escalate. Never a gate, never a permit" — ruled out for merges/tool-call gating because it fails open on network errors. Adopted unchanged; if added, may only order Board>board needs-you list or pre-sort findings in Work>review.
|
||||
|
||||
4) Lazygit: already wired — `t` in Board>board or Work>work, opens in correct workspace, quits with `q`.
|
||||
|
||||
5) Old `office` (~/paseo/projects/tuios_coding_harness, scripts office/new-project/board): remembers host in .harness/host; runs new-project to write scaffold (settings.toml, per-role file, verify.sh, per-screen notes) only what is missing; refuses if session absent and prints exact `tuios new <session>` line (TUIOS cannot create sessions non-interactively — "Standard output is not a terminal"); then builds pages. Current office does host/refusal/pages but NO scaffold — cheapest real gap.
|
||||
|
||||
6) Dashboard: `GET /api/companies/{id}/dashboard` returns ~1.8KB: agents{active 6, running 0, paused 0, error 0}, tasks{open 8, inProgress 0, blocked 4, done 147}, costs{monthSpendCents 11, monthBudgetCents 0, utilization 0}, runActivity[14]. Proposal: Project>overview panel with those blocks + sparkline via tuios.dev/plot instead of embedding web dashboard. Artifacts explicitly dropped.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 90%
|
||||
- Reason: Rich evidence-backed discovery snapshot with concrete endpoints, component versions, paths, and proposals useful to future agents.
|
||||
|
||||
## Related
|
||||
|
||||
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 10:01:16 -->
|
||||
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip per-agent skills state and sync semantics]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Adopt an existing folder into the harness with `office` (and its known scaffold gap)]]
|
||||
- decision: [[packs/paperclip-harness/50-decisions/mouse-1-restricted-to-triage-never-a-gate-or-permit|MOUSE-1 restricted to triage; never a gate or permit]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Recorded interface plan for Paperclip + TUIOS harness in docs/PLAN-INTERFACE.md]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-tuios-interface-discovery-skills-api-memory-stack-|Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tuios-harness-sam-s-coding-harness-office-board-wo|Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclipai-2026-11-10-10-01-16|Rich discovery: paperclipai 2026-11-10 10:01:16]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|paperclipai]]
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
type: session
|
||||
id: session.paperclip-harness.rich-discovery-paperclipai-2026-11-10-10-01-16
|
||||
title: Rich discovery: paperclipai 2026-11-10 10:01:16
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-10
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/session
|
||||
- autolearn
|
||||
- rich-discovery
|
||||
- repo/paperclipai
|
||||
---
|
||||
|
||||
# Rich discovery: paperclipai 2026-11-10 10:01:16
|
||||
|
||||
Sanitized rich discovery snapshot captured automatically from the completed turn.
|
||||
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `home/sam/.local/bin/engram`
|
||||
- `home/sam/.config/environment.d/10-secrets.conf`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/paperclip-harness-reverted-pane-split-interface-gap-discover.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-tmp-2026-11-10-07-35-38.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/80-sessions/rich-discovery-home-2026-11-10-05-41-48.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups.md`
|
||||
- `home/sam/paseo/projects/paperclip-harness/.pi/memory-vault/packs/paperclip-harness/20-context/home.md`
|
||||
- `github.com/Gentleman-Programming/engram/cmd/engram`
|
||||
- `api/skills/available`
|
||||
- `api/skills/catalog`
|
||||
- `api/skills/index`
|
||||
- `paperclipai/paperclip/paperclip`
|
||||
- `company/d4921013-e5da-4d88-8016-57d5746e2d03/obsidian-cli`
|
||||
- `home/sam/.paperclip/instances/default/skills/d4921013-e5da-4d88-8016-57d5746e2d03/obsidian-cli`
|
||||
- `home/sam/.pi/agent/skills/obsidian-`
|
||||
- `dir/.harness/host`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/82-control-room.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/83-interface.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/80-forked-plan.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/91-paperclip-or-oma.md`
|
||||
- `home/sam/paseo/projects/tuios_coding_harness/plan/50-open-work.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/skills/graphify/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/skills/system-architect/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/extensions/pi-graphify/skills/graphify/SKILL.md`
|
||||
- `home/sam/.pi/agent/git/gitea.lab.audasmedia.com.au/sam/pi-config/node_modules`
|
||||
- `google/genai/dist/node/index.cjs`
|
||||
- `google/genai/dist/node/node.d.ts`
|
||||
- `home/sam/.config/systemd/user/lan-mouse.service`
|
||||
- `home/sam/.config/lan-mouse`
|
||||
- `home/sam/.config/lan-mouse/lan-mouse.pem`
|
||||
- `home/sam/.cache/lan-mouse`
|
||||
- `home/sam/.local/bin/lan-mouse-011`
|
||||
- `home/sam/.pi/agent/auth.json`
|
||||
- `home/sam/.pi/agent/mcp-cache.json`
|
||||
- `home/sam/.pi/agent/mcp.json`
|
||||
- `home/sam/.pi/agent/models.json`
|
||||
- `home/sam/.pi/agent/models-store.json`
|
||||
- `home/sam/.pi/agent/settings.json`
|
||||
- `home/sam/.pi/agent/trust.json`
|
||||
- `home/sam/.local/bin/codebase-memory-mcp`
|
||||
|
||||
## Final answer snapshot
|
||||
|
||||
Explored all of it. Recorded in `docs/PLAN-INTERFACE.md`; the short version:
|
||||
|
||||
## Skills per agent — Paperclip already models it
|
||||
|
||||
`GET /api/agents/{id}/skills` returns a desired set, a managed set and a state per skill. On `Builder` today:
|
||||
|
||||
```
|
||||
desired: ["paperclipai/paperclip/paperclip"]
|
||||
company/<id>/obsidian-cli desired: false managed: true state: "stale"
|
||||
```
|
||||
|
||||
`POST /api/agents/{id}/skills/sync` takes `add`, `remove` or **`replace`** — `replace` is exactly "this agent gets these and nothing else", which is how a sub-agent's context stays small. There is also a company skill catalog, versions, audit, and `GET/PUT /api/companies/{id}/skill-policy` with an `evaluate` call.
|
||||
|
||||
Proposal: two rows in `Agents>agents` settings — **skills** (the desired set, read-only first, add/remove later) and **skill source**. A full browser is a later screen, not a panel. Also: `obsidian-cli` sitting `stale` on Builder is worth fixing.
|
||||
|
||||
## Memory — three different things
|
||||
|
||||
| | state here | what it is |
|
||||
|---|---|---|
|
||||
| **engram** | installed, v1.16.1, MCP mode, **not** registered in `~/.pi/agent/mcp.json` (only `codebase-memory`, `graphify-vault`) | persistent memory |
|
||||
| **headroom** | running, v0.24.0, healthy at `192.168.20.13:8787`, memory backend **disabled**, compression on | a prompt-compression proxy, not a store |
|
||||
| **pi memctx** | in use now | injects notes into a prompt |
|
||||
|
||||
They are complementary. Paperclip's only per-agent lever is `adapterConfig` and `runtimeConfig`, so memory is set per agent by pointing that agent at the proxy or store it should use. Proposal: a **memory** row in `Agents>agents` settings showing which of the three that agent uses, and nothing more until one agent has run both ways and been measured.
|
||||
|
||||
## MOUSE-1
|
||||
|
||||
`MOUSE_API_KEY` is set (checked the name only, never the value). `JEV_API_KEY` too. No `mouse`, `mouse1`, `jev` or `switch` binary is installed.
|
||||
|
||||
There **are** notes, and they are good ones — in the old project's plan documents:
|
||||
|
||||
> MOUSE-1 is *"triage only: label, score, route, escalate. Never a gate, never a permit"* — explicitly ruled out for deciding a merge or allowing a tool call, because a cheap classifier that fails open on a network error makes a green run a lie.
|
||||
|
||||
I would adopt that policy unchanged. Its place, if added: ordering `Board>board`'s needs-you list, or pre-sorting findings in `Work>review`. Never the merge, never an approval.
|
||||
|
||||
## Lazygit
|
||||
|
||||
Already wired: `t` in `Board>board` or `Work>work`, choose Lazygit. Verified opening in the right workspace and closing with `q`.
|
||||
|
||||
## The old `office` — and what ours lacks
|
||||
|
||||
The previous `office` did four things: remember the host; run `new-project` to write the scaffold (`settings.toml`, a file per role, `verify.sh`, the per-screen notes) writing **only what is missing**; refuse if the session does not exist and print the exact `tuios new` line; then build the pages.
|
||||
|
||||
Ours does the host, the refusal and the pages — but **no scaffold**. No per-role files, no `verify.sh`, no page notes. That is the cheapest real gap in the whole plan.
|
||||
|
||||
## Dashboard — the API answers it in one call
|
||||
|
||||
`GET /api/companies/{id}/dashboard`, 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, utilization 0}
|
||||
runActivity [14 entries]
|
||||
```
|
||||
|
||||
Proposal: a `Project>overview` panel with those blocks and a sparkline drawn in Go with `tuios.dev/plot`, rather than embedding the web dashboard in a pane.
|
||||
|
||||
## Not doing
|
||||
|
||||
Artifacts — dropped as instructed.
|
||||
|
||||
I am ready for the task you are about to deliver; nothing in the tree is half-changed, the eight workspaces are running, and the last commit is `3d31243`.
|
||||
|
||||
## 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-10 10:01:16 -->
|
||||
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Paperclip per-agent skills state and sync semantics]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Adopt an existing folder into the harness with `office` (and its known scaffold gap)]]
|
||||
- decision: [[packs/paperclip-harness/50-decisions/mouse-1-restricted-to-triage-never-a-gate-or-permit|MOUSE-1 restricted to triage; never a gate or permit]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Recorded interface plan for Paperclip + TUIOS harness in docs/PLAN-INTERFACE.md]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-tuios-interface-discovery-skills-api-memory-stack-|Paperclip-TUIOS interface discovery: skills API, memory stack, MOUSE-1, dashboard, old office scaffold]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tuios-harness-sam-s-coding-harness-office-board-wo|Paperclip-TUIOS harness (sam's coding harness: office/board/work screens)]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclipai-2026-11-10-10-01-16|Rich discovery: paperclipai 2026-11-10 10:01:16]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|paperclipai]]
|
||||
@@ -58,12 +58,12 @@ program running in the Board workspace.
|
||||
|
||||
| Workspace>pane | shows | keys |
|
||||
|---|---|---|
|
||||
| Shell>shell | a prompt in the project folder | — |
|
||||
| Shell>shell | a prompt in the project folder: the pane that never exits, and the escape hatch for anything no panel covers | — |
|
||||
| Board>board | tasks by group · the chosen task · needs you | ↑↓ j k · enter · a · u · / · t (tools) · tab |
|
||||
| Work>work | runs · change · facts · review | [ ] tab · ↑↓ j k · g G · t (tools) |
|
||||
| Reply>reply | the task · the thread · the reply box | enter · s · esc |
|
||||
| New task>new | the form · what a task needs · what will be sent | tab · enter · ctrl+n |
|
||||
| Project>project | facts · costs · settings | [ ] tab · ↑↓ j k |
|
||||
| Project>project | overview · facts · costs · settings | [ ] tab · ↑↓ j k |
|
||||
| Repair>repair | health · layout · rebuild log | [ ] tab · ↑↓ j k · R · B |
|
||||
| Agents>agents | roster · runs · log · settings | [ ] tab · ↑↓ j k · enter · p P w · A |
|
||||
|
||||
@@ -73,7 +73,9 @@ Choosing a task on the board and pressing Enter writes it into the project's
|
||||
### Tool panes
|
||||
|
||||
`t` in `Board>board` or `Work>work` opens a chooser: shell, Lazygit, Hunk, Yazi, Neovim,
|
||||
fzf, ocr. The tool opens as a pane beside the one you are in, in the same workspace, and
|
||||
fzf, ocr. Note that TUIOS also binds `t` in **window management mode** (toggle tiling, new
|
||||
window); inside the program the pane must be in terminal mode for `t` to arrive, which is
|
||||
the normal state while you are typing in it. The tool opens as a pane beside the one you are in, in the same workspace, and
|
||||
`esc` closes the chooser. Quitting the tool (its own key) closes its pane. Nothing is added
|
||||
to the layout, so the eight workspaces stay as they are.
|
||||
|
||||
|
||||
BIN
bin/harness
BIN
bin/harness
Binary file not shown.
@@ -6,7 +6,16 @@ panels are what the pane's program draws, switched with Tab or the tab keys.
|
||||
Status: **built** means running in the project session now. **missing** means planned, not
|
||||
written yet.
|
||||
|
||||
## 1. Shell
|
||||
## 1. Shell — a plain prompt in the project folder
|
||||
|
||||
It is not a screen of the factory. It is there because some things are quicker to type than
|
||||
to click, and because every workspace needs one pane that never exits: TUIOS deletes a
|
||||
workspace whose last pane closes and renumbers the rest. It is also the fallback for a
|
||||
command no panel covers, and the place a tool pane is opened *from* when you know what you
|
||||
want.
|
||||
|
||||
There is deliberately nothing in it beyond your own shell, in the project folder, so that
|
||||
what it shows is never a second copy of anything.
|
||||
|
||||
| Pane | Shows | Status |
|
||||
|---|---|---|
|
||||
@@ -58,7 +67,7 @@ written yet.
|
||||
|
||||
| Pane | Shows | Status |
|
||||
|---|---|---|
|
||||
| `Project>project` | project, folder, machine, session, agents | built |
|
||||
| `Project>project` | overview: agents, tasks, money, run activity sparkline — then facts, costs, settings | built |
|
||||
| `Project>costs` | spend per task and the total | built |
|
||||
| `Project>settings` | the project's own file, and the limits Paperclip holds | built |
|
||||
|
||||
|
||||
16
tui/board.go
16
tui/board.go
@@ -355,6 +355,17 @@ func (m boardModel) View() string {
|
||||
m.width, m.height))
|
||||
}
|
||||
|
||||
if m.tools {
|
||||
entries := make([][2]string, 0, len(tools))
|
||||
for i, t := range tools {
|
||||
mark := " "
|
||||
if i == m.toolAt {
|
||||
mark = "▸ "
|
||||
}
|
||||
entries = append(entries, [2]string{mark + t.name, t.about})
|
||||
}
|
||||
return helpOverlay("open a tool pane here", entries, m.width, m.height)
|
||||
}
|
||||
if m.showHelp {
|
||||
return helpOverlay("keys on this panel", [][2]string{
|
||||
{"↑ ↓ j k", "choose a task"},
|
||||
@@ -517,7 +528,10 @@ func (m boardModel) treeLines(width int) []string {
|
||||
// makes the groups visible at a glance without a box around every one.
|
||||
func groupHeading(name string, count, width int) string {
|
||||
label := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color(active.Mauve)).Render(strings.ToUpper(name))
|
||||
n := lipgloss.NewStyle().Foreground(lipgloss.Color(active.Muted)).Render(fmt.Sprintf(" %d ", count))
|
||||
n := ""
|
||||
if count >= 0 {
|
||||
n = lipgloss.NewStyle().Foreground(lipgloss.Color(active.Muted)).Render(fmt.Sprintf(" %d ", count))
|
||||
}
|
||||
rule := strings.Repeat("─", max(0, width-lipgloss.Width(label)-lipgloss.Width(n)))
|
||||
return label + dimStyle().Render(rule) + n
|
||||
}
|
||||
|
||||
@@ -458,3 +458,44 @@ func (c *Client) AgentRaw(agentID string) (map[string]any, error) {
|
||||
err := c.do("GET", "/api/agents/"+agentID, nil, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Dashboard is the company's own summary: counts, spend and recent run activity.
|
||||
// One call, 1.8 KB, cheap enough to poll.
|
||||
type Dashboard struct {
|
||||
Agents struct {
|
||||
Active int `json:"active"`
|
||||
Running int `json:"running"`
|
||||
Paused int `json:"paused"`
|
||||
Error int `json:"error"`
|
||||
} `json:"agents"`
|
||||
Tasks struct {
|
||||
Open int `json:"open"`
|
||||
InProgress int `json:"inProgress"`
|
||||
Blocked int `json:"blocked"`
|
||||
Done int `json:"done"`
|
||||
} `json:"tasks"`
|
||||
Costs struct {
|
||||
MonthSpendCents int `json:"monthSpendCents"`
|
||||
MonthBudgetCents int `json:"monthBudgetCents"`
|
||||
MonthUtilizationPercent float64 `json:"monthUtilizationPercent"`
|
||||
} `json:"costs"`
|
||||
PendingApprovals int `json:"pendingApprovals"`
|
||||
Budgets struct {
|
||||
ActiveIncidents int `json:"activeIncidents"`
|
||||
PausedAgents int `json:"pausedAgents"`
|
||||
PausedProjects int `json:"pausedProjects"`
|
||||
} `json:"budgets"`
|
||||
RunActivity []struct {
|
||||
Date string `json:"date"`
|
||||
Total int `json:"total"`
|
||||
Succeeded int `json:"succeeded"`
|
||||
Failed int `json:"failed"`
|
||||
} `json:"runActivity"`
|
||||
}
|
||||
|
||||
// DashboardSummary reads the company's dashboard.
|
||||
func (c *Client) DashboardSummary() (Dashboard, error) {
|
||||
var out Dashboard
|
||||
err := c.do("GET", "/api/companies/"+c.Company+"/dashboard", nil, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
)
|
||||
|
||||
type projectMsg struct {
|
||||
dash paperclip.Dashboard
|
||||
project paperclip.Project
|
||||
cfg map[string]string
|
||||
agents []paperclip.Agent
|
||||
@@ -38,6 +39,7 @@ type projectModel struct {
|
||||
client *paperclip.Client
|
||||
folder string
|
||||
|
||||
dash paperclip.Dashboard
|
||||
project paperclip.Project
|
||||
cfg map[string]string
|
||||
agents []paperclip.Agent
|
||||
@@ -53,7 +55,7 @@ type projectModel struct {
|
||||
width, height int
|
||||
}
|
||||
|
||||
var projectTabs = []string{"facts", "costs", "settings"}
|
||||
var projectTabs = []string{"overview", "facts", "costs", "settings"}
|
||||
|
||||
func newProjectModel(c *paperclip.Client, folder string) projectModel {
|
||||
return projectModel{client: c, folder: folder}
|
||||
@@ -96,7 +98,8 @@ func (m projectModel) load() tea.Cmd {
|
||||
}
|
||||
costs = append(costs, taskCost{t.Identifier, t.Status, cost.CostCents, cost.RunCount})
|
||||
}
|
||||
return projectMsg{project: proj, cfg: cfg, agents: agents, costs: costs}
|
||||
dash, _ := c.DashboardSummary()
|
||||
return projectMsg{project: proj, cfg: cfg, agents: agents, costs: costs, dash: dash}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +185,7 @@ func (m projectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
case projectMsg:
|
||||
m.dash = msg.dash
|
||||
m.project = msg.project
|
||||
m.cfg = msg.cfg
|
||||
m.agents = msg.agents
|
||||
@@ -225,8 +229,10 @@ func (m projectModel) View() string {
|
||||
var body []string
|
||||
switch m.tab {
|
||||
case 0:
|
||||
body = m.factLines()
|
||||
body = m.overviewLines(m.width - 4)
|
||||
case 1:
|
||||
body = m.factLines()
|
||||
case 2:
|
||||
body = m.costLines()
|
||||
default:
|
||||
body = m.settingLines()
|
||||
@@ -268,6 +274,82 @@ func (m projectModel) row(label, value string) string {
|
||||
lipgloss.NewStyle().Foreground(lipgloss.Color(active.Text)).Render(value)
|
||||
}
|
||||
|
||||
// overviewLines is the company dashboard, drawn as numbers a person can act on
|
||||
// and a sparkline of the last two weeks of runs. Everything here comes from
|
||||
// GET /api/companies/{id}/dashboard in one call.
|
||||
func (m projectModel) overviewLines(width int) []string {
|
||||
d := m.dash
|
||||
out := []string{"", groupHeading("agents", -1, width), ""}
|
||||
out = append(out, " "+stat("active", d.Agents.Active, active.Text)+
|
||||
" "+stat("running", d.Agents.Running, active.Info)+
|
||||
" "+stat("paused", d.Agents.Paused, active.Warning)+
|
||||
" "+stat("error", d.Agents.Error, active.Error))
|
||||
out = append(out, "", groupHeading("tasks", -1, width), "")
|
||||
out = append(out, " "+stat("open", d.Tasks.Open, active.Text)+
|
||||
" "+stat("in progress", d.Tasks.InProgress, active.Info)+
|
||||
" "+stat("blocked", d.Tasks.Blocked, active.Error)+
|
||||
" "+stat("done", d.Tasks.Done, active.Success))
|
||||
out = append(out, "", groupHeading("money, this month", -1, width), "")
|
||||
budget := "no company budget set"
|
||||
if d.Costs.MonthBudgetCents > 0 {
|
||||
budget = fmt.Sprintf("%.0f%% of %d cents", d.Costs.MonthUtilizationPercent, d.Costs.MonthBudgetCents)
|
||||
}
|
||||
out = append(out, " "+stat("cents spent", d.Costs.MonthSpendCents, active.Text)+" "+
|
||||
mutedStyle2().Render(budget))
|
||||
out = append(out, " "+stat("pending approvals", d.PendingApprovals, active.Warning))
|
||||
if d.Budgets.ActiveIncidents > 0 || d.Budgets.PausedAgents > 0 || d.Budgets.PausedProjects > 0 {
|
||||
out = append(out, " "+stat("budget incidents", d.Budgets.ActiveIncidents, active.Error)+
|
||||
mutedStyle2().Render(fmt.Sprintf(" paused: %d agent(s), %d project(s)",
|
||||
d.Budgets.PausedAgents, d.Budgets.PausedProjects)))
|
||||
}
|
||||
out = append(out, "", groupHeading("runs, last two weeks", -1, width), "")
|
||||
out = append(out, " "+sparkline(d.RunActivity))
|
||||
if n := len(d.RunActivity); n > 0 {
|
||||
first, last := d.RunActivity[0].Date, d.RunActivity[n-1].Date
|
||||
out = append(out, dimStyle().Render(" "+first+" → "+last+" one bar per day, taller is more runs"))
|
||||
}
|
||||
out = append(out, "")
|
||||
out = append(out, dimStyle().Render(" read from Paperclip's own dashboard, not counted here."))
|
||||
return out
|
||||
}
|
||||
|
||||
// stat is a label and a number, the number first because it is what you look at.
|
||||
func stat(label string, value int, colour string) string {
|
||||
return lipgloss.NewStyle().Foreground(lipgloss.Color(colour)).Bold(true).Render(fmt.Sprintf("%d", value)) +
|
||||
" " + mutedStyle2().Render(label)
|
||||
}
|
||||
|
||||
// sparkline draws one bar per day using block characters, scaled so the busiest
|
||||
// day fills the height. No chart library, no second language: the data is in
|
||||
// memory and the terminal already knows how to draw blocks.
|
||||
func sparkline(points []struct {
|
||||
Date string `json:"date"`
|
||||
Total int `json:"total"`
|
||||
Succeeded int `json:"succeeded"`
|
||||
Failed int `json:"failed"`
|
||||
}) string {
|
||||
bars := []rune("▁▂▃▄▅▆▇█")
|
||||
peak := 0
|
||||
for _, p := range points {
|
||||
if p.Total > peak {
|
||||
peak = p.Total
|
||||
}
|
||||
}
|
||||
if peak == 0 {
|
||||
return mutedStyle2().Render("no runs in the last two weeks")
|
||||
}
|
||||
var b strings.Builder
|
||||
for _, p := range points {
|
||||
idx := int(float64(p.Total) / float64(peak) * float64(len(bars)-1))
|
||||
colour := active.Success
|
||||
if p.Failed > 0 {
|
||||
colour = active.Warning
|
||||
}
|
||||
b.WriteString(lipgloss.NewStyle().Foreground(lipgloss.Color(colour)).Render(string(bars[idx])))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (m projectModel) factLines() []string {
|
||||
out := []string{""}
|
||||
if m.project.Name != "" {
|
||||
|
||||
Reference in New Issue
Block a user