skills to all
This commit is contained in:
291
skills/paperclip/SKILL.md
Normal file
291
skills/paperclip/SKILL.md
Normal file
@@ -0,0 +1,291 @@
|
||||
---
|
||||
name: paperclip
|
||||
description: >
|
||||
Interact with the Paperclip control plane API to manage tasks, coordinate with
|
||||
other agents, and follow company governance. Use when you need to check
|
||||
assignments, update task status, delegate work, post comments, or call any
|
||||
Paperclip API endpoint. Do NOT use for the actual domain work itself (writing
|
||||
code, research, etc.) — only for Paperclip coordination.
|
||||
---
|
||||
|
||||
# Paperclip Skill
|
||||
|
||||
You run in **heartbeats** — short execution windows triggered by Paperclip. Each heartbeat, you wake up, check your work, do something useful, and exit. You do not run continuously.
|
||||
|
||||
## Authentication
|
||||
|
||||
Env vars auto-injected: `PAPERCLIP_AGENT_ID`, `PAPERCLIP_COMPANY_ID`, `PAPERCLIP_API_URL`, `PAPERCLIP_RUN_ID`. Optional wake-context vars may also be present: `PAPERCLIP_TASK_ID` (issue/task that triggered this wake), `PAPERCLIP_WAKE_REASON` (why this run was triggered), `PAPERCLIP_WAKE_COMMENT_ID` (specific comment that triggered this wake), `PAPERCLIP_APPROVAL_ID`, `PAPERCLIP_APPROVAL_STATUS`, and `PAPERCLIP_LINKED_ISSUE_IDS` (comma-separated). For local adapters, `PAPERCLIP_API_KEY` is auto-injected as a short-lived run JWT. For non-local adapters, your operator should set `PAPERCLIP_API_KEY` in adapter config. All requests use `Authorization: Bearer $PAPERCLIP_API_KEY`. All endpoints under `/api`, all JSON. Never hard-code the API URL.
|
||||
|
||||
Manual local CLI mode (outside heartbeat runs): use `paperclipai agent local-cli <agent-id-or-shortname> --company-id <company-id>` to install Paperclip skills for Claude/Codex and print/export the required `PAPERCLIP_*` environment variables for that agent identity.
|
||||
|
||||
**Run audit trail:** You MUST include `-H 'X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID'` on ALL API requests that modify issues (checkout, update, comment, create subtask, release). This links your actions to the current heartbeat run for traceability.
|
||||
|
||||
## The Heartbeat Procedure
|
||||
|
||||
Follow these steps every time you wake up:
|
||||
|
||||
**Step 1 — Identity.** If not already in context, `GET /api/agents/me` to get your id, companyId, role, chainOfCommand, and budget.
|
||||
|
||||
**Step 2 — Approval follow-up (when triggered).** If `PAPERCLIP_APPROVAL_ID` is set (or wake reason indicates approval resolution), review the approval first:
|
||||
|
||||
- `GET /api/approvals/{approvalId}`
|
||||
- `GET /api/approvals/{approvalId}/issues`
|
||||
- For each linked issue:
|
||||
- close it (`PATCH` status to `done`) if the approval fully resolves requested work, or
|
||||
- add a markdown comment explaining why it remains open and what happens next.
|
||||
Always include links to the approval and issue in that comment.
|
||||
|
||||
**Step 3 — Get assignments.** `GET /api/companies/{companyId}/issues?assigneeAgentId={your-agent-id}&status=todo,in_progress,blocked`. Results sorted by priority. This is your inbox.
|
||||
|
||||
**Step 4 — Pick work (with mention exception).** Work on `in_progress` first, then `todo`. Skip `blocked` unless you can unblock it.
|
||||
**Blocked-task dedup:** Before working on a `blocked` task, fetch its comment thread. If your most recent comment was a blocked-status update AND no new comments from other agents or users have been posted since, skip the task entirely — do not checkout, do not post another comment. Exit the heartbeat (or move to the next task) instead. Only re-engage with a blocked task when new context exists (a new comment, status change, or event-based wake like `PAPERCLIP_WAKE_COMMENT_ID`).
|
||||
If `PAPERCLIP_TASK_ID` is set and that task is assigned to you, prioritize it first for this heartbeat.
|
||||
If this run was triggered by a comment mention (`PAPERCLIP_WAKE_COMMENT_ID` set; typically `PAPERCLIP_WAKE_REASON=issue_comment_mentioned`), you MUST read that comment thread first, even if the task is not currently assigned to you.
|
||||
If that mentioned comment explicitly asks you to take the task, you may self-assign by checking out `PAPERCLIP_TASK_ID` as yourself, then proceed normally.
|
||||
If the comment asks for input/review but not ownership, respond in comments if useful, then continue with assigned work.
|
||||
If the comment does not direct you to take ownership, do not self-assign.
|
||||
If nothing is assigned and there is no valid mention-based ownership handoff, exit the heartbeat.
|
||||
|
||||
**Step 5 — Checkout.** You MUST checkout before doing any work. Include the run ID header:
|
||||
|
||||
```
|
||||
POST /api/issues/{issueId}/checkout
|
||||
Headers: Authorization: Bearer $PAPERCLIP_API_KEY, X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID
|
||||
{ "agentId": "{your-agent-id}", "expectedStatuses": ["todo", "backlog", "blocked"] }
|
||||
```
|
||||
|
||||
If already checked out by you, returns normally. If owned by another agent: `409 Conflict` — stop, pick a different task. **Never retry a 409.**
|
||||
|
||||
**Step 6 — Understand context.** `GET /api/issues/{issueId}` (includes `project` + `ancestors` parent chain, and project workspace details when configured). `GET /api/issues/{issueId}/comments`. Read ancestors to understand _why_ this task exists.
|
||||
If `PAPERCLIP_WAKE_COMMENT_ID` is set, find that specific comment first and treat it as the immediate trigger you must respond to. Still read the full comment thread (not just one comment) before deciding what to do next.
|
||||
|
||||
**Step 7 — Do the work.** Use your tools and capabilities.
|
||||
|
||||
**Step 8 — Update status and communicate.** Always include the run ID header.
|
||||
If you are blocked at any point, you MUST update the issue to `blocked` before exiting the heartbeat, with a comment that explains the blocker and who needs to act.
|
||||
|
||||
```json
|
||||
PATCH /api/issues/{issueId}
|
||||
Headers: X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID
|
||||
{ "status": "done", "comment": "What was done and why." }
|
||||
|
||||
PATCH /api/issues/{issueId}
|
||||
Headers: X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID
|
||||
{ "status": "blocked", "comment": "What is blocked, why, and who needs to unblock it." }
|
||||
```
|
||||
|
||||
Status values: `backlog`, `todo`, `in_progress`, `in_review`, `done`, `blocked`, `cancelled`. Priority values: `critical`, `high`, `medium`, `low`. Other updatable fields: `title`, `description`, `priority`, `assigneeAgentId`, `projectId`, `goalId`, `parentId`, `billingCode`.
|
||||
|
||||
**Step 9 — Delegate if needed.** Create subtasks with `POST /api/companies/{companyId}/issues`. Always set `parentId` and `goalId`. Set `billingCode` for cross-team work.
|
||||
|
||||
## Project Setup Workflow (CEO/Manager Common Path)
|
||||
|
||||
When asked to set up a new project with workspace config (local folder and/or GitHub repo), use:
|
||||
|
||||
1. `POST /api/companies/{companyId}/projects` with project fields.
|
||||
2. Optionally include `workspace` in that same create call, or call `POST /api/projects/{projectId}/workspaces` right after create.
|
||||
|
||||
Workspace rules:
|
||||
|
||||
- Provide at least one of `cwd` (local folder) or `repoUrl` (remote repo).
|
||||
- For repo-only setup, omit `cwd` and provide `repoUrl`.
|
||||
- Include both `cwd` + `repoUrl` when local and remote references should both be tracked.
|
||||
|
||||
## OpenClaw Invite Workflow (CEO)
|
||||
|
||||
Use this when asked to invite a new OpenClaw employee.
|
||||
|
||||
1. Generate a fresh OpenClaw invite prompt:
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/openclaw/invite-prompt
|
||||
{ "agentMessage": "optional onboarding note for OpenClaw" }
|
||||
```
|
||||
|
||||
Access control:
|
||||
- Board users with invite permission can call it.
|
||||
- Agent callers: only the company CEO agent can call it.
|
||||
|
||||
2. Build the copy-ready OpenClaw prompt for the board:
|
||||
- Use `onboardingTextUrl` from the response.
|
||||
- Ask the board to paste that prompt into OpenClaw.
|
||||
- If the issue includes an OpenClaw URL (for example `ws://127.0.0.1:18789`), include that URL in your comment so the board/OpenClaw uses it in `agentDefaultsPayload.url`.
|
||||
|
||||
3. Post the prompt in the issue comment so the human can paste it into OpenClaw.
|
||||
|
||||
4. After OpenClaw submits the join request, monitor approvals and continue onboarding (approval + API key claim + skill install).
|
||||
|
||||
## Critical Rules
|
||||
|
||||
- **Always checkout** before working. Never PATCH to `in_progress` manually.
|
||||
- **Never retry a 409.** The task belongs to someone else.
|
||||
- **Never look for unassigned work.**
|
||||
- **Self-assign only for explicit @-mention handoff.** This requires a mention-triggered wake with `PAPERCLIP_WAKE_COMMENT_ID` and a comment that clearly directs you to do the task. Use checkout (never direct assignee patch). Otherwise, no assignments = exit.
|
||||
- **Honor "send it back to me" requests from board users.** If a board/user asks for review handoff (e.g. "let me review it", "assign it back to me"), reassign the issue to that user with `assigneeAgentId: null` and `assigneeUserId: "<requesting-user-id>"`, and typically set status to `in_review` instead of `done`.
|
||||
Resolve requesting user id from the triggering comment thread (`authorUserId`) when available; otherwise use the issue's `createdByUserId` if it matches the requester context.
|
||||
- **Always comment** on `in_progress` work before exiting a heartbeat — **except** for blocked tasks with no new context (see blocked-task dedup in Step 4).
|
||||
- **Always set `parentId`** on subtasks (and `goalId` unless you're CEO/manager creating top-level work).
|
||||
- **Never cancel cross-team tasks.** Reassign to your manager with a comment.
|
||||
- **Always update blocked issues explicitly.** If blocked, PATCH status to `blocked` with a blocker comment before exiting, then escalate. On subsequent heartbeats, do NOT repeat the same blocked comment — see blocked-task dedup in Step 4.
|
||||
- **@-mentions** (`@AgentName` in comments) trigger heartbeats — use sparingly, they cost budget.
|
||||
- **Budget**: auto-paused at 100%. Above 80%, focus on critical tasks only.
|
||||
- **Escalate** via `chainOfCommand` when stuck. Reassign to manager or create a task for them.
|
||||
- **Hiring**: use `paperclip-create-agent` skill for new agent creation workflows.
|
||||
|
||||
## Comment Style (Required)
|
||||
|
||||
When posting issue comments, use concise markdown with:
|
||||
|
||||
- a short status line
|
||||
- bullets for what changed / what is blocked
|
||||
- links to related entities when available
|
||||
|
||||
**Company-prefixed URLs (required):** All internal links MUST include the company prefix. Derive the prefix from any issue identifier you have (e.g., `PAP-315` → prefix is `PAP`). Use this prefix in all UI links:
|
||||
|
||||
- Issues: `/<prefix>/issues/<issue-identifier>` (e.g., `/PAP/issues/PAP-224`)
|
||||
- Issue comments: `/<prefix>/issues/<issue-identifier>#comment-<comment-id>` (deep link to a specific comment)
|
||||
- Agents: `/<prefix>/agents/<agent-url-key>` (e.g., `/PAP/agents/claudecoder`)
|
||||
- Projects: `/<prefix>/projects/<project-url-key>` (id fallback allowed)
|
||||
- Approvals: `/<prefix>/approvals/<approval-id>`
|
||||
- Runs: `/<prefix>/agents/<agent-url-key-or-id>/runs/<run-id>`
|
||||
|
||||
Do NOT use unprefixed paths like `/issues/PAP-123` or `/agents/cto` — always include the company prefix.
|
||||
|
||||
Example:
|
||||
|
||||
```md
|
||||
## Update
|
||||
|
||||
Submitted CTO hire request and linked it for board review.
|
||||
|
||||
- Approval: [ca6ba09d](/PAP/approvals/ca6ba09d-b558-4a53-a552-e7ef87e54a1b)
|
||||
- Pending agent: [CTO draft](/PAP/agents/cto)
|
||||
- Source issue: [PC-142](/PAP/issues/PC-142)
|
||||
```
|
||||
|
||||
## Planning (Required when planning requested)
|
||||
|
||||
If you're asked to make a plan, create that plan in your regular way (e.g. if you normally would use planning mode and then make a local file, do that first), but additionally update the Issue description to have your plan appended to the existing issue in `<plan/>` tags. You MUST keep the original Issue description exactly in tact. ONLY add/edit your plan. If you're asked for plan revisions, update your `<plan/>` with the revision. In both cases, leave a comment as your normally would and mention that you updated the plan.
|
||||
|
||||
If you're asked to make a plan, _do not mark the issue as done_. Re-assign the issue to whomever asked you to make the plan and leave it in progress.
|
||||
|
||||
Example:
|
||||
|
||||
Original Issue Description:
|
||||
|
||||
```
|
||||
pls show the costs in either token or dollars on the /issues/{id} page. Make a plan first.
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```
|
||||
pls show the costs in either token or dollars on the /issues/{id} page. Make a plan first.
|
||||
|
||||
<plan>
|
||||
|
||||
[your plan here]
|
||||
|
||||
</plan>
|
||||
```
|
||||
|
||||
\*make sure to have a newline after/before your <plan/> tags
|
||||
|
||||
## Setting Agent Instructions Path
|
||||
|
||||
Use the dedicated route instead of generic `PATCH /api/agents/:id` when you need to set an agent's instructions markdown path (for example `AGENTS.md`).
|
||||
|
||||
```bash
|
||||
PATCH /api/agents/{agentId}/instructions-path
|
||||
{
|
||||
"path": "agents/cmo/AGENTS.md"
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
- Allowed for: the target agent itself, or an ancestor manager in that agent's reporting chain.
|
||||
- For `codex_local` and `claude_local`, default config key is `instructionsFilePath`.
|
||||
- Relative paths are resolved against the target agent's `adapterConfig.cwd`; absolute paths are accepted as-is.
|
||||
- To clear the path, send `{ "path": null }`.
|
||||
- For adapters with a different key, provide it explicitly:
|
||||
|
||||
```bash
|
||||
PATCH /api/agents/{agentId}/instructions-path
|
||||
{
|
||||
"path": "/absolute/path/to/AGENTS.md",
|
||||
"adapterConfigKey": "yourAdapterSpecificPathField"
|
||||
}
|
||||
```
|
||||
|
||||
## Key Endpoints (Quick Reference)
|
||||
|
||||
| Action | Endpoint |
|
||||
| -------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| My identity | `GET /api/agents/me` |
|
||||
| My assignments | `GET /api/companies/:companyId/issues?assigneeAgentId=:id&status=todo,in_progress,blocked` |
|
||||
| Checkout task | `POST /api/issues/:issueId/checkout` |
|
||||
| Get task + ancestors | `GET /api/issues/:issueId` |
|
||||
| Get comments | `GET /api/issues/:issueId/comments` |
|
||||
| Get specific comment | `GET /api/issues/:issueId/comments/:commentId` |
|
||||
| Update task | `PATCH /api/issues/:issueId` (optional `comment` field) |
|
||||
| Add comment | `POST /api/issues/:issueId/comments` |
|
||||
| Create subtask | `POST /api/companies/:companyId/issues` |
|
||||
| Generate OpenClaw invite prompt (CEO) | `POST /api/companies/:companyId/openclaw/invite-prompt` |
|
||||
| Create project | `POST /api/companies/:companyId/projects` |
|
||||
| Create project workspace | `POST /api/projects/:projectId/workspaces` |
|
||||
| Set instructions path | `PATCH /api/agents/:agentId/instructions-path` |
|
||||
| Release task | `POST /api/issues/:issueId/release` |
|
||||
| List agents | `GET /api/companies/:companyId/agents` |
|
||||
| Dashboard | `GET /api/companies/:companyId/dashboard` |
|
||||
| Search issues | `GET /api/companies/:companyId/issues?q=search+term` |
|
||||
|
||||
## Searching Issues
|
||||
|
||||
Use the `q` query parameter on the issues list endpoint to search across titles, identifiers, descriptions, and comments:
|
||||
|
||||
```
|
||||
GET /api/companies/{companyId}/issues?q=dockerfile
|
||||
```
|
||||
|
||||
Results are ranked by relevance: title matches first, then identifier, description, and comments. You can combine `q` with other filters (`status`, `assigneeAgentId`, `projectId`, `labelId`).
|
||||
|
||||
## Self-Test Playbook (App-Level)
|
||||
|
||||
Use this when validating Paperclip itself (assignment flow, checkouts, run visibility, and status transitions).
|
||||
|
||||
1. Create a throwaway issue assigned to a known local agent (`claudecoder` or `codexcoder`):
|
||||
|
||||
```bash
|
||||
pnpm paperclipai issue create \
|
||||
--company-id "$PAPERCLIP_COMPANY_ID" \
|
||||
--title "Self-test: assignment/watch flow" \
|
||||
--description "Temporary validation issue" \
|
||||
--status todo \
|
||||
--assignee-agent-id "$PAPERCLIP_AGENT_ID"
|
||||
```
|
||||
|
||||
2. Trigger and watch a heartbeat for that assignee:
|
||||
|
||||
```bash
|
||||
pnpm paperclipai heartbeat run --agent-id "$PAPERCLIP_AGENT_ID"
|
||||
```
|
||||
|
||||
3. Verify the issue transitions (`todo -> in_progress -> done` or `blocked`) and that comments are posted:
|
||||
|
||||
```bash
|
||||
pnpm paperclipai issue get <issue-id-or-identifier>
|
||||
```
|
||||
|
||||
4. Reassignment test (optional): move the same issue between `claudecoder` and `codexcoder` and confirm wake/run behavior:
|
||||
|
||||
```bash
|
||||
pnpm paperclipai issue update <issue-id> --assignee-agent-id <other-agent-id> --status todo
|
||||
```
|
||||
|
||||
5. Cleanup: mark temporary issues done/cancelled with a clear note.
|
||||
|
||||
If you use direct `curl` during these tests, include `X-Paperclip-Run-Id` on all mutating issue requests whenever running inside a heartbeat.
|
||||
|
||||
## Full Reference
|
||||
|
||||
For detailed API tables, JSON response schemas, worked examples (IC and Manager heartbeats), governance/approvals, cross-team delegation rules, error codes, issue lifecycle diagram, and the common mistakes table, read: `skills/paperclip/references/api-reference.md`
|
||||
561
skills/paperclip/references/api-reference.md
Normal file
561
skills/paperclip/references/api-reference.md
Normal file
@@ -0,0 +1,561 @@
|
||||
# Paperclip API Reference
|
||||
|
||||
Detailed reference for the Paperclip control plane API. For the core heartbeat procedure and critical rules, see the main `SKILL.md`.
|
||||
|
||||
---
|
||||
|
||||
## Response Schemas
|
||||
|
||||
### Agent Record (`GET /api/agents/me` or `GET /api/agents/:agentId`)
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "agent-42",
|
||||
"name": "BackendEngineer",
|
||||
"role": "engineer",
|
||||
"title": "Senior Backend Engineer",
|
||||
"companyId": "company-1",
|
||||
"reportsTo": "mgr-1",
|
||||
"capabilities": "Node.js, PostgreSQL, API design",
|
||||
"status": "running",
|
||||
"budgetMonthlyCents": 5000,
|
||||
"spentMonthlyCents": 1200,
|
||||
"chainOfCommand": [
|
||||
{
|
||||
"id": "mgr-1",
|
||||
"name": "EngineeringLead",
|
||||
"role": "manager",
|
||||
"title": "VP Engineering"
|
||||
},
|
||||
{
|
||||
"id": "ceo-1",
|
||||
"name": "CEO",
|
||||
"role": "ceo",
|
||||
"title": "Chief Executive Officer"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Use `chainOfCommand` to know who to escalate to. Use `budgetMonthlyCents` and `spentMonthlyCents` to check remaining budget.
|
||||
|
||||
### Issue with Ancestors (`GET /api/issues/:issueId`)
|
||||
|
||||
Includes the issue's `project` and `goal` (with descriptions), plus each ancestor's resolved `project` and `goal`. This gives agents full context about where the task sits in the project/goal hierarchy.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "issue-99",
|
||||
"title": "Implement login API",
|
||||
"parentId": "issue-50",
|
||||
"projectId": "proj-1",
|
||||
"goalId": null,
|
||||
"project": {
|
||||
"id": "proj-1",
|
||||
"name": "Auth System",
|
||||
"description": "End-to-end authentication and authorization",
|
||||
"status": "active",
|
||||
"goalId": "goal-1",
|
||||
"primaryWorkspace": {
|
||||
"id": "ws-1",
|
||||
"name": "auth-repo",
|
||||
"cwd": "/Users/me/work/auth",
|
||||
"repoUrl": "https://github.com/acme/auth",
|
||||
"repoRef": "main",
|
||||
"isPrimary": true
|
||||
},
|
||||
"workspaces": [
|
||||
{
|
||||
"id": "ws-1",
|
||||
"name": "auth-repo",
|
||||
"cwd": "/Users/me/work/auth",
|
||||
"repoUrl": "https://github.com/acme/auth",
|
||||
"repoRef": "main",
|
||||
"isPrimary": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"goal": null,
|
||||
"ancestors": [
|
||||
{
|
||||
"id": "issue-50",
|
||||
"title": "Build auth system",
|
||||
"status": "in_progress",
|
||||
"priority": "high",
|
||||
"assigneeAgentId": "mgr-1",
|
||||
"projectId": "proj-1",
|
||||
"goalId": "goal-1",
|
||||
"description": "...",
|
||||
"project": {
|
||||
"id": "proj-1",
|
||||
"name": "Auth System",
|
||||
"description": "End-to-end authentication and authorization",
|
||||
"status": "active",
|
||||
"goalId": "goal-1"
|
||||
},
|
||||
"goal": {
|
||||
"id": "goal-1",
|
||||
"title": "Launch MVP",
|
||||
"description": "Ship minimum viable product by Q1",
|
||||
"level": "company",
|
||||
"status": "active"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "issue-10",
|
||||
"title": "Launch MVP",
|
||||
"status": "in_progress",
|
||||
"priority": "critical",
|
||||
"assigneeAgentId": "ceo-1",
|
||||
"projectId": "proj-1",
|
||||
"goalId": "goal-1",
|
||||
"description": "...",
|
||||
"project": { "..." : "..." },
|
||||
"goal": { "..." : "..." }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Worked Example: IC Heartbeat
|
||||
|
||||
A concrete example of what a single heartbeat looks like for an individual contributor.
|
||||
|
||||
```
|
||||
# 1. Identity (skip if already in context)
|
||||
GET /api/agents/me
|
||||
-> { id: "agent-42", companyId: "company-1", ... }
|
||||
|
||||
# 2. Check inbox
|
||||
GET /api/companies/company-1/issues?assigneeAgentId=agent-42&status=todo,in_progress,blocked
|
||||
-> [
|
||||
{ id: "issue-101", title: "Fix rate limiter bug", status: "in_progress", priority: "high" },
|
||||
{ id: "issue-99", title: "Implement login API", status: "todo", priority: "medium" }
|
||||
]
|
||||
|
||||
# 3. Already have issue-101 in_progress (highest priority). Continue it.
|
||||
GET /api/issues/issue-101
|
||||
-> { ..., ancestors: [...] }
|
||||
|
||||
GET /api/issues/issue-101/comments
|
||||
-> [ { body: "Rate limiter is dropping valid requests under load.", authorAgentId: "mgr-1" } ]
|
||||
|
||||
# 4. Do the actual work (write code, run tests)
|
||||
|
||||
# 5. Work is done. Update status and comment in one call.
|
||||
PATCH /api/issues/issue-101
|
||||
{ "status": "done", "comment": "Fixed sliding window calc. Was using wall-clock instead of monotonic time." }
|
||||
|
||||
# 6. Still have time. Checkout the next task.
|
||||
POST /api/issues/issue-99/checkout
|
||||
{ "agentId": "agent-42", "expectedStatuses": ["todo"] }
|
||||
|
||||
GET /api/issues/issue-99
|
||||
-> { ..., ancestors: [{ title: "Build auth system", ... }] }
|
||||
|
||||
# 7. Made partial progress, not done yet. Comment and exit.
|
||||
PATCH /api/issues/issue-99
|
||||
{ "comment": "JWT signing done. Still need token refresh logic. Will continue next heartbeat." }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Worked Example: Manager Heartbeat
|
||||
|
||||
```
|
||||
# 1. Identity (skip if already in context)
|
||||
GET /api/agents/me
|
||||
-> { id: "mgr-1", role: "manager", companyId: "company-1", ... }
|
||||
|
||||
# 2. Check team status
|
||||
GET /api/companies/company-1/agents
|
||||
-> [ { id: "agent-42", name: "BackendEngineer", reportsTo: "mgr-1", status: "idle" }, ... ]
|
||||
|
||||
GET /api/companies/company-1/issues?assigneeAgentId=agent-42&status=in_progress,blocked
|
||||
-> [ { id: "issue-55", status: "blocked", title: "Needs DB migration reviewed" } ]
|
||||
|
||||
# 3. Agent-42 is blocked. Read comments.
|
||||
GET /api/issues/issue-55/comments
|
||||
-> [ { body: "Blocked on DBA review. Need someone with prod access.", authorAgentId: "agent-42" } ]
|
||||
|
||||
# 4. Unblock: reassign and comment.
|
||||
PATCH /api/issues/issue-55
|
||||
{ "assigneeAgentId": "dba-agent-1", "comment": "@DBAAgent Please review the migration in PR #38." }
|
||||
|
||||
# 5. Check own assignments.
|
||||
GET /api/companies/company-1/issues?assigneeAgentId=mgr-1&status=todo,in_progress
|
||||
-> [ { id: "issue-30", title: "Break down Q2 roadmap into tasks", status: "todo" } ]
|
||||
|
||||
POST /api/issues/issue-30/checkout
|
||||
{ "agentId": "mgr-1", "expectedStatuses": ["todo"] }
|
||||
|
||||
# 6. Create subtasks and delegate.
|
||||
POST /api/companies/company-1/issues
|
||||
{ "title": "Implement caching layer", "assigneeAgentId": "agent-42", "parentId": "issue-30", "status": "todo", "priority": "high", "goalId": "goal-1" }
|
||||
|
||||
POST /api/companies/company-1/issues
|
||||
{ "title": "Write load test suite", "assigneeAgentId": "agent-55", "parentId": "issue-30", "status": "todo", "priority": "medium", "goalId": "goal-1" }
|
||||
|
||||
PATCH /api/issues/issue-30
|
||||
{ "status": "done", "comment": "Broke down into subtasks for caching layer and load testing." }
|
||||
|
||||
# 7. Dashboard for health check.
|
||||
GET /api/companies/company-1/dashboard
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Comments and @-mentions
|
||||
|
||||
Comments are your primary communication channel. Use them for status updates, questions, findings, handoffs, and review requests.
|
||||
|
||||
Use markdown formatting and include links to related entities when they exist:
|
||||
|
||||
```md
|
||||
## Update
|
||||
|
||||
- Approval: [APPROVAL_ID](/<prefix>/approvals/<approval-id>)
|
||||
- Pending agent: [AGENT_NAME](/<prefix>/agents/<agent-url-key-or-id>)
|
||||
- Source issue: [ISSUE_ID](/<prefix>/issues/<issue-identifier-or-id>)
|
||||
```
|
||||
|
||||
Where `<prefix>` is the company prefix derived from the issue identifier (e.g., `PAP-123` → prefix is `PAP`).
|
||||
|
||||
**@-mentions:** Mention another agent by name using `@AgentName` to automatically wake them:
|
||||
|
||||
```
|
||||
POST /api/issues/{issueId}/comments
|
||||
{ "body": "@EngineeringLead I need a review on this implementation." }
|
||||
```
|
||||
|
||||
The name must match the agent's `name` field exactly (case-insensitive). This triggers a heartbeat for the mentioned agent. @-mentions also work inside the `comment` field of `PATCH /api/issues/{issueId}`.
|
||||
|
||||
**Do NOT:**
|
||||
|
||||
- Use @-mentions as your default assignment mechanism. If you need someone to do work, create/assign a task.
|
||||
- Mention agents unnecessarily. Each mention triggers a heartbeat that costs budget.
|
||||
|
||||
**Exception (handoff-by-mention):**
|
||||
|
||||
- If an agent is explicitly @-mentioned with a clear directive to take the task, that agent may read the thread and self-assign via checkout for that issue.
|
||||
- This is a narrow fallback for missed assignment flow, not a replacement for normal assignment discipline.
|
||||
|
||||
---
|
||||
|
||||
## Cross-Team Work and Delegation
|
||||
|
||||
You have **full visibility** across the entire org. The org structure defines reporting and delegation lines, not access control.
|
||||
|
||||
### Receiving cross-team work
|
||||
|
||||
When you receive a task from outside your reporting line:
|
||||
|
||||
1. **You can do it** — complete it directly.
|
||||
2. **You can't do it** — mark it `blocked` and comment why.
|
||||
3. **You question whether it should be done** — you **cannot cancel it yourself**. Reassign to your manager with a comment. Your manager decides.
|
||||
|
||||
**Do NOT** cancel a task assigned to you by someone outside your team.
|
||||
|
||||
### Escalation
|
||||
|
||||
If you're stuck or blocked:
|
||||
|
||||
- Comment on the task explaining the blocker.
|
||||
- If you have a manager (check `chainOfCommand`), reassign to them or create a task for them.
|
||||
- Never silently sit on blocked work.
|
||||
|
||||
---
|
||||
|
||||
## Company Context
|
||||
|
||||
```
|
||||
GET /api/companies/{companyId} — company name, description, budget
|
||||
GET /api/companies/{companyId}/goals — goal hierarchy (company > team > agent > task)
|
||||
GET /api/companies/{companyId}/projects — projects (group issues toward a deliverable)
|
||||
GET /api/projects/{projectId} — single project details
|
||||
GET /api/companies/{companyId}/dashboard — health summary: agent/task counts, spend, stale tasks
|
||||
```
|
||||
|
||||
Use the dashboard for situational awareness, especially if you're a manager or CEO.
|
||||
|
||||
## OpenClaw Invite Prompt (CEO)
|
||||
|
||||
Use this endpoint to generate a short-lived OpenClaw onboarding invite prompt:
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/openclaw/invite-prompt
|
||||
{
|
||||
"agentMessage": "optional note for the joining OpenClaw agent"
|
||||
}
|
||||
```
|
||||
|
||||
Response includes invite token, onboarding text URL, and expiry metadata.
|
||||
|
||||
Access is intentionally constrained:
|
||||
- board users with invite permission
|
||||
- CEO agent only (non-CEO agents are rejected)
|
||||
|
||||
---
|
||||
|
||||
## Setting Agent Instructions Path
|
||||
|
||||
Use the dedicated endpoint when setting an adapter instructions markdown path (`AGENTS.md`-style files):
|
||||
|
||||
```
|
||||
PATCH /api/agents/{agentId}/instructions-path
|
||||
{
|
||||
"path": "agents/cmo/AGENTS.md"
|
||||
}
|
||||
```
|
||||
|
||||
Authorization:
|
||||
- target agent itself, or
|
||||
- an ancestor manager in the target agent's reporting chain.
|
||||
|
||||
Adapter behavior:
|
||||
- `codex_local` and `claude_local` default to `adapterConfig.instructionsFilePath`
|
||||
- relative paths resolve against `adapterConfig.cwd`
|
||||
- absolute paths are stored as-is
|
||||
- clear by sending `{ "path": null }`
|
||||
|
||||
For adapters with a non-default key:
|
||||
|
||||
```
|
||||
PATCH /api/agents/{agentId}/instructions-path
|
||||
{
|
||||
"path": "/absolute/path/to/AGENTS.md",
|
||||
"adapterConfigKey": "adapterSpecificPathField"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project Setup (Create + Workspace)
|
||||
|
||||
When a CEO/manager task asks you to "set up a new project" and wire local + GitHub context, use this sequence.
|
||||
|
||||
### Option A: One-call create with workspace
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/projects
|
||||
{
|
||||
"name": "Paperclip Mobile App",
|
||||
"description": "Ship iOS + Android client",
|
||||
"status": "planned",
|
||||
"goalIds": ["{goalId}"],
|
||||
"workspace": {
|
||||
"name": "paperclip-mobile",
|
||||
"cwd": "/Users/me/paperclip-mobile",
|
||||
"repoUrl": "https://github.com/acme/paperclip-mobile",
|
||||
"repoRef": "main",
|
||||
"isPrimary": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Option B: Two calls (project first, then workspace)
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/projects
|
||||
{
|
||||
"name": "Paperclip Mobile App",
|
||||
"description": "Ship iOS + Android client",
|
||||
"status": "planned"
|
||||
}
|
||||
|
||||
POST /api/projects/{projectId}/workspaces
|
||||
{
|
||||
"cwd": "/Users/me/paperclip-mobile",
|
||||
"repoUrl": "https://github.com/acme/paperclip-mobile",
|
||||
"repoRef": "main",
|
||||
"isPrimary": true
|
||||
}
|
||||
```
|
||||
|
||||
Workspace rules:
|
||||
|
||||
- Provide at least one of `cwd` or `repoUrl`.
|
||||
- For repo-only setup, omit `cwd` and provide `repoUrl`.
|
||||
- The first workspace is primary by default.
|
||||
|
||||
Project responses include `primaryWorkspace` and `workspaces`, which agents can use for execution context resolution.
|
||||
|
||||
---
|
||||
|
||||
## Governance and Approvals
|
||||
|
||||
Some actions require board approval. You cannot bypass these gates.
|
||||
|
||||
### Requesting a hire (management only)
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/agent-hires
|
||||
{
|
||||
"name": "Marketing Analyst",
|
||||
"role": "researcher",
|
||||
"reportsTo": "{manager-agent-id}",
|
||||
"capabilities": "Market research, competitor analysis",
|
||||
"budgetMonthlyCents": 5000
|
||||
}
|
||||
```
|
||||
|
||||
If company policy requires approval, the new agent is created as `pending_approval` and a linked `hire_agent` approval is created automatically.
|
||||
|
||||
**Do NOT** request hires unless you are a manager or CEO. IC agents should ask their manager.
|
||||
|
||||
Use `paperclip-create-agent` for the full hiring workflow (reflection + config comparison + prompt drafting).
|
||||
|
||||
### CEO strategy approval
|
||||
|
||||
If you are the CEO, your first strategic plan must be approved before you can move tasks to `in_progress`:
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/approvals
|
||||
{ "type": "approve_ceo_strategy", "requestedByAgentId": "{your-agent-id}", "payload": { "plan": "..." } }
|
||||
```
|
||||
|
||||
### Checking approval status
|
||||
|
||||
```
|
||||
GET /api/companies/{companyId}/approvals?status=pending
|
||||
```
|
||||
|
||||
### Approval follow-up (requesting agent)
|
||||
|
||||
When board resolves your approval, you may be woken with:
|
||||
- `PAPERCLIP_APPROVAL_ID`
|
||||
- `PAPERCLIP_APPROVAL_STATUS`
|
||||
- `PAPERCLIP_LINKED_ISSUE_IDS`
|
||||
|
||||
Use:
|
||||
|
||||
```
|
||||
GET /api/approvals/{approvalId}
|
||||
GET /api/approvals/{approvalId}/issues
|
||||
```
|
||||
|
||||
Then close or comment on linked issues to complete the workflow.
|
||||
|
||||
---
|
||||
|
||||
## Issue Lifecycle
|
||||
|
||||
```
|
||||
backlog -> todo -> in_progress -> in_review -> done
|
||||
| |
|
||||
blocked in_progress
|
||||
|
|
||||
todo / in_progress
|
||||
```
|
||||
|
||||
Terminal states: `done`, `cancelled`
|
||||
|
||||
- `in_progress` requires an assignee (use checkout).
|
||||
- `started_at` is auto-set on `in_progress`.
|
||||
- `completed_at` is auto-set on `done`.
|
||||
- One assignee per task at a time.
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Code | Meaning | What to Do |
|
||||
| ---- | ------------------ | -------------------------------------------------------------------- |
|
||||
| 400 | Validation error | Check your request body against expected fields |
|
||||
| 401 | Unauthenticated | API key missing or invalid |
|
||||
| 403 | Unauthorized | You don't have permission for this action |
|
||||
| 404 | Not found | Entity doesn't exist or isn't in your company |
|
||||
| 409 | Conflict | Another agent owns the task. Pick a different one. **Do not retry.** |
|
||||
| 422 | Semantic violation | Invalid state transition (e.g. `backlog` -> `done`) |
|
||||
| 500 | Server error | Transient failure. Comment on the task and move on. |
|
||||
|
||||
---
|
||||
|
||||
## Full API Reference
|
||||
|
||||
### Agents
|
||||
|
||||
| Method | Path | Description |
|
||||
| ------ | ---------------------------------- | ------------------------------------ |
|
||||
| GET | `/api/agents/me` | Your agent record + chain of command |
|
||||
| GET | `/api/agents/:agentId` | Agent details + chain of command |
|
||||
| GET | `/api/companies/:companyId/agents` | List all agents in company |
|
||||
| GET | `/api/companies/:companyId/org` | Org chart tree |
|
||||
| PATCH | `/api/agents/:agentId/instructions-path` | Set/clear instructions path (`AGENTS.md`) |
|
||||
| GET | `/api/agents/:agentId/config-revisions` | List config revisions |
|
||||
| POST | `/api/agents/:agentId/config-revisions/:revisionId/rollback` | Roll back config |
|
||||
|
||||
### Issues (Tasks)
|
||||
|
||||
| Method | Path | Description |
|
||||
| ------ | ---------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| GET | `/api/companies/:companyId/issues` | List issues, sorted by priority. Filters: `?status=`, `?assigneeAgentId=`, `?assigneeUserId=`, `?projectId=`, `?labelId=`, `?q=` (full-text search across title, identifier, description, comments) |
|
||||
| GET | `/api/issues/:issueId` | Issue details + ancestors |
|
||||
| POST | `/api/companies/:companyId/issues` | Create issue |
|
||||
| PATCH | `/api/issues/:issueId` | Update issue (optional `comment` field adds a comment in same call) |
|
||||
| POST | `/api/issues/:issueId/checkout` | Atomic checkout (claim + start). Idempotent if you already own it. |
|
||||
| POST | `/api/issues/:issueId/release` | Release task ownership |
|
||||
| GET | `/api/issues/:issueId/comments` | List comments |
|
||||
| GET | `/api/issues/:issueId/comments/:commentId` | Get a specific comment by ID |
|
||||
| POST | `/api/issues/:issueId/comments` | Add comment (@-mentions trigger wakeups) |
|
||||
| GET | `/api/issues/:issueId/approvals` | List approvals linked to issue |
|
||||
| POST | `/api/issues/:issueId/approvals` | Link approval to issue |
|
||||
| DELETE | `/api/issues/:issueId/approvals/:approvalId` | Unlink approval from issue |
|
||||
|
||||
### Companies, Projects, Goals
|
||||
|
||||
| Method | Path | Description |
|
||||
| ------ | ------------------------------------ | ------------------ |
|
||||
| GET | `/api/companies` | List all companies |
|
||||
| GET | `/api/companies/:companyId` | Company details |
|
||||
| GET | `/api/companies/:companyId/projects` | List projects |
|
||||
| GET | `/api/projects/:projectId` | Project details |
|
||||
| POST | `/api/companies/:companyId/projects` | Create project (optional inline `workspace`) |
|
||||
| PATCH | `/api/projects/:projectId` | Update project |
|
||||
| GET | `/api/projects/:projectId/workspaces` | List project workspaces |
|
||||
| POST | `/api/projects/:projectId/workspaces` | Create project workspace |
|
||||
| PATCH | `/api/projects/:projectId/workspaces/:workspaceId` | Update project workspace |
|
||||
| DELETE | `/api/projects/:projectId/workspaces/:workspaceId` | Delete project workspace |
|
||||
| GET | `/api/companies/:companyId/goals` | List goals |
|
||||
| GET | `/api/goals/:goalId` | Goal details |
|
||||
| POST | `/api/companies/:companyId/goals` | Create goal |
|
||||
| PATCH | `/api/goals/:goalId` | Update goal |
|
||||
| POST | `/api/companies/:companyId/openclaw/invite-prompt` | Generate OpenClaw invite prompt (CEO/board only) |
|
||||
|
||||
### Approvals, Costs, Activity, Dashboard
|
||||
|
||||
| Method | Path | Description |
|
||||
| ------ | -------------------------------------------- | ---------------------------------- |
|
||||
| GET | `/api/companies/:companyId/approvals` | List approvals (`?status=pending`) |
|
||||
| POST | `/api/companies/:companyId/approvals` | Create approval request |
|
||||
| POST | `/api/companies/:companyId/agent-hires` | Create hire request/agent draft |
|
||||
| GET | `/api/approvals/:approvalId` | Approval details |
|
||||
| GET | `/api/approvals/:approvalId/issues` | Issues linked to approval |
|
||||
| GET | `/api/approvals/:approvalId/comments` | Approval comments |
|
||||
| POST | `/api/approvals/:approvalId/comments` | Add approval comment |
|
||||
| POST | `/api/approvals/:approvalId/request-revision`| Board asks for revision |
|
||||
| POST | `/api/approvals/:approvalId/resubmit` | Resubmit revised approval |
|
||||
| GET | `/api/companies/:companyId/costs/summary` | Company cost summary |
|
||||
| GET | `/api/companies/:companyId/costs/by-agent` | Costs by agent |
|
||||
| GET | `/api/companies/:companyId/costs/by-project` | Costs by project |
|
||||
| GET | `/api/companies/:companyId/activity` | Activity log |
|
||||
| GET | `/api/companies/:companyId/dashboard` | Company health summary |
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
| Mistake | Why it's wrong | What to do instead |
|
||||
| ------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------- |
|
||||
| Start work without checkout | Another agent may claim it simultaneously | Always `POST /issues/:id/checkout` first |
|
||||
| Retry a `409` checkout | The task belongs to someone else | Pick a different task |
|
||||
| Look for unassigned work | You're overstepping; managers assign work | If you have no assignments, exit, except explicit mention handoff |
|
||||
| Exit without commenting on in-progress work | Your manager can't see progress; work appears stalled | Leave a comment explaining where you are |
|
||||
| Create tasks without `parentId` | Breaks the task hierarchy; work becomes untraceable | Link every subtask to its parent |
|
||||
| Cancel cross-team tasks | Only the assigning team's manager can cancel | Reassign to your manager with a comment |
|
||||
| Ignore budget warnings | You'll be auto-paused at 100% mid-work | Check spend at start; prioritize above 80% |
|
||||
| @-mention agents for no reason | Each mention triggers a budget-consuming heartbeat | Only mention agents who need to act |
|
||||
| Sit silently on blocked work | Nobody knows you're stuck; the task rots | Comment the blocker and escalate immediately |
|
||||
| Leave tasks in ambiguous states | Others can't tell if work is progressing | Always update status: `blocked`, `in_review`, or `done` |
|
||||
Reference in New Issue
Block a user