117 lines
5.4 KiB
Markdown
117 lines
5.4 KiB
Markdown
---
|
||
type: note
|
||
proposed_folder: 200 projects/210 AI Resume
|
||
proposed_toc: 100 Table of Contents/Projects.md → AI Resume
|
||
proposed_tags:
|
||
- ai-resume
|
||
- board
|
||
- operator
|
||
- paperclip
|
||
- keys
|
||
confidence: 0.92
|
||
approved: false
|
||
proposed_for: 61e258687cd8
|
||
created: "2026-10-26 20:05"
|
||
tags:
|
||
- paperclip
|
||
- ai-resume
|
||
- board
|
||
- keys
|
||
aliases: []
|
||
modified: "2026-10-26 20:05"
|
||
---
|
||
|
||
# [[Paperclip board — operator notes and key model]]
|
||
|
||
Written after a failed board build on the Ai Resume project. The purpose is that nobody, human or agent, repeats it.
|
||
|
||
## Two key types, and they are not interchangeable
|
||
|
||
- **Board key** — prefix `pcp_board_`. This is Sam as operator. Creates, links, reassigns and deletes tasks. Can read agent configuration. Held in `PAPERCLIP_BOARD_KEY`.
|
||
- **Agent key** — prefix `pcp_`. This is one named agent (Hub, Builder, System, Documenter, researcher, Chief of Staff). Works its own task and comments on it. **Cannot write to other tasks** — it returns `Cross-issue writes need a run to attribute them to`. Held in `PAPERCLIP_API_KEY`.
|
||
|
||
Both live in `~/.config/environment.d/10-secrets.conf`. Do not put a board key in `PAPERCLIP_API_KEY`; agents expect that name to be an agent identity.
|
||
|
||
Machines carrying the board key: `.13` (host), `.27`, `.51`. One key works on all of them because it belongs to the user, not the machine.
|
||
|
||
## Minting a board key
|
||
|
||
There is no settings page for this. Board keys are created through a CLI auth challenge and approved in a browser that already has a session.
|
||
|
||
```
|
||
curl -s -X POST http://127.0.0.1:3100/api/cli-auth/challenges \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"command":"paperclipai connect --persona board --token-name operator","requestedAccess":"board"}'
|
||
```
|
||
|
||
The reply contains `boardApiToken` (inactive until approved) and `approvalPath`. Open the approval URL **on the public hostname**, not localhost:
|
||
|
||
`https://paperclip.lab.audasmedia.com.au<approvalPath>`
|
||
|
||
Approve, then confirm with `GET /api/cli-auth/me`. It should return `"source":"board_key"`.
|
||
|
||
Do not use `paperclipai connect` interactively for this. It asks for an email and password first, and that is the step that fails.
|
||
|
||
## The rule that broke the board
|
||
|
||
**Never create a task and assign it in one action.**
|
||
|
||
An assigned task is claimed by that agent's run within seconds. Paperclip then locks field writes to that run, so every other writer — including the board — gets `409 issue_write_assignee_run_lock`. The dependency links then never get written, and the graph silently does not exist. Every task looks ready; they all start; phases run out of order.
|
||
|
||
Correct order, always:
|
||
|
||
1. Create the task **unassigned**.
|
||
2. PATCH `blockedByIssueIds` in a separate call.
|
||
3. Assign.
|
||
4. Verify.
|
||
|
||
`blockedByIssueIds` passed at creation is **silently ignored**. It must be PATCHed afterwards, and the PATCH response is the proof — the list endpoint does not return the field.
|
||
|
||
An agent cannot do steps 1–3 reliably. The operator does. Never instruct an agent to "decompose and wire the plan".
|
||
|
||
## Where the agents' instructions actually live
|
||
|
||
```
|
||
/home/sam/.paperclip/instances/default/companies/<companyId>/agents/<agentId>/instructions/AGENTS.md
|
||
```
|
||
|
||
Read these before designing work for an agent. The Chief of Staff's own file says "create a child task, assign it, and set blockedByIssueIds" — in that order — which is the unworkable sequence above. Any instruction that says this will fail the same way every time.
|
||
|
||
## When agents go silent
|
||
|
||
Check heartbeats. All six agents were created with `heartbeat.enabled = false`, so nothing advances between direct assignments.
|
||
|
||
```
|
||
curl -s -X PATCH -H "Authorization: Bearer $PAPERCLIP_BOARD_KEY" \
|
||
-H 'Content-Type: application/json' \
|
||
-d '{"runtimeConfig":{"heartbeat":{"enabled":true,"maxConcurrentRuns":20}}}' \
|
||
http://127.0.0.1:3100/api/agents/<agentId>
|
||
```
|
||
|
||
Builder, System and Documenter are now on. Hub, researcher and Chief of Staff are deliberately off — a coordinator that wakes with no job invents one.
|
||
|
||
## Failure mode to never repeat
|
||
|
||
**Never schedule a monitor to wait on your own failed write.** A monitor that re-checks a condition which cannot change re-wakes the agent forever. That is what turned a one-off 409 into a loop of runs, each burning seventeen minutes and ending in `execution_finalization_deadline_exceeded`.
|
||
|
||
If a write returns a run-lock: report it and stop.
|
||
|
||
## The board as it stands (2026-10-26)
|
||
|
||
- AUD-140 — parent, holds the build brief
|
||
- AUD-141 — content source of truth — **done**, 40 documents, `make validate` passing
|
||
- AUD-142 — site skeleton and pages — in progress
|
||
- AUD-143 — deploy to the server — waits on 142
|
||
- AUD-144 — searchable index — waits on 141 and 142
|
||
- AUD-145 — AI question box and safety rules — waits on 143 and 144
|
||
|
||
Working directory: `/home/sam/paseo/projects/resume_ai_system_paperclip_build`, which is the git working copy of `sam/ai-resume`.
|
||
|
||
## What actually sources the content pipeline
|
||
|
||
Only `content/` in that repository. Nothing in this vault is read by the pipeline, and nothing in Outline or Vikunja is either.
|
||
|
||
That is deliberate for now: one source, so the pages and the AI corpus cannot drift. Obsidian is the obvious second source later — but it should be an allow-list of chosen notes, never the whole vault, because the vault contains family and personal material.
|
||
|
||
Outline and Vikunja being offline does not block anything. No part of the build depends on them.
|