From 9499d0df973349e7adfec27892d05eb58779961c Mon Sep 17 00:00:00 2001 From: dotta Date: Sat, 4 Apr 2026 19:34:14 -0500 Subject: [PATCH] Add blocker/dependency documentation to Paperclip skill Document blockedByIssueIds field, issue_blockers_resolved and issue_children_completed wake reasons, and blockedBy/blocks response arrays in both SKILL.md and api-reference.md so agents know how to set and use first-class issue dependencies. Co-Authored-By: Paperclip --- skills/paperclip/SKILL.md | 41 +++++++++++++++++++- skills/paperclip/references/api-reference.md | 14 +++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/skills/paperclip/SKILL.md b/skills/paperclip/SKILL.md index fae34f35..43a69b41 100644 --- a/skills/paperclip/SKILL.md +++ b/skills/paperclip/SKILL.md @@ -88,10 +88,48 @@ 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`. +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`. **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) + +Paperclip supports first-class blocker relationships between issues. Use these to express "issue A is blocked by issue B" so that dependent work automatically resumes when blockers are resolved. + +### Setting blockers + +Pass `blockedByIssueIds` (an array of issue IDs) when creating or updating an issue: + +```json +// At creation time +POST /api/companies/{companyId}/issues +{ "title": "Deploy to prod", "blockedByIssueIds": ["issue-id-1", "issue-id-2"], "status": "blocked", ... } + +// After the fact +PATCH /api/issues/{issueId} +{ "blockedByIssueIds": ["issue-id-1", "issue-id-2"] } +``` + +The `blockedByIssueIds` array **replaces** the existing blocker set on each update. To add a blocker, include the full list. To remove all blockers, send `[]`. + +Constraints: issues cannot block themselves, and circular blocker chains are rejected. + +### Reading blockers + +`GET /api/issues/{issueId}` returns two relation arrays: + +- `blockedBy` — issues that block this one (with `id`, `identifier`, `title`, `status`, `priority`, assignee info) +- `blocks` — issues that this one blocks + +### Automatic wake-on-dependency-resolved + +Paperclip fires automatic wakes in two scenarios: + +1. **All blockers done** (`PAPERCLIP_WAKE_REASON=issue_blockers_resolved`): When every issue in the `blockedBy` set reaches `done`, the dependent issue's assignee is woken to resume work. +2. **All children done** (`PAPERCLIP_WAKE_REASON=issue_children_completed`): When every direct child issue of a parent reaches a terminal state (`done` or `cancelled`), the parent issue's assignee is woken to finalize or close out. + +When you receive one of these wake reasons, check the issue state and continue the work or mark it done. + ## 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: @@ -166,6 +204,7 @@ If you are asked to create or manage routines you MUST read: - **Preserve workspace continuity for follow-ups.** Child issues inherit execution workspace linkage server-side from `parentId`. For non-child follow-ups tied to the same checkout/worktree, send `inheritExecutionWorkspaceFromIssueId` explicitly instead of relying on free-text references or memory. - **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. +- **Use first-class blockers** when a task depends on other tasks. Set `blockedByIssueIds` on the dependent issue so Paperclip automatically wakes the assignee when all blockers are done. Prefer this over ad-hoc "blocked by X" comments. - **@-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. diff --git a/skills/paperclip/references/api-reference.md b/skills/paperclip/references/api-reference.md index 7b341927..60f02803 100644 --- a/skills/paperclip/references/api-reference.md +++ b/skills/paperclip/references/api-reference.md @@ -109,6 +109,8 @@ POST /api/companies/company-1/exports 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: + ```json { "id": "issue-99", @@ -116,6 +118,10 @@ Includes the issue's `project` and `goal` (with descriptions), plus each ancesto "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", @@ -290,7 +296,8 @@ 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" } +{ "title": "Write load test suite", "assigneeAgentId": "agent-55", "parentId": "issue-30", "status": "blocked", "priority": "medium", "goalId": "goal-1", "blockedByIssueIds": [""] } +# ^ 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." } @@ -617,8 +624,8 @@ Terminal states: `done`, `cancelled` | 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 | -| PATCH | `/api/issues/:issueId` | Update issue (optional `comment` field adds a comment in same call) | +| 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 | @@ -719,3 +726,4 @@ Terminal states: `done`, `cancelled` | @-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 |