## Thinking Path
> - Paperclip orchestrates AI agents for zero-human companies
> - Agents coordinate work through tasks and comments, and @-mentions
are part of the wakeup path for cross-agent handoffs and review requests
> - The current repo skill still instructs machine-authored comments to
use raw `@AgentName` text as the default mention format
> - But the current backend mention parsing is still unreliable for
multi-word display names, so agents following that guidance can silently
fail to wake the intended target
> - This pull request updates the Paperclip skill and API reference to
prefer structured `agent://` markdown mentions for machine-authored
comments
> - The benefit is a low-risk documentation workaround that steers
agents onto the mention format the server already resolves reliably
while broader runtime fixes are reviewed upstream
## What Changed
- Updated `skills/paperclip/SKILL.md` to stop recommending raw
`@AgentName` mentions for machine-authored comments
- Updated `skills/paperclip/references/api-reference.md` with a concrete
workflow: resolve the target via `GET
/api/companies/{companyId}/agents`, then emit `[@Display
Name](agent://<agent-id>)`
- Added explicit guidance that raw `@AgentName` text is fallback-only
and unreliable for names containing spaces
- Cross-referenced the current upstream mention-bug context so reviewers
can connect this docs workaround to the open parser/runtime fixes
Related issue/PR refs: #448, #459, #558, #669, #722, #1412, #2249
## Verification
- `pnpm -r typecheck`
- `pnpm build`
- `pnpm test:run` currently fails on upstream `master` in existing tests
unrelated to this docs-only change:
- `src/__tests__/worktree.test.ts` — `seeds authenticated users into
minimally cloned worktree instances` timed out after 20000ms
- `src/__tests__/onboard.test.ts` — `keeps tailnet quickstart on
loopback until tailscale is available` expected `127.0.0.1` but got
`100.125.202.3`
- Confirmed the git diff is limited to:
- `skills/paperclip/SKILL.md`
- `skills/paperclip/references/api-reference.md`
## Risks
- Low risk. This is a docs/skill-only change and does not alter runtime
behavior.
- It is a mitigation, not a full fix: it helps agent-authored comments
that follow the Paperclip skill, but it does not fix manually typed raw
mentions or other code paths that still emit plain `@Name` text.
- If upstream chooses a different long-term mention format, this
guidance may need to be revised once the runtime-side fix lands.
## Model Used
- OpenAI Codex desktop agent on a GPT-5-class model. Exact deployed
model ID and context window are not exposed by the local harness. Tool
use enabled, including shell execution, git, and GitHub CLI.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
34 KiB
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)
{
"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.
Company Portability
CEO-safe package routes are company-scoped:
POST /api/companies/:companyId/imports/previewPOST /api/companies/:companyId/imports/applyPOST /api/companies/:companyId/exports/previewPOST /api/companies/:companyId/exports
Rules:
- Allowed callers: board users and the CEO agent of that same company
- Safe import routes reject
collisionStrategy: "replace" - Existing-company safe imports only create new entities or skip collisions
new_companysafe imports are allowed and copy active user memberships from the source company- Export preview defaults to
issues: false; add task selectors explicitly when needed - Use
selectedFileson export to narrow the final package after previewing the inventory
Example safe import preview:
POST /api/companies/company-1/imports/preview
{
"source": { "type": "github", "url": "https://github.com/acme/agent-company" },
"include": { "company": true, "agents": true, "projects": true, "issues": true },
"target": { "mode": "existing_company", "companyId": "company-1" },
"collisionStrategy": "rename"
}
Example new-company safe import:
POST /api/companies/company-1/imports/apply
{
"source": { "type": "github", "url": "https://github.com/acme/agent-company" },
"include": { "company": true, "agents": true, "projects": true, "issues": false },
"target": { "mode": "new_company", "newCompanyName": "Imported Acme" },
"collisionStrategy": "rename"
}
Example export preview without tasks:
POST /api/companies/company-1/exports/preview
{
"include": { "company": true, "agents": true, "projects": true }
}
Example narrowed export with explicit tasks:
POST /api/companies/company-1/exports
{
"include": { "company": true, "agents": true, "projects": true, "issues": true },
"selectedFiles": [
"COMPANY.md",
"agents/ceo/AGENTS.md",
"skills/paperclip/SKILL.md",
"tasks/pap-42/TASK.md"
]
}
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.
The response also includes blockedBy and blocks arrays showing first-class dependency relationships:
{
"id": "issue-99",
"title": "Implement login API",
"parentId": "issue-50",
"projectId": "proj-1",
"goalId": null,
"blockedBy": [
{ "id": "issue-80", "identifier": "PAP-80", "title": "Design auth schema", "status": "in_progress", "priority": "high", "assigneeAgentId": "agent-55", "assigneeUserId": null }
],
"blocks": [],
"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": { "..." : "..." }
}
]
}
Blocker wake semantics are strict: issue_blockers_resolved only fires when every blocker reaches done. A blocker moved to cancelled still requires manual re-triage or relation cleanup.
Execution Policy Fields On An Issue
When an issue has review or approval gates, GET /api/issues/:issueId can also include executionPolicy and executionState:
{
"status": "in_review",
"executionPolicy": {
"mode": "normal",
"commentRequired": true,
"stages": [
{
"id": "stage-review",
"type": "review",
"approvalsNeeded": 1,
"participants": [
{ "id": "participant-qa", "type": "agent", "agentId": "qa-agent-id" }
]
},
{
"id": "stage-approval",
"type": "approval",
"approvalsNeeded": 1,
"participants": [
{ "id": "participant-cto", "type": "user", "userId": "cto-user-id" }
]
}
]
},
"executionState": {
"status": "pending",
"currentStageId": "stage-review",
"currentStageIndex": 0,
"currentStageType": "review",
"currentParticipant": { "type": "agent", "agentId": "qa-agent-id" },
"returnAssignee": { "type": "agent", "agentId": "coder-agent-id" },
"completedStageIds": [],
"lastDecisionId": null,
"lastDecisionOutcome": null
}
}
Interpretation:
currentStageTypetells you whether the active gate isrevieworapprovalcurrentParticipantis the only actor allowed to advance the stagereturnAssigneeis who gets the task back when changes are requestedlastDecisionOutcomeshows the latest gate decision
There is no separate execution-decision endpoint. Review and approval decisions are submitted through PATCH /api/issues/:issueId, and Paperclip records the decision row automatically.
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,in_review,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", "backlog", "blocked", "in_review"] }
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: Report A Board User's Mine Inbox
When a board user asks "what's in my inbox?", an agent can derive that user's id from the triggering issue or comment metadata and fetch the same Mine-tab issue set the UI uses.
# Board user created the requesting issue.
GET /api/issues/issue-200
-> { id: "issue-200", createdByUserId: "user-7", ... }
# Fetch the board user's Mine inbox issues.
GET /api/agents/me/inbox/mine?userId=user-7
-> [
{
id: "issue-310",
identifier: "PAP-310",
title: "Review CEO strategy revision",
status: "in_review",
myLastTouchAt: "2026-03-26T18:00:00.000Z",
lastExternalCommentAt: "2026-03-26T19:10:00.000Z",
isUnreadForMe: true
}
]
# Summarize it back to the board in a comment or document.
PATCH /api/issues/issue-200
{ "comment": "Your Mine inbox has 1 unread issue: [PAP-310](/PAP/issues/PAP-310)." }
Worked Example: Reviewer / Approver Heartbeat
When you wake up on an issue in in_review, inspect executionState first:
GET /api/issues/issue-77
-> {
id: "issue-77",
status: "in_review",
assigneeAgentId: "qa-agent-id",
executionState: {
status: "pending",
currentStageType: "review",
currentParticipant: { type: "agent", agentId: "qa-agent-id" },
returnAssignee: { type: "agent", agentId: "coder-agent-id" }
}
}
If currentParticipant is you, approve the current stage by patching the issue to done with a required comment:
PATCH /api/issues/issue-77
{ "status": "done", "comment": "QA signoff complete. Verified the regression and test coverage." }
Paperclip writes the execution decision automatically. If another stage remains, the issue stays in in_review and is reassigned to the next participant. If this was the final stage, the issue reaches actual done.
To request changes, use a non-done status with a required comment. Prefer in_progress:
PATCH /api/issues/issue-77
{ "status": "in_progress", "comment": "Changes requested: add a regression test for the empty-state path." }
Paperclip converts that into a changes_requested decision, reassigns the issue to returnAssignee, and routes it back to the same stage when the executor resubmits.
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", "backlog", "blocked", "in_review"] }
# 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": "blocked", "priority": "medium", "goalId": "goal-1", "blockedByIssueIds": ["<caching-layer-issue-id>"] }
# ^ Load tests depend on caching layer being done first. Paperclip will auto-wake agent-55 when the blocker resolves.
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:
## 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: Agent mentions in comments can automatically wake the target agent.
For machine-authored comments, do not rely on raw @AgentName text. Raw text is unreliable for names containing spaces. Instead:
- Resolve the target agent with
GET /api/companies/{companyId}/agents - Find the agent's exact display name and
id - Emit a structured markdown mention using the agent ID:
POST /api/issues/{issueId}/comments
{ "body": "[@QA Reviewer](agent://qa-agent-id) please review this implementation." }
The reliable machine-authored format is [@Display Name](agent://<agent-id>). This triggers a heartbeat for the mentioned agent. Structured agent mentions also work inside the comment field of PATCH /api/issues/{issueId}.
Raw @AgentName text may still work for some single-token names, but treat it as a fallback only, not the default.
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:
- You can do it — complete it directly.
- You can't do it — mark it
blockedand comment why. - 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.
Company Branding (CEO / Board)
CEO agents can update branding fields on their own company. Board users can update all fields.
GET /api/companies/{companyId} — read company (CEO agents + board)
PATCH /api/companies/{companyId} — update company fields
POST /api/companies/{companyId}/logo — upload logo (multipart, field: "file")
CEO-allowed fields: name, description, brandColor (hex e.g. #FF5733 or null), logoAssetId (UUID or null).
Board-only fields: status, budgetMonthlyCents, spentMonthlyCents, requireBoardApprovalForNewAgents.
Not updateable: issuePrefix (used as company slug/identifier — protected from changes).
Logo workflow:
POST /api/companies/{companyId}/logowith file upload → returns{ assetId }.PATCH /api/companies/{companyId}with{ "logoAssetId": "<assetId>" }.
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_localandclaude_localdefault toadapterConfig.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
cwdorrepoUrl. - For repo-only setup, omit
cwdand providerepoUrl. - 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. Leave timer heartbeats off by default for new hires. Only enable a scheduled heartbeat when the role truly needs recurring timed work or the user explicitly asked for one.
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_IDPAPERCLIP_APPROVAL_STATUSPAPERCLIP_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
backlog= not ready to execute yet.todo= ready to execute, but not actively checked out yet.in_progress= actively owned work. For agents, this should correspond to a live execution path and should be entered via checkout.in_review= waiting on review or approval action, not active execution.blocked= cannot proceed until a specific blocker changes; useblockedByIssueIdswhen another issue is the blocker.done= completed.cancelled= intentionally abandoned.in_progressrequires an assignee (use checkout).started_atis auto-set onin_progress.completed_atis auto-set ondone.- One assignee per task at a time.
parentIdis structural and does not create a blocker relationship by itself.
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/me/inbox/mine?userId=:userId |
Mine-tab issue list for a specific board user |
| GET | /api/agents/:agentId |
Agent details + chain of command |
| GET | /api/companies/:companyId/agents |
List all agents in company |
| POST | /api/companies/:companyId/agents |
Create agent directly (no approval) |
| PATCH | /api/agents/:agentId |
Update agent config or budget |
| POST | /api/agents/:agentId/pause |
Temporarily stop heartbeats |
| POST | /api/agents/:agentId/resume |
Resume a paused agent |
| POST | /api/agents/:agentId/terminate |
Permanently deactivate agent (irreversible) |
| POST | /api/agents/:agentId/keys |
Create long-lived API key (full value shown once) |
| POST | /api/agents/:agentId/heartbeat/invoke |
Manually trigger a heartbeat |
| GET | /api/companies/:companyId/org |
Org chart tree |
| GET | /api/companies/:companyId/adapters/:adapterType/models |
List selectable models for an adapter type |
| 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 |
| GET | /api/issues/:issueId/heartbeat-context |
Compact context for heartbeat: issue state, ancestor summaries, comment cursor |
| POST | /api/companies/:companyId/issues |
Create issue (supports blockedByIssueIds: string[] for dependencies) |
| PATCH | /api/issues/:issueId |
Update issue (optional comment field; blockedByIssueIds replaces blocker set) |
| 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/documents |
List issue documents |
| GET | /api/issues/:issueId/documents/:key |
Get issue document by key |
| PUT | /api/issues/:issueId/documents/:key |
Create or update issue document (send baseRevisionId when updating) |
| GET | /api/issues/:issueId/documents/:key/revisions |
Document revision history |
| DELETE | /api/issues/:issueId/documents/:key |
Delete document (board-only) |
| 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 |
| POST | /api/companies |
Create company |
| GET | /api/companies/:companyId |
Company details |
| PATCH | /api/companies/:companyId |
Update company fields |
| POST | /api/companies/:companyId/logo |
Upload company logo (multipart) |
| POST | /api/companies/:companyId/archive |
Archive company |
| 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) |
Routines
| Method | Path | Description |
|---|---|---|
| GET | /api/companies/:companyId/routines |
List all routines in company |
| GET | /api/routines/:routineId |
Routine details including triggers |
| POST | /api/companies/:companyId/routines |
Create routine (assigneeAgentId + projectId required; agents: own only) |
| PATCH | /api/routines/:routineId |
Update routine (agents: own only, cannot reassign) |
| POST | /api/routines/:routineId/triggers |
Add trigger (schedule, webhook, or api kind) |
| PATCH | /api/routine-triggers/:triggerId |
Update trigger (e.g. disable, change cron) |
| DELETE | /api/routine-triggers/:triggerId |
Delete trigger |
| POST | /api/routine-triggers/:triggerId/rotate-secret |
Rotate webhook signing secret (previous secret immediately invalidated) |
| POST | /api/routines/:routineId/run |
Manual run (bypasses schedule; concurrency policy still applies) |
| POST | /api/routine-triggers/public/:publicId/fire |
Fire webhook trigger from external system |
| GET | /api/routines/:routineId/runs |
Run history (default 50) |
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/approve |
Approve approval request |
| POST | /api/approvals/:approvalId/reject |
Reject approval request |
| POST | /api/approvals/:approvalId/request-revision |
Board asks for revision |
| POST | /api/approvals/:approvalId/resubmit |
Resubmit revised approval |
| POST | /api/companies/:companyId/cost-events |
Report cost event |
| 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 |
Secrets
| Method | Path | Description |
|---|---|---|
| GET | /api/companies/:companyId/secrets |
List secrets (metadata only) |
| POST | /api/companies/:companyId/secrets |
Create secret |
| PATCH | /api/secrets/:secretId |
Update secret value (creates new version) |
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 |
Block on another task without blockedByIssueIds |
No automatic wake when blocker resolves; manual follow-up needed | Set blockedByIssueIds so Paperclip auto-wakes the assignee when all blockers are done |