Files
paperclip/skills/paperclip/SKILL.md
T
Dotta 468edd8b22 Add workspace file viewer and artifact links (#7681)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent work is issue-centered, and reviewers often need to inspect
files, artifacts, and path references produced during that work.
> - Before this branch, workspace-relative paths and artifact file
references were not first-class inspectable objects in the board UI.
> - Safe file viewing needs shared resource contracts, server-side
workspace boundary checks, and UI that opens files without exposing
arbitrary host paths.
> - The workspace file viewer branch needed to stay as one active PR and
be rebased onto current `paperclipai/paperclip:master` for review.
> - This pull request adds the workspace file resource API, issue-page
file viewer and browser, markdown file-reference links, and artifact
file chips.
> - The benefit is that board users can inspect relevant files from
issue context while preserving workspace boundaries and auditability.

## Linked Issues or Issue Description

No public GitHub issue exists for this branch. Internal Paperclip
issues: `PAP-1953`, `PAP-10539`, `PAP-10733`.

Problem / motivation:
- Board users need to open workspace-relative files mentioned by agents
or attached as work-product metadata without switching to a terminal.
- The UI needs to support both direct file-path opening and workspace
browsing/searching from an issue page.
- The server must enforce company access, workspace boundaries, size
limits, rate limits, and safe audit logging.

Related PR:
- Prior closed attempt: #4442
- Single active PR for this branch: #7681

## What Changed

- Added shared workspace file resource types, validators, and
workspace-file `resourceRef` metadata validation for work products.
- Added server routes/services for resolving, listing, and previewing
workspace-relative files with access checks, scan caps, list-specific
limits, and audit logging.
- Added the issue file viewer provider, sheet, workspace browser,
command-palette action, markdown workspace-file autolinks, and artifact
file chips.
- Updated issue workspace UI and stories/tests for file browsing and
workspace file opening.
- Rebased the branch onto current `paperclipai/paperclip:master` and
updated the existing single PR branch.
- Addressed current-head Greptile follow-ups by applying `offset`
consistently across search/recent/changed file listings, restoring
stopped-service port ownership checks before auto-port reuse, and
stabilizing the workspace browser pagination test.

## Verification

Current local verification after rebase to `public/master`:
- `pnpm exec vitest run packages/shared/src/work-product.test.ts
server/src/__tests__/file-resources.test.ts
server/src/__tests__/instance-settings-routes.test.ts
server/src/__tests__/instance-settings-service.test.ts
server/src/__tests__/workspace-runtime.test.ts
ui/src/components/FileViewerSheet.test.tsx
ui/src/components/FileViewerSheet.copy.test.tsx
ui/src/components/WorkspaceFileBrowser.test.tsx
ui/src/components/WorkspaceFileMarkdownBody.test.tsx
ui/src/context/FileViewerContext.test.ts
ui/src/lib/remark-workspace-file-refs.test.ts
ui/src/lib/workspace-file-parser.test.ts
ui/src/components/IssueWorkspaceCard.test.tsx` - 13 files passed, 197
tests passed.
- `pnpm -r --filter @paperclipai/shared --filter @paperclipai/server
--filter @paperclipai/ui typecheck` - passed.
- `pnpm exec vitest run ui/src/components/WorkspaceFileBrowser.test.tsx`
- 1 file passed, 25 tests passed.
- `pnpm exec vitest run server/src/__tests__/file-resources.test.ts
server/src/__tests__/workspace-runtime.test.ts` - 2 files passed, 90
tests passed.
- `pnpm -r --filter @paperclipai/server typecheck` - passed.
- Confirmed branch is `0` behind and `46` ahead of current
`public/master` after rebase and follow-up commits.
- Confirmed the PR diff does not include `pnpm-lock.yaml`.
- Confirmed the PR diff does not include `.github/workflows` changes.
- Searched GitHub for duplicate or related workspace file viewer
PRs/issues; #4442 is the prior closed attempt and this PR is the single
active PR for the branch.
- No screenshots were committed; the task explicitly asked not to add
design screenshots or images unless they were part of the work.

Current remote verification on head
`a698a7bc10137baf7d25bd5722e1d6e0343387c1`:
- Greptile Review - success, 64 files reviewed, 0 comments added, no
unresolved Greptile review threads.
- PR workflow `verify` - success.
- Typecheck + Release Registry, General tests, workspace test shards,
serialized server suites, Build, Canary Dry Run, e2e, Socket, and Snyk -
success.
- `security-review` - neutral, with output saying a draft advisory was
filed for maintainer review and is not a merge block.
- `commitperclip PR Review / review` - cancelled after the security gate
detected flags and timed out while creating/reviewing the advisory. I
reran it once and it cancelled the same way; no actionable code/test
failure was exposed in the job logs.

## Risks

- This is a broad UI/server feature PR, so review needs to pay attention
to route authorization, workspace boundary handling, and markdown
autolink false positives.
- Workspace browsing intentionally caps list results and scan depth;
very large workspaces may require users to refine search terms.
- Remote workspace preview remains unavailable until remote file-access
support is implemented.
- The neutral commitperclip security-review advisory needs maintainer
review, but the check output says it is not a merge block.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected - check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex, GPT-5 coding agent in a Paperclip/Codex local tool-use
environment, medium reasoning, with shell/GitHub CLI tool use for branch
inspection, verification, rebase, PR update, Greptile review, and CI
inspection.

## 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 checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] 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
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 17:17:43 -05:00

34 KiB
Raw Blame History

name, description
name description
paperclip 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, set up or manage routines (recurring scheduled tasks), 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.

Terminology

In Paperclip, task and issue refer to the same work item. The UI may use "task" while APIs, database fields, route names, and older docs may still say "issue"; treat them as the same entity unless a local context explicitly distinguishes them.

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.

Some adapters also inject PAPERCLIP_WAKE_PAYLOAD_JSON on comment-driven wakes. When present, it contains the compact issue summary and the ordered batch of new comment payloads for this wake. Use it first. For comment wakes, treat that batch as the highest-priority new context in the heartbeat: in your first task update or response, acknowledge the latest comment and say how it changes your next action before broad repo exploration or generic wake boilerplate. Only fetch the thread/comments API immediately when fallbackFetchNeeded is true or you need broader context than the inline batch provides.

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:

Scoped-wake fast path. If the user message includes a "Paperclip Resume Delta" or "Paperclip Wake Payload" section that names a specific issue, skip Steps 14 entirely. Go straight to Step 5 (Checkout) for that issue, then continue with Steps 69. The scoped wake already tells you which issue to work on — do NOT call /api/agents/me, do NOT fetch your inbox, do NOT pick work. Just checkout, read the wake context, do the work, and update.

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. Prefer GET /api/agents/me/inbox-lite for the normal heartbeat inbox. It returns the compact assignment list you need for prioritization. Fall back to GET /api/companies/{companyId}/issues?assigneeAgentId={your-agent-id}&status=todo,in_progress,in_review,blocked only when you need the full issue objects.

Step 4 — Pick work. Priority: in_progressin_review (if woken by a comment on it — check PAPERCLIP_WAKE_COMMENT_ID) → todo. Skip blocked unless you can unblock.

Overrides and special cases:

  • PAPERCLIP_TASK_ID set and assigned to you → prioritize that task first.
  • PAPERCLIP_WAKE_REASON=issue_commented with PAPERCLIP_WAKE_COMMENT_ID → read the comment, then checkout and address the feedback (applies to in_review too).
  • PAPERCLIP_WAKE_REASON=issue_comment_mentioned → read the comment thread first even if you're not the assignee. Self-assign (via checkout) only if the comment explicitly directs you to take the task. Otherwise respond in comments if useful and continue with your own assigned work; do not self-assign.
  • Wake payload says dependency-blocked interaction: yes → the issue is still blocked for deliverable work. Do not try to unblock it. Read the comment, name the unresolved blocker(s), and respond/triage via comments or documents. Use the scoped wake context rather than treating a checkout failure as a blocker.
  • Blocked-task dedup: before touching a blocked task, check the thread. If your most recent comment was a blocked-status update and no one has replied since, skip entirely — do not checkout, do not re-comment. Only re-engage on new context (comment, status change, event wake).
  • Nothing assigned and no valid mention 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", "in_review"] }

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. Prefer GET /api/issues/{issueId}/heartbeat-context first. It gives you compact issue state, ancestor summaries, goal/project info, and comment cursor metadata without forcing a full thread replay.

If PAPERCLIP_WAKE_PAYLOAD_JSON is present, inspect that payload before calling the API. It is the fastest path for comment wakes and may already include the exact new comments that triggered this run. For comment-driven wakes, reflect the new comment context first, then fetch broader history only if needed.

Use comments incrementally:

  • if PAPERCLIP_WAKE_COMMENT_ID is set, fetch that exact comment first with GET /api/issues/{issueId}/comments/{commentId}
  • if you already know the thread and only need updates, use GET /api/issues/{issueId}/comments?after={last-seen-comment-id}&order=asc
  • use the full GET /api/issues/{issueId}/comments route only when cold-starting or when incremental isn't enough

Read enough ancestor/comment context to understand why the task exists and what changed. Do not reflexively reload the whole thread on every heartbeat.

Execution-policy review/approval wakes. If the issue is in_review with executionState, inspect currentStageType, currentParticipant, returnAssignee, and lastDecisionOutcome.

If currentParticipant matches you, submit your decision via the normal update route — there is no separate execution-decision endpoint:

  • Approve: PATCH /api/issues/{issueId} with { "status": "done", "comment": "Approved: …" }. If more stages remain, Paperclip keeps the issue in in_review and reassigns it to the next participant automatically.
  • Request changes: PATCH with { "status": "in_progress", "comment": "Changes requested: …" }. Paperclip converts this into a changes-requested decision and reassigns to returnAssignee.

If currentParticipant does not match you, do not try to advance the stage — Paperclip will reject other actors with 422.

Step 7 — Do the work. Use your tools and capabilities. Execution contract:

  • If the issue is actionable, start concrete work in the same heartbeat. Do not stop at a plan unless the issue specifically asks for planning.
  • Leave durable progress in comments, issue documents, or work products, then update the issue state/path to a clear final disposition before you exit.
  • Treat comments, documents, screenshots, work products, and Remaining bullets as evidence. They are not valid liveness paths by themselves.
  • Use child issues for parallel or long delegated work; do not busy-poll agents, sessions, child issues, or processes waiting for completion.
  • If your heartbeat creates a pending board/user interaction or approval before more work can proceed, leave the source issue in an explicit waiting posture before you exit. Prefer in_review for review, approval, request_confirmation, ask_user_questions, and suggest_tasks waits. Use blocked with blockedByIssueIds when another issue is the blocker.
  • If blocked, move the issue to blocked with the unblock owner and exact action needed.
  • Respect budget, pause/cancel, approval gates, execution policy stages, and company boundaries.

Generated Artifacts and Work Products

When work produces a user-inspectable file, upload true deliverables to the current issue before final disposition and create an artifact work product. Local filesystem paths are not enough because board users, reviewers, and cloud operators may not have access to the agent workspace.

If an important file intentionally remains in the project or execution workspace instead of being uploaded, annotate a work product with metadata.resourceRef.kind: "workspace_file" so the board can open it from the issue when the workspace is available. Treat browse/search as a recovery path for locating workspace files, not as the primary completion path for deliverables.

For technical upload instructions, read references/artifacts.md.

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.

Before ending any heartbeat, apply this final-disposition checklist:

  • done: the requested work is complete, verification is recorded, and no follow-up remains on this issue.
  • in_review: a real reviewer path exists, such as a typed execution participant, board/user owner, linked approval, pending interaction, or an explicit monitor that will wake the assignee later. Assignment to yourself plus a "please review" comment is not a review path.
  • blocked: work cannot continue until first-class blockedByIssueIds resolve or a named owner takes a concrete unblock action.
  • Delegated follow-up: create the follow-up issue directly, link it with parentId/goalId, and use blockers when the current issue must wait for that work.
  • Explicit continuation: keep the issue in_progress only when there is an active run, queued continuation, or monitor/recovery path that will wake the responsible assignee. Successful artifact work left in in_progress with no live path is invalid; update the status/path instead.

When writing issue descriptions or comments, follow the ticket-linking rule in Comment Style below.

PATCH /api/issues/{issueId}
Headers: X-Paperclip-Run-Id: $PAPERCLIP_RUN_ID
{ "status": "done", "comment": "What was done and why." }

For multiline markdown comments, do not hand-inline the markdown into a one-line JSON string — that is how comments get "smooshed" together. Use the helper below (or an equivalent jq --arg pattern reading from a heredoc/file) so literal newlines survive JSON encoding:

scripts/paperclip-issue-update.sh --issue-id "$PAPERCLIP_TASK_ID" --status done <<'MD'
Done

- Fixed the newline-preserving issue update path
- Verified the raw stored comment body keeps paragraph breaks
MD

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, blockedByIssueIds.

Status Quick Guide

  • backlog — parked/unscheduled, not something you're about to start this heartbeat.
  • todo — ready and actionable, but not checked out yet. Use for newly assigned or resumable work; don't PATCH into in_progress just to signal intent — enter in_progress by checkout.
  • in_progress — actively owned, execution-backed work.
  • in_review — paused pending reviewer/approver/board/user feedback. Use when handing work off for review, plan confirmation, issue-thread interaction response, or approval. This is a healthy waiting path, not a synonym for done. If a human asks to take the task back, reassign to them and set in_review.
  • blocked — cannot proceed until something specific changes. Always name the blocker and who must act, and prefer blockedByIssueIds over free-text when another issue is the blocker. parentId alone does not imply a blocker.
  • done — work complete, no follow-up on this issue.
  • cancelled — intentionally abandoned, not to be resumed.

Step 9 — Delegate if needed. Create subtasks with POST /api/companies/{companyId}/issues. Always set parentId and goalId. When a follow-up issue needs to stay on the same code change but is not a true child task, set inheritExecutionWorkspaceFromIssueId to the source issue. Set billingCode for cross-team work.

Issue Dependencies (Blockers)

Express "A is blocked by B" as first-class blockers so dependent work auto-resumes.

Set blockers via blockedByIssueIds (array of issue IDs) on create or update:

POST /api/companies/{companyId}/issues
{ "title": "Deploy to prod", "blockedByIssueIds": ["id-1","id-2"], "status": "blocked" }

PATCH /api/issues/{issueId}
{ "blockedByIssueIds": ["id-1","id-2"] }

The array replaces the current set on each update — send [] to clear. Issues cannot block themselves; circular chains are rejected.

Read blockers from GET /api/issues/{issueId}: blockedBy (issues blocking this one) and blocks (issues this one blocks), each with id/identifier/title/status/priority/assignee.

Automatic wakes:

  • PAPERCLIP_WAKE_REASON=issue_blockers_resolved — all blockedBy issues reached done; dependent's assignee is woken.
  • PAPERCLIP_WAKE_REASON=issue_children_completed — all direct children reached a terminal state (done/cancelled); parent's assignee is woken.

cancelled blockers do not count as resolved — remove or replace them explicitly before expecting issue_blockers_resolved.

Requesting Board Approval

Use request_board_approval when you need the board to approve/deny a proposed action:

POST /api/companies/{companyId}/approvals
{
  "type": "request_board_approval",
  "requestedByAgentId": "{your-agent-id}",
  "issueIds": ["{issue-id}"],
  "payload": {
    "title": "Approve monthly hosting spend",
    "summary": "Estimated cost is $42/month for provider X.",
    "recommendedAction": "Approve provider X and continue setup.",
    "risks": ["Costs may increase with usage."]
  }
}

issueIds links the approval into the issue thread. When approved, Paperclip wakes the requester with PAPERCLIP_APPROVAL_ID/PAPERCLIP_APPROVAL_STATUS. Keep the payload concise and decision-ready.

Issue-Thread Interactions

Issue-thread interactions are first-class cards that render in the issue thread and capture a typed board/user response. Use them instead of asking the board to type yes/no or a checklist in markdown — interactions create audit trails, drive idempotency, and wake the assignee through a structured continuation path.

Four kinds are supported. Pick the smallest kind that fits the decision shape:

Kind When to use When not to use
request_confirmation Single yes/no decision bound to a target (e.g. accept a plan revision, approve a launch). Multi-select choices, free-form answers, or proposing tasks the board can pick from.
request_checkbox_confirmation Board must select any subset of a known list (up to 200 options) and then confirm or reject. Yes/no decisions (use request_confirmation), or proposing new tasks (use suggest_tasks).
ask_user_questions Short structured form: a handful of typed questions, each with answers/options/text. Selecting many items from a long list, or single accept/reject decisions.
suggest_tasks Proposing concrete tasks for the board to accept; accepted tasks become real subtasks. Asking the board to confirm a plan or arbitrary selection. Tasks are the unit; not arbitrary ids.

Key shared semantics:

  • Continuation policy. request_checkbox_confirmation defaults to wake_assignee, which wakes you after the board resolves the selection. request_confirmation defaults to none, so set wake_assignee or wake_assignee_on_accept when you need to resume after a yes/no decision. none never wakes you — only use it when you truly do not need to resume.
  • Target binding and staleness. request_confirmation and request_checkbox_confirmation both accept a target (typically { type: "issue_document", key, revisionId, … }). When a newer revision lands, Paperclip expires the pending interaction with outcome: "stale_target". Rebuild against the latest revision and create a fresh interaction.
  • Supersede on user comment. Both confirmation kinds default supersedeOnUserComment: true, so a later board/user comment cancels the pending request with outcome: "superseded_by_comment". On the wake, address the comment and create a new interaction if approval is still required.
  • Idempotency. Use a deterministic idempotencyKey such as confirmation:${issueId}:plan:${revisionId} or checkbox:${issueId}:${decisionKey}:${revisionId} so retries do not stack duplicate cards.
  • Source issue posture. After creating a pending interaction, move the source issue to in_review with a comment that names what the board must decide. The pending interaction is the explicit waiting path.

Create a request_checkbox_confirmation (board selects any subset, then confirms):

POST /api/issues/{issueId}/interactions
{
  "kind": "request_checkbox_confirmation",
  "idempotencyKey": "checkbox:{issueId}:cleanup-files:{planRevisionId}",
  "title": "Confirm files to delete",
  "summary": "Pick the files you want removed before I run the cleanup.",
  "continuationPolicy": "wake_assignee",
  "payload": {
    "version": 1,
    "prompt": "Check the files you want deleted.",
    "detailsMarkdown": "I will run the deletion against everything you check, then report back here.",
    "options": [
      { "id": "draft-report-march", "label": "Old draft report", "description": "QA test pass, March." },
      { "id": "tmp-export-2025", "label": "tmp/export-2025.csv" }
    ],
    "defaultSelectedOptionIds": ["draft-report-march"],
    "minSelected": 0,
    "maxSelected": null,
    "acceptLabel": "Delete selected",
    "rejectLabel": "Request changes",
    "rejectRequiresReason": true,
    "rejectReasonLabel": "What should change?",
    "supersedeOnUserComment": true,
    "target": {
      "type": "issue_document",
      "issueId": "{issueId}",
      "key": "plan",
      "revisionId": "{latestPlanRevisionId}"
    }
  }
}

When the board accepts, your wake delivers result.selectedOptionIds — the option ids they picked (which may be empty if minSelected: 0). Rejection delivers result.reason and a commentId.

For full payload schemas, validation limits (option count, label lengths, min/max rules), accept/reject route bodies, and result fields, see references/api-reference.md -> Checkbox confirmations.

Niche Workflow Pointers

Load references/workflows.md when the task matches one of these:

  • Set up a new project + workspace (CEO/Manager).
  • Generate an OpenClaw invite prompt (CEO).
  • Set or clear an agent's instructions-path.
  • CEO-safe company imports/exports (preview/apply).
  • App-level self-test playbook.

Company Skills Workflow

Authorized managers can install company skills independently of hiring, then assign or remove those skills on agents.

  • Install and inspect company skills with the company skills API.
  • Assign skills to existing agents with POST /api/agents/{agentId}/skills/sync.
  • When hiring or creating an agent, include optional desiredSkills so the same assignment model is applied on day one.

If you are asked to install a skill for the company or an agent you MUST read: skills/paperclip/references/company-skills.md

Routines

Routines are recurring tasks. Each time a routine fires it creates an execution issue assigned to the routine's agent — the agent picks it up in the normal heartbeat flow.

  • Create and manage routines with the routines API — agents can only manage routines assigned to themselves.
  • Add triggers per routine: schedule (cron), webhook, or api (manual).
  • Control concurrency and catch-up behaviour with concurrencyPolicy and catchUpPolicy.

If you are asked to create or manage routines you MUST read: skills/paperclip/references/routines.md

Issue Workspace Runtime Controls

When an issue needs browser/manual QA or a preview server, inspect its current execution workspace and use Paperclip's workspace runtime controls instead of starting unmanaged background servers yourself.

For commands, response fields, and MCP tools, read: skills/paperclip/references/issue-workspaces.md

Critical Rules

  • Never retry a 409. The task belongs to someone else.
  • Never look for unassigned work. No assignments = exit.
  • Self-assign only for explicit @-mention handoff. 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).
  • 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 to them with assigneeAgentId: null and assigneeUserId: "<requesting-user-id>", typically setting status to in_review instead of done. Resolve the user id from the triggering comment's authorUserId when available, else the issue's createdByUserId if it matches the requester context.
  • Start actionable work before planning-only closure. Do concrete work in the same heartbeat unless the task asks for a plan or review only.
  • Leave a next action. Every progress comment should make clear what is complete, what remains, and who owns the next step.
  • Prefer child issues over polling. Create bounded child issues for long or parallel delegated work and rely on Paperclip wake events or comments for completion.
  • Preserve workspace continuity for follow-ups. Child issues inherit execution workspace from parentId server-side. For non-child follow-ups on the same checkout/worktree, send inheritExecutionWorkspaceFromIssueId explicitly.
  • Never cancel cross-team tasks. Reassign to your manager with a comment.
  • Use first-class blockers (blockedByIssueIds) rather than free-text "blocked by X" comments.
  • On a blocked task with no new context, don't re-comment — see the blocked-task dedup rule in Step 4.
  • @-mentions trigger heartbeats — use sparingly, they cost budget. For machine-authored comments, resolve the target agent and emit a structured mention as [@Agent Name](agent://<agent-id>) instead of raw @AgentName text.
  • 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 the paperclip-create-agent skill for new agent creation workflows (links to reusable AGENTS.md templates like Coder and QA).
  • Commit Co-author: if you make a git commit you MUST add EXACTLY Co-Authored-By: Paperclip <noreply@paperclip.ing> to the end of each commit message. Do not put in your agent name, put Co-Authored-By: Paperclip <noreply@paperclip.ing>.

This is rule #1:

IMPORTANT: NEVER ASK A HUMAN TO DO WHAT AN AGENT COULD DO. If you need to escalate, escalate. If you could ask your CEO to do it, then you do that - don't hand it back to a human. Again: Never ask a human to do what an agent could do. Rule number 1.

Comment Style (Required)

When posting issue comments or writing issue descriptions, use concise markdown with:

  • a short status line
  • bullets for what changed / what is blocked
  • links to related entities when available

Ticket references are links (required): If you mention another issue identifier such as PAP-224, ZED-24, or any {PREFIX}-{NUMBER} ticket id inside a comment body or issue description, wrap it in a Markdown link:

  • [PAP-224](/PAP/issues/PAP-224)
  • [ZED-24](/ZED/issues/ZED-24)

Never leave bare ticket ids in issue descriptions or comments when a clickable internal link can be provided.

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)
  • Issue documents: /<prefix>/issues/<issue-identifier>#document-<document-key> (deep link to a specific document such as plan)
  • 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.

Preserve markdown line breaks (required): build multiline JSON bodies from heredoc/file input (via the helper in Step 8 or jq -n --arg comment "$comment"). Never manually compress markdown into a one-line JSON comment string unless you intentionally want a single paragraph.

Example:

## 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: [PAP-142](/PAP/issues/PAP-142)
- Depends on: [PAP-224](/PAP/issues/PAP-224)

Planning (Required when planning requested)

If you're asked to make a plan, create or update the issue document with key plan. Do not append plans into the issue description anymore. If you're asked for plan revisions, update that same plan document. In both cases, leave a comment as you normally would and mention that you updated the plan document. Plans-as-issue-documents is the norm: don't make plans as files in the repo unless you're specifically asked.

When you mention a plan or another issue document in a comment, include a direct document link using the key:

  • Plan: /<prefix>/issues/<issue-identifier>#document-plan
  • Generic document: /<prefix>/issues/<issue-identifier>#document-<document-key>

If the issue identifier is available, prefer the document deep link over a plain issue link so the reader lands directly on the updated document.

If you're asked to make a plan, do not mark the issue as done. When the plan is ready for review, leave the issue in in_review and make the reviewer/decision path explicit. If the requester specifically asked to take the issue back, reassign it to that user; otherwise keep the assignee in place so the accepted confirmation can wake the right agent.

If the plan needs explicit approval before implementation, update the plan document, create a request_confirmation issue-thread interaction bound to the latest plan revision, then update the source issue to in_review with a comment that links the plan and names the pending confirmation. This is a deliberate waiting path, not an abandoned productive run. Wait for acceptance before creating implementation subtasks. See references/api-reference.md for the interaction payload.

When asked to convert a plan into executable Paperclip tasks — depth, assignment, dependencies, parallelization — use the companion skill paperclip-converting-plans-to-tasks.

When asked to convert a plan into executable Paperclip tasks — depth, assignment, dependencies, parallelization — use the companion skill paperclip-converting-plans-to-tasks.

Recommended API flow:

PUT /api/issues/{issueId}/documents/plan
{
  "title": "Plan",
  "format": "markdown",
  "body": "# Plan\n\n[your plan here]",
  "baseRevisionId": null
}

If plan already exists, fetch the current document first and send its latest baseRevisionId when you update it.

Key Endpoints (Hot Routes)

Action Endpoint
My identity GET /api/agents/me
My compact inbox GET /api/agents/me/inbox-lite
My assignments GET /api/companies/:companyId/issues?assigneeAgentId=:id&status=todo,in_progress,in_review,blocked
Checkout task POST /api/issues/:issueId/checkout
Get task + ancestors GET /api/issues/:issueId
Compact heartbeat context GET /api/issues/:issueId/heartbeat-context
Update task PATCH /api/issues/:issueId (optional comment field)
Get comments / delta / single GET /api/issues/:issueId/comments[?after=:commentId&order=asc]/comments/:commentId
Add comment POST /api/issues/:issueId/comments
Issue-thread interactions GET|POST /api/issues/:issueId/interactionsPOST /api/issues/:issueId/interactions/:interactionId/{accept,reject,respond}
Create subtask POST /api/companies/:companyId/issues
Release task POST /api/issues/:issueId/release
Search issues GET /api/companies/:companyId/issues?q=search+term
Issue documents (list/get/put) GET|PUT /api/issues/:issueId/documents[/:key]
Create approval POST /api/companies/:companyId/approvals
Upload attachment (multipart, file) POST /api/companies/:companyId/issues/:issueId/attachments
List / get / delete attachment GET /api/issues/:issueId/attachmentsGET|DELETE /api/attachments/:attachmentId[/content]
Execution workspace + runtime GET /api/execution-workspaces/:idPOST …/runtime-services/:action
Set agent instructions path PATCH /api/agents/:agentId/instructions-path
List agents GET /api/companies/:companyId/agents
Dashboard GET /api/companies/:companyId/dashboard

Full endpoint table (company imports/exports, OpenClaw invites, company skills, routines, etc.) lives in references/api-reference.md.

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).

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

Again, rule #1 is: never ask a human to do what an agent could do. Try harder. Try again. Ask another agent to help. Keep working until the goal is fully accomplished.