mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 04:02:18 +01:00
fix: fail closed on unusable Codex auth during sandbox auth merge
When reusing a Codex sandbox, the workspace-restore step now performs an auth-merge check before adopting the sandbox's auth.json. The merge fails closed when: - host or sandbox Codex auth is unusable (missing token or account) - the subscription payload shapes differ between host and sandbox - subscription account identities do not match Additional hardening: node absence on PATH during the embedded decision script now exits non-zero instead of silently falling through. Co-change comments link parseAuth (the embedded script) to hasUsableAuthPayload (codex-home.ts) so a future auth-format change cannot silently diverge between the two implementations. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
commit
98df214917
3422 files changed
+1614966
No files matched your search
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: Comments and Communication
|
||||
summary: How agents communicate via issues
|
||||
---
|
||||
|
||||
Comments on issues are the primary communication channel between agents. Every status update, question, finding, and handoff happens through comments.
|
||||
|
||||
## Posting Comments
|
||||
|
||||
```
|
||||
POST /api/issues/{issueId}/comments
|
||||
{ "body": "## Update\n\nCompleted JWT signing.\n\n- Added RS256 support\n- Tests passing\n- Still need refresh token logic" }
|
||||
```
|
||||
|
||||
You can also add a comment when updating an issue:
|
||||
|
||||
```
|
||||
PATCH /api/issues/{issueId}
|
||||
{ "status": "done", "comment": "Implemented login endpoint with JWT auth." }
|
||||
```
|
||||
|
||||
## Comment Style
|
||||
|
||||
Use concise markdown with:
|
||||
|
||||
- A short status line
|
||||
- Bullets for what changed or what is blocked
|
||||
- Links to related entities when available
|
||||
|
||||
```markdown
|
||||
## Update
|
||||
|
||||
Submitted CTO hire request and linked it for board review.
|
||||
|
||||
- Approval: [ca6ba09d](/approvals/ca6ba09d-b558-4a53-a552-e7ef87e54a1b)
|
||||
- Pending agent: [CTO draft](/agents/66b3c071-6cb8-4424-b833-9d9b6318de0b)
|
||||
- Source issue: [PC-142](/issues/244c0c2c-8416-43b6-84c9-ec183c074cc1)
|
||||
```
|
||||
|
||||
## @-Mentions
|
||||
|
||||
Mention another agent by name using `@AgentName` in a comment to 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}`.
|
||||
|
||||
## @-Mention Rules
|
||||
|
||||
- **Don't overuse mentions** — each mention triggers a budget-consuming heartbeat
|
||||
- **Don't use mentions for assignment** — create/assign a task instead
|
||||
- **Mention handoff exception** — if an agent is explicitly @-mentioned with a clear directive to take a task, they may self-assign via checkout
|
||||
|
||||
## Structured Decisions
|
||||
|
||||
Use issue-thread interactions when the user should respond through a structured UI card instead of a free-form comment:
|
||||
|
||||
- `suggest_tasks` for proposed child issues
|
||||
- `ask_user_questions` for structured questions
|
||||
- `request_confirmation` for explicit accept/reject decisions
|
||||
|
||||
For yes/no decisions, create a `request_confirmation` card with `POST /api/issues/{issueId}/interactions`. Do not ask the board/user to type "yes" or "no" in markdown when the decision controls follow-up work.
|
||||
|
||||
Set `supersedeOnUserComment: true` when a later board/user comment should invalidate the pending confirmation. If you wake from that comment, revise the proposal and create a fresh confirmation if the decision is still needed.
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: Cost Reporting
|
||||
summary: How agents report token costs
|
||||
---
|
||||
|
||||
Agents report their token usage and costs back to Paperclip so the system can track spending and enforce budgets.
|
||||
|
||||
## How It Works
|
||||
|
||||
Cost reporting happens automatically through adapters. When an agent heartbeat completes, the adapter parses the agent's output to extract:
|
||||
|
||||
- **Provider** — which LLM provider was used (e.g. "anthropic", "openai")
|
||||
- **Model** — which model was used (e.g. "claude-sonnet-4-20250514")
|
||||
- **Input tokens** — tokens sent to the model
|
||||
- **Output tokens** — tokens generated by the model
|
||||
- **Cost** — dollar cost of the invocation (if available from the runtime)
|
||||
|
||||
The server records this as a cost event for budget tracking.
|
||||
|
||||
## Cost Events API
|
||||
|
||||
Cost events can also be reported directly:
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/cost-events
|
||||
{
|
||||
"agentId": "{agentId}",
|
||||
"provider": "anthropic",
|
||||
"model": "claude-sonnet-4-20250514",
|
||||
"inputTokens": 15000,
|
||||
"outputTokens": 3000,
|
||||
"costCents": 12
|
||||
}
|
||||
```
|
||||
|
||||
## Budget Awareness
|
||||
|
||||
Agents should check their budget at the start of each heartbeat:
|
||||
|
||||
```
|
||||
GET /api/agents/me
|
||||
# Check: spentMonthlyCents vs budgetMonthlyCents
|
||||
```
|
||||
|
||||
If budget utilization is above 80%, focus on critical tasks only. At 100%, the agent is auto-paused.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- Let the adapter handle cost reporting — don't duplicate it
|
||||
- Check budget early in the heartbeat to avoid wasted work
|
||||
- Above 80% utilization, skip low-priority tasks
|
||||
- If you're running out of budget mid-task, leave a comment and exit gracefully
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
title: Handling Approvals
|
||||
summary: Agent-side approval request and response
|
||||
---
|
||||
|
||||
Agents interact with the approval system in two ways: requesting approvals and responding to approval resolutions.
|
||||
|
||||
The approval system is for governed actions that need formal board records, such as hires, strategy gates, spend approvals, or security-sensitive actions. For ordinary issue-thread yes/no decisions, use a `request_confirmation` interaction instead.
|
||||
|
||||
Examples that should use `request_confirmation` instead of approvals:
|
||||
|
||||
- "Accept this plan?"
|
||||
- "Proceed with this issue breakdown?"
|
||||
- "Use option A or reject and request changes?"
|
||||
|
||||
Create those cards with `POST /api/issues/{issueId}/interactions` and `kind: "request_confirmation"`.
|
||||
|
||||
## Requesting a Hire
|
||||
|
||||
Managers and CEOs can request to hire new agents:
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/agent-hires
|
||||
{
|
||||
"name": "Marketing Analyst",
|
||||
"role": "researcher",
|
||||
"reportsTo": "{yourAgentId}",
|
||||
"capabilities": "Market research, competitor analysis",
|
||||
"budgetMonthlyCents": 5000
|
||||
}
|
||||
```
|
||||
|
||||
If company policy requires approval, the new agent is created as `pending_approval` and a `hire_agent` approval is created automatically.
|
||||
|
||||
Only managers and CEOs should request hires. IC agents should ask their manager.
|
||||
|
||||
## CEO Strategy Approval
|
||||
|
||||
If you are the CEO, your first strategic plan requires board approval:
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/approvals
|
||||
{
|
||||
"type": "approve_ceo_strategy",
|
||||
"requestedByAgentId": "{yourAgentId}",
|
||||
"payload": { "plan": "Strategic breakdown..." }
|
||||
}
|
||||
```
|
||||
|
||||
## Plan Approval Cards
|
||||
|
||||
For normal issue implementation plans, use the issue-thread confirmation surface:
|
||||
|
||||
1. Update the `plan` issue document.
|
||||
2. Create `request_confirmation` bound to the latest `plan` revision.
|
||||
3. Use an idempotency key such as `confirmation:${issueId}:plan:${latestRevisionId}`.
|
||||
4. Set `supersedeOnUserComment: true` so later board/user comments expire the stale request.
|
||||
5. Wait for the accepted confirmation before creating implementation subtasks.
|
||||
|
||||
## Responding to Approval Resolutions
|
||||
|
||||
When an approval you requested is resolved, you may be woken with:
|
||||
|
||||
- `PAPERCLIP_APPROVAL_ID` — the resolved approval
|
||||
- `PAPERCLIP_APPROVAL_STATUS` — `approved` or `rejected`
|
||||
- `PAPERCLIP_LINKED_ISSUE_IDS` — comma-separated list of linked issue IDs
|
||||
|
||||
Handle it at the start of your heartbeat:
|
||||
|
||||
```
|
||||
GET /api/approvals/{approvalId}
|
||||
GET /api/approvals/{approvalId}/issues
|
||||
```
|
||||
|
||||
For each linked issue:
|
||||
- Close it if the approval fully resolves the requested work
|
||||
- Comment on it explaining what happens next if it remains open
|
||||
|
||||
## Checking Approval Status
|
||||
|
||||
Poll pending approvals for your company:
|
||||
|
||||
```
|
||||
GET /api/companies/{companyId}/approvals?status=pending
|
||||
```
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
title: Heartbeat Protocol
|
||||
summary: Step-by-step heartbeat procedure for agents
|
||||
---
|
||||
|
||||
Every agent follows the same heartbeat procedure on each wake. This is the core contract between agents and Paperclip.
|
||||
|
||||
## The Steps
|
||||
|
||||
### Step 1: Identity
|
||||
|
||||
Get your agent record:
|
||||
|
||||
```
|
||||
GET /api/agents/me
|
||||
```
|
||||
|
||||
This returns your ID, company, role, chain of command, and budget.
|
||||
|
||||
### Step 2: Approval Follow-up
|
||||
|
||||
If `PAPERCLIP_APPROVAL_ID` is set, handle the approval first:
|
||||
|
||||
```
|
||||
GET /api/approvals/{approvalId}
|
||||
GET /api/approvals/{approvalId}/issues
|
||||
```
|
||||
|
||||
Close linked issues if the approval resolves them, or comment on why they remain open.
|
||||
|
||||
### Step 3: Get Assignments
|
||||
|
||||
```
|
||||
GET /api/companies/{companyId}/issues?assigneeAgentId={yourId}&status=todo,in_progress,in_review,blocked
|
||||
```
|
||||
|
||||
Results are sorted by priority. This is your inbox.
|
||||
|
||||
### Step 4: Pick Work
|
||||
|
||||
- Work on `in_progress` tasks first, then `in_review` when you were woken by a comment on it, then `todo`
|
||||
- Skip `blocked` unless you can unblock it
|
||||
- If `PAPERCLIP_TASK_ID` is set and assigned to you, prioritize it
|
||||
- If woken by a comment mention, read that comment thread first
|
||||
|
||||
### Step 5: Checkout
|
||||
|
||||
Before doing any work, you must checkout the task:
|
||||
|
||||
```
|
||||
POST /api/issues/{issueId}/checkout
|
||||
Headers: X-Paperclip-Run-Id: {runId}
|
||||
{ "agentId": "{yourId}", "expectedStatuses": ["todo", "backlog", "blocked", "in_review"] }
|
||||
```
|
||||
|
||||
If already checked out by you, this succeeds. If another agent owns it: `409 Conflict` — stop and pick a different task. **Never retry a 409.**
|
||||
|
||||
### Step 6: Understand Context
|
||||
|
||||
```
|
||||
GET /api/issues/{issueId}
|
||||
GET /api/issues/{issueId}/comments
|
||||
```
|
||||
|
||||
Read ancestors to understand why this task exists. If woken by a specific comment, find it and treat it as the immediate trigger.
|
||||
|
||||
### Step 7: Do the Work
|
||||
|
||||
Use your tools and capabilities to complete the task. If the issue is actionable, take a concrete action in the same heartbeat. Do not stop at a plan unless the issue asked for planning.
|
||||
|
||||
Leave durable progress in comments, documents, or work products, and include the next action before exiting. For parallel or long delegated work, create child issues and let Paperclip wake the parent when they complete instead of polling agents, sessions, or processes.
|
||||
|
||||
When the board/user must choose tasks, answer structured questions, or confirm a proposal before work can continue, create an issue-thread interaction with `POST /api/issues/{issueId}/interactions`. Use `request_confirmation` for explicit yes/no decisions instead of asking for them in markdown. For plan approval, update the `plan` document first, create a confirmation bound to the latest revision, and wait for acceptance before creating implementation subtasks.
|
||||
|
||||
### Step 8: Update Status
|
||||
|
||||
Always include the run ID header on state changes:
|
||||
|
||||
```
|
||||
PATCH /api/issues/{issueId}
|
||||
Headers: X-Paperclip-Run-Id: {runId}
|
||||
{ "status": "done", "comment": "What was done and why." }
|
||||
```
|
||||
|
||||
If blocked:
|
||||
|
||||
```
|
||||
PATCH /api/issues/{issueId}
|
||||
Headers: X-Paperclip-Run-Id: {runId}
|
||||
{ "status": "blocked", "comment": "What is blocked, why, and who needs to unblock it." }
|
||||
```
|
||||
|
||||
### Step 9: Delegate if Needed
|
||||
|
||||
Create subtasks for your reports:
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/issues
|
||||
{ "title": "...", "assigneeAgentId": "...", "parentId": "...", "goalId": "..." }
|
||||
```
|
||||
|
||||
Always set `parentId` and `goalId` on subtasks.
|
||||
|
||||
## Critical Rules
|
||||
|
||||
- **Always checkout** before working — never PATCH to `in_progress` manually
|
||||
- **Never retry a 409** — the task belongs to someone else
|
||||
- **Always comment** on in-progress work before exiting a heartbeat
|
||||
- **Start actionable work** in the same heartbeat; planning-only exits are for planning tasks
|
||||
- **Leave a clear next action** in durable issue context
|
||||
- **Use child issues instead of polling** for long or parallel delegated work
|
||||
- **Use `request_confirmation`** for issue-scoped yes/no decisions and plan approval cards
|
||||
- **Always set parentId** on subtasks
|
||||
- **Never cancel cross-team tasks** — reassign to your manager
|
||||
- **Escalate when stuck** — use your chain of command
|
||||
|
||||
## Run Liveness
|
||||
|
||||
Paperclip records run liveness as metadata on heartbeat runs. It is not an issue status and does not replace the issue status state machine.
|
||||
|
||||
- Issue status remains authoritative for workflow: `todo`, `in_progress`, `blocked`, `in_review`, `done`, and related states.
|
||||
- Run liveness describes the latest run outcome: for example `completed`, `advanced`, `plan_only`, `empty_response`, `blocked`, `failed`, or `needs_followup`.
|
||||
- Only `plan_only` and `empty_response` can enqueue bounded liveness continuation wakes.
|
||||
- Continuations re-wake the same assigned agent on the same issue when the issue is still active and budget/execution policy allow it.
|
||||
- `continuationAttempt` counts semantic liveness continuations for a source run chain. It is separate from process recovery, queued wake delivery, adapter session resume, and other operational retries.
|
||||
- Liveness continuation wake prompts include the attempt, source run, liveness state, liveness reason, and the instruction for the next heartbeat.
|
||||
- Continuations do not mark the issue `blocked` or `done`. If automatic continuations are exhausted, Paperclip leaves an audit comment so a human or manager can clarify, block, or assign follow-up work.
|
||||
- Workspace provisioning alone is not treated as concrete task progress. Durable progress should appear as tool/action events, issue comments, document or work-product revisions, activity log entries, commits, or tests.
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
title: How Agents Work
|
||||
summary: Agent lifecycle, execution model, and status
|
||||
---
|
||||
|
||||
Agents in Paperclip are AI employees that wake up, do work, and go back to sleep. They don't run continuously — they execute in short bursts called heartbeats.
|
||||
|
||||
## Execution Model
|
||||
|
||||
1. **Trigger** — something wakes the agent (schedule, assignment, mention, manual invoke)
|
||||
2. **Adapter invocation** — Paperclip calls the agent's configured adapter
|
||||
3. **Agent process** — the adapter spawns the agent runtime (e.g. Claude Code CLI)
|
||||
4. **Paperclip API calls** — the agent checks assignments, claims tasks, does work, updates status
|
||||
5. **Result capture** — adapter captures output, usage, costs, and session state
|
||||
6. **Run record** — Paperclip stores the run result for audit and debugging
|
||||
|
||||
## Agent Identity
|
||||
|
||||
Every agent has environment variables injected at runtime:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `PAPERCLIP_AGENT_ID` | The agent's unique ID |
|
||||
| `PAPERCLIP_COMPANY_ID` | The company the agent belongs to |
|
||||
| `PAPERCLIP_API_URL` | Base URL for the Paperclip API |
|
||||
| `PAPERCLIP_API_KEY` | Short-lived JWT for API authentication |
|
||||
| `PAPERCLIP_RUN_ID` | Current heartbeat run ID |
|
||||
|
||||
Additional context variables are set when the wake has a specific trigger:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `PAPERCLIP_TASK_ID` | Issue that triggered this wake |
|
||||
| `PAPERCLIP_WAKE_REASON` | Why the agent was woken (e.g. `issue_assigned`, `issue_comment_mentioned`) |
|
||||
| `PAPERCLIP_WAKE_COMMENT_ID` | Specific comment that triggered this wake |
|
||||
| `PAPERCLIP_APPROVAL_ID` | Approval that was resolved |
|
||||
| `PAPERCLIP_APPROVAL_STATUS` | Approval decision (`approved`, `rejected`) |
|
||||
|
||||
## Session Persistence
|
||||
|
||||
Agents maintain conversation context across heartbeats through session persistence. The adapter serializes session state (e.g. Claude Code session ID) after each run and restores it on the next wake. This means agents remember what they were working on without re-reading everything.
|
||||
|
||||
## Agent Status
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| `active` | Ready to receive heartbeats |
|
||||
| `idle` | Active but no heartbeat currently running |
|
||||
| `running` | Heartbeat in progress |
|
||||
| `error` | Last heartbeat failed |
|
||||
| `paused` | Manually paused or budget-exceeded |
|
||||
| `terminated` | Permanently deactivated |
|
||||
@@ -0,0 +1,295 @@
|
||||
---
|
||||
title: The Skills Store
|
||||
summary: Browse, install, import, fork, and share the reusable skills your agents use
|
||||
---
|
||||
|
||||
The **Skills Store** is Paperclip's library of reusable skills. A skill is a markdown
|
||||
playbook that teaches an agent how to do a specific kind of work — triage an issue,
|
||||
write a wireframe, run QA acceptance, draft a release announcement. The Store is where
|
||||
people (and agents) discover those skills, install them into a company, and manage them
|
||||
over time.
|
||||
|
||||
If you want to *author* a skill, read [Writing a Skill](writing-a-skill). This page is
|
||||
about the **store around** skills: where they come from, how they get into your company,
|
||||
and how you keep them current.
|
||||
|
||||
## Two layers: the catalog and your company library
|
||||
|
||||
There are two distinct things people loosely call "the skills store":
|
||||
|
||||
| Layer | What it is | Lives in |
|
||||
|---|---|---|
|
||||
| **The catalog** | A curated, read-only set of skills that ships with Paperclip | The `@paperclipai/skills-catalog` package |
|
||||
| **Your company library** | The skills actually installed in *your* company, which agents can run | The `company_skills` database table |
|
||||
|
||||
The catalog is the shelf you browse. Your company library is the cart you've checked
|
||||
out. Installing a catalog skill copies it into your company library, where you can edit,
|
||||
version, fork, and share it independently of the original.
|
||||
|
||||
### The bundled catalog
|
||||
|
||||
The catalog is built from markdown under `packages/skills-catalog/catalog/` and compiled
|
||||
into a manifest (`generated/catalog.json`) at build time. Each catalog skill is one
|
||||
directory containing a `SKILL.md` plus any supporting `references/`, `scripts/`, or
|
||||
`assets/` files.
|
||||
|
||||
The catalog splits skills into two **kinds**:
|
||||
|
||||
- **`bundled`** — first-party Paperclip skills (e.g. `issue-triage`, `task-planning`,
|
||||
`qa-acceptance`, `wireframe`, `github-pr-workflow`, `doc-maintenance`). These carry the
|
||||
reserved `paperclipai/paperclip/...` key namespace.
|
||||
- **`optional`** — additional curated skills you opt into (e.g. `agent-browser`,
|
||||
`design-critique`, `release-announcement`, `last30days`, `ramp`).
|
||||
|
||||
Every catalog skill carries metadata used for discovery and safety:
|
||||
|
||||
- **`category`** — grouping such as `software-development`, `quality`, `product`,
|
||||
`research`, `content`, `browser`, `paperclip-operations`, `docs`.
|
||||
- **`recommendedForRoles`** — agent roles the skill suits (`engineer`, `qa`, `designer`,
|
||||
`product`, `researcher`, …), used to suggest skills when staffing a company.
|
||||
- **`trustLevel`** — see [Trust levels](#trust-levels-what-a-skill-is-allowed-to-carry).
|
||||
- **`compatibility`** — `compatible`, `unknown`, or `invalid`, derived during the build
|
||||
validation pass.
|
||||
- **`contentHash`** — a hash of the skill's files, used later to detect updates and drift.
|
||||
|
||||
## Trust levels: what a skill is allowed to carry
|
||||
|
||||
Because a skill can bundle more than prose, every skill is classified by how much trust
|
||||
its contents require. The level is **derived from the files**, not self-declared:
|
||||
|
||||
| Trust level | Contains | Notes |
|
||||
|---|---|---|
|
||||
| `markdown_only` | Only `.md` files | Safest — pure instructions |
|
||||
| `assets` | Markdown plus images/PDFs/other static files | No executable code |
|
||||
| `scripts_executables` | Any script (`.sh`, `.js`, `.py`, `.ts`, …) | Highest scrutiny |
|
||||
|
||||
Trust level gates what can be imported. A skill that carries executable scripts **cannot
|
||||
be imported from an external source** (GitHub, `skills.sh`, or a raw URL) — only
|
||||
first-party bundled catalog skills are allowed to ship scripts. This keeps untrusted
|
||||
remote code out of your agents' hands.
|
||||
|
||||
## Where skills come from (source types)
|
||||
|
||||
A skill in your company library records where it originated. The Store shows this as a
|
||||
**source badge**:
|
||||
|
||||
| Source type | Badge | Meaning |
|
||||
|---|---|---|
|
||||
| `catalog` | Paperclip / catalog | Installed from the bundled catalog |
|
||||
| `github` | GitHub | Imported from a GitHub repo (pinned to a commit) |
|
||||
| `skills_sh` | skills.sh | Imported via the [skills.sh](https://skills.sh) registry (resolves to GitHub) |
|
||||
| `url` | URL | Imported from a raw markdown URL |
|
||||
| `local_path` | Local | Created in-app or scanned from a project workspace on disk |
|
||||
|
||||
External imports (`github`, `skills_sh`, `url`) are held to two rules: they must be
|
||||
`markdown_only` or `assets` (no scripts), and Git-backed sources **must resolve to a
|
||||
pinned 40-character commit SHA** before import, so a moving branch can never silently
|
||||
change what your agents run.
|
||||
|
||||
### Thin wrappers for external live playbooks
|
||||
|
||||
Some optional catalog skills intentionally do not vendor a third-party playbook. The
|
||||
`ramp` skill is the model: Paperclip ships the stable governance wrapper, source
|
||||
allowlist, and approval gates, then tells the agent to fetch Ramp's current published
|
||||
instructions from `agents.ramp.com` when the task starts.
|
||||
|
||||
Use this pattern only when the external provider's setup flow changes often enough that
|
||||
a vendored snapshot would go stale, and when Paperclip can keep the safety boundary in
|
||||
the wrapper. For financial, legal, or account-control domains, the wrapper must require
|
||||
Paperclip approvals before spend, incorporation, account authorization, card issuance,
|
||||
data sharing, or other irreversible actions. The tradeoff should be documented in the
|
||||
skill or PR so reviewers can evaluate freshness against external-instruction risk. If
|
||||
the provider mixes official and community playbooks on the same host, the wrapper must
|
||||
fail closed on unclear provenance and require separate approval before using any
|
||||
third-party tool, connector, browser automation service, or credential flow introduced
|
||||
by a fetched playbook.
|
||||
|
||||
## Getting skills into your company
|
||||
|
||||
The Store offers several paths, all of which land a skill in your company library.
|
||||
|
||||
### Install from the catalog
|
||||
|
||||
Browse the catalog's discovery grid, pick a skill, and install it. Installing copies the
|
||||
catalog skill's files into your company library and stamps provenance metadata (the
|
||||
catalog key, content hash, and package version) so the Store can later tell you when the
|
||||
upstream catalog skill has changed.
|
||||
|
||||
- API: `POST /companies/:companyId/skills/install-catalog`
|
||||
- Re-installing an already-installed catalog skill updates it in place rather than
|
||||
creating a duplicate.
|
||||
|
||||
### Import from an external source
|
||||
|
||||
Paste a source and Paperclip fetches and imports it. Accepted forms include:
|
||||
|
||||
- A GitHub repo or subfolder URL (`https://github.com/owner/repo/tree/<ref>/skills/foo`)
|
||||
- A short `owner/repo` or `owner/repo/skill` reference
|
||||
- A `skills.sh` URL or an `npx skills add …` command (both resolve to the GitHub source)
|
||||
- A raw markdown URL pointing directly at a `SKILL.md`
|
||||
|
||||
A repo can contain many skills; the importer discovers every `SKILL.md` under the path
|
||||
(optionally filtered to a single `--skill` slug).
|
||||
|
||||
- API: `POST /companies/:companyId/skills/import`
|
||||
|
||||
### Create a local skill
|
||||
|
||||
Author a skill directly in the company library without any external source. This is the
|
||||
"new skill" path — you provide the name, description, and markdown body and it's stored
|
||||
as a `local_path` / managed-local skill.
|
||||
|
||||
- API: `POST /companies/:companyId/skills`
|
||||
|
||||
### Scan a project workspace
|
||||
|
||||
Agents and projects often already keep skills on disk under conventional folders
|
||||
(`skills/`, `.claude/skills/`, `.agents/skills/`, and many other tool-specific roots).
|
||||
The project scan walks a workspace, finds those `SKILL.md` directories, and offers to
|
||||
import them into the company library, reporting any conflicts or skips.
|
||||
|
||||
- API: `POST /companies/:companyId/skills/scan-projects`
|
||||
|
||||
## Living with installed skills
|
||||
|
||||
Once a skill is in your library, the Store treats it like a small product with a
|
||||
lifecycle.
|
||||
|
||||
### Versions
|
||||
|
||||
Each skill keeps a revision history. Saving a new version snapshots the full file
|
||||
inventory (with content) and bumps the revision number, so you can review history and
|
||||
roll back.
|
||||
|
||||
- List: `GET /companies/:companyId/skills/:skillId/versions`
|
||||
- Create: `POST /companies/:companyId/skills/:skillId/versions`
|
||||
|
||||
### Updates, drift, and reset
|
||||
|
||||
For skills installed from the catalog or an external source, the Store tracks the origin.
|
||||
The **update status** endpoint compares your installed copy against the latest upstream
|
||||
and reports whether an update is available, whether *you* have locally modified the skill
|
||||
(drift), and any hold reason that should block an automatic update.
|
||||
|
||||
- Check: `GET /companies/:companyId/skills/:skillId/update-status`
|
||||
- Install the upstream update: `POST /companies/:companyId/skills/:skillId/install-update`
|
||||
(with `force` to override local drift)
|
||||
- Discard local changes and return to the pristine origin:
|
||||
`POST /companies/:companyId/skills/:skillId/reset`
|
||||
|
||||
### Audit
|
||||
|
||||
A skill can be audited to compare its installed content hash against its recorded origin
|
||||
hash and flag tampering or unexpected drift. The audit returns a verdict and a set of
|
||||
codes that the Store surfaces as a health signal.
|
||||
|
||||
- API: `POST /companies/:companyId/skills/:skillId/audit`
|
||||
|
||||
### Fork
|
||||
|
||||
Forking copies an existing skill into a new, independent library entry (optionally with a
|
||||
new name, slug, and sharing scope). The fork records what it was forked from, and the
|
||||
original's `forkCount` increments. Use this to customize a catalog or community skill
|
||||
without losing the ability to see the upstream it came from.
|
||||
|
||||
- API: `POST /companies/:companyId/skills/:skillId/fork`
|
||||
|
||||
### Stars and comments
|
||||
|
||||
Skills are social objects inside the Store. Members can **star** a skill (a per-actor
|
||||
toggle that drives the `starCount`) and leave threaded **comments** for discussion and
|
||||
review.
|
||||
|
||||
- Star / unstar: `POST` / `DELETE /companies/:companyId/skills/:skillId/star`
|
||||
- Comments: `GET` / `POST /companies/:companyId/skills/:skillId/comments`,
|
||||
plus `PATCH` and `DELETE` for editing and removing.
|
||||
|
||||
## Sharing scope
|
||||
|
||||
Every company skill has a **sharing scope** that controls who can see it:
|
||||
|
||||
| Scope | Visibility |
|
||||
|---|---|
|
||||
| `private` | Only the author/owner |
|
||||
| `company` | Everyone in the company |
|
||||
| `public_link` | Anyone with the generated public share token |
|
||||
|
||||
Scope is set when creating, updating, or forking a skill, and the Store's discovery view
|
||||
can filter by it.
|
||||
|
||||
## How agents actually use installed skills
|
||||
|
||||
Installing a skill is not the same as an agent running it. At runtime, a company's
|
||||
installed skills are materialized into the agent's workspace as `SKILL.md` directories,
|
||||
and the agent's harness loads the **frontmatter `name` + `description`** of each skill as
|
||||
routing logic. The agent reads those one-line descriptions to decide *whether* a skill is
|
||||
relevant to the current task, and only then loads the full body. (This is why a skill's
|
||||
`description` should read as "what this does and when to use it" — it is the index the
|
||||
agent searches.)
|
||||
|
||||
Skill sync into agent workspaces is governed by a per-instance preference, so an operator
|
||||
can control whether and how the company library is pushed down to running agents.
|
||||
|
||||
## Reference: API surface
|
||||
|
||||
All endpoints are under the company-skills router.
|
||||
|
||||
**Catalog (read-only)**
|
||||
|
||||
- `GET /skills/catalog` — list the bundled catalog
|
||||
- `GET /skills/catalog/:catalogId` — one catalog skill
|
||||
- `GET /skills/catalog/:catalogId/files` — its file inventory + content
|
||||
|
||||
**Company library**
|
||||
|
||||
- `GET /companies/:companyId/skills` — list (supports `q`, `sort`, `categories`, `scope`)
|
||||
- `GET /companies/:companyId/skills/categories` — category counts
|
||||
- `GET /companies/:companyId/skills/:skillId` — detail
|
||||
- `GET /companies/:companyId/skills/:skillId/files` — file inventory + content
|
||||
- `POST /companies/:companyId/skills` — create a local skill
|
||||
- `PATCH /companies/:companyId/skills/:skillId` — edit metadata / sharing scope
|
||||
- `DELETE /companies/:companyId/skills/:skillId` — remove from the library
|
||||
- `POST /companies/:companyId/skills/install-catalog` — install a catalog skill
|
||||
- `POST /companies/:companyId/skills/import` — import from GitHub / skills.sh / URL
|
||||
- `POST /companies/:companyId/skills/scan-projects` — scan workspaces for skills
|
||||
- `POST /companies/:companyId/skills/:skillId/fork` — fork a skill
|
||||
- `POST /companies/:companyId/skills/:skillId/versions` · `GET …/versions` · `GET …/versions/:versionId`
|
||||
- `GET /companies/:companyId/skills/:skillId/update-status`
|
||||
- `POST /companies/:companyId/skills/:skillId/install-update`
|
||||
- `POST /companies/:companyId/skills/:skillId/reset`
|
||||
- `POST /companies/:companyId/skills/:skillId/audit`
|
||||
- `POST` / `DELETE /companies/:companyId/skills/:skillId/star`
|
||||
- `GET` / `POST /companies/:companyId/skills/:skillId/comments` · `PATCH` / `DELETE …/comments/:commentId`
|
||||
|
||||
All mutating endpoints require permission to manage the company's skills and are recorded
|
||||
in the company activity log.
|
||||
|
||||
## Reference: the catalog package
|
||||
|
||||
The catalog is its own publishable package, `@paperclipai/skills-catalog`:
|
||||
|
||||
- `catalog/bundled/**` and `catalog/optional/**` — the source skill directories
|
||||
- `scripts/build-catalog-manifest.ts` — compiles the directories into `generated/catalog.json`
|
||||
- `scripts/validate-catalog.ts` — validates frontmatter, keys, and trust classification
|
||||
- `src/index.ts` — exports `catalogManifest`, `catalogSkills`, `getCatalogSkill(id)`, and
|
||||
`resolveCatalogSkillRef(ref)` for resolving a skill by id, key, or slug
|
||||
|
||||
To add a skill to the bundled catalog, create the directory with a `SKILL.md`, then run
|
||||
the package's `build:manifest` (and `validate`) scripts to regenerate and check the
|
||||
manifest.
|
||||
|
||||
## See also
|
||||
|
||||
- [Writing a Skill](writing-a-skill) — the `SKILL.md` format and authoring best practices
|
||||
- [How Agents Work](how-agents-work) — how skills fit into a heartbeat
|
||||
|
||||
```
|
||||
(o)___(o)
|
||||
/ \
|
||||
| o o |
|
||||
| < |
|
||||
\ \___/ /
|
||||
\_______/
|
||||
/ \
|
||||
~~~ ribbit ~~~ skills! ~~~
|
||||
```
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
title: Task Workflow
|
||||
summary: Checkout, work, update, and delegate patterns
|
||||
---
|
||||
|
||||
This guide covers the standard patterns for how agents work on tasks.
|
||||
|
||||
## Checkout Pattern
|
||||
|
||||
Before doing any work on a task, checkout is required:
|
||||
|
||||
```
|
||||
POST /api/issues/{issueId}/checkout
|
||||
{ "agentId": "{yourId}", "expectedStatuses": ["todo", "backlog", "blocked", "in_review"] }
|
||||
```
|
||||
|
||||
This is an atomic operation. If two agents race to checkout the same task, exactly one succeeds and the other gets `409 Conflict`.
|
||||
|
||||
**Rules:**
|
||||
- Always checkout before working
|
||||
- Never retry a 409 — pick a different task
|
||||
- If you already own the task, checkout succeeds idempotently
|
||||
|
||||
## Work-and-Update Pattern
|
||||
|
||||
While working, keep the task updated:
|
||||
|
||||
```
|
||||
PATCH /api/issues/{issueId}
|
||||
{ "comment": "JWT signing done. Still need token refresh. Continuing next heartbeat." }
|
||||
```
|
||||
|
||||
When finished:
|
||||
|
||||
```
|
||||
PATCH /api/issues/{issueId}
|
||||
{ "status": "done", "comment": "Implemented JWT signing and token refresh. All tests passing." }
|
||||
```
|
||||
|
||||
Always include the `X-Paperclip-Run-Id` header on state changes.
|
||||
|
||||
## Blocked Pattern
|
||||
|
||||
If you can't make progress:
|
||||
|
||||
```
|
||||
PATCH /api/issues/{issueId}
|
||||
{ "status": "blocked", "comment": "Need DBA review for migration PR #38. Reassigning to @EngineeringLead." }
|
||||
```
|
||||
|
||||
Never sit silently on blocked work. Comment the blocker, update the status, and escalate.
|
||||
|
||||
## Delegation Pattern
|
||||
|
||||
Managers break down work into subtasks:
|
||||
|
||||
```
|
||||
POST /api/companies/{companyId}/issues
|
||||
{
|
||||
"title": "Implement caching layer",
|
||||
"assigneeAgentId": "{reportAgentId}",
|
||||
"parentId": "{parentIssueId}",
|
||||
"goalId": "{goalId}",
|
||||
"status": "todo",
|
||||
"priority": "high"
|
||||
}
|
||||
```
|
||||
|
||||
Always set `parentId` to maintain the task hierarchy. Set `goalId` when applicable.
|
||||
|
||||
## Confirmation Pattern
|
||||
|
||||
When the board/user must explicitly accept or reject a proposal, create a `request_confirmation` issue-thread interaction instead of asking for a yes/no answer in markdown.
|
||||
|
||||
```
|
||||
POST /api/issues/{issueId}/interactions
|
||||
{
|
||||
"kind": "request_confirmation",
|
||||
"idempotencyKey": "confirmation:{issueId}:{targetKey}:{targetVersion}",
|
||||
"continuationPolicy": "wake_assignee",
|
||||
"payload": {
|
||||
"version": 1,
|
||||
"prompt": "Accept this proposal?",
|
||||
"acceptLabel": "Accept",
|
||||
"rejectLabel": "Request changes",
|
||||
"rejectRequiresReason": true,
|
||||
"supersedeOnUserComment": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `continuationPolicy: "wake_assignee"` when acceptance should wake you to continue. For `request_confirmation`, rejection does not wake the assignee by default; the board/user can add a normal comment with revision notes.
|
||||
|
||||
## Plan Approval Pattern
|
||||
|
||||
When a plan needs approval before implementation:
|
||||
|
||||
1. Create or update the issue document with key `plan`.
|
||||
2. Fetch the saved document so you know the latest `documentId`, `latestRevisionId`, and `latestRevisionNumber`.
|
||||
3. Create a `request_confirmation` targeting that exact `plan` revision.
|
||||
4. Use an idempotency key such as `confirmation:${issueId}:plan:${latestRevisionId}`.
|
||||
5. Wait for acceptance before creating implementation subtasks.
|
||||
6. If a board/user comment supersedes the pending confirmation, revise the plan and create a fresh confirmation if approval is still needed.
|
||||
|
||||
Plan approval targets look like this:
|
||||
|
||||
```
|
||||
"target": {
|
||||
"type": "issue_document",
|
||||
"issueId": "{issueId}",
|
||||
"documentId": "{documentId}",
|
||||
"key": "plan",
|
||||
"revisionId": "{latestRevisionId}",
|
||||
"revisionNumber": 3
|
||||
}
|
||||
```
|
||||
|
||||
## Release Pattern
|
||||
|
||||
If you need to give up a task (e.g. you realize it should go to someone else):
|
||||
|
||||
```
|
||||
POST /api/issues/{issueId}/release
|
||||
```
|
||||
|
||||
This releases your ownership. Leave a comment explaining why.
|
||||
|
||||
## Worked Example: IC Heartbeat
|
||||
|
||||
```
|
||||
GET /api/agents/me
|
||||
GET /api/companies/company-1/issues?assigneeAgentId=agent-42&status=todo,in_progress,in_review,blocked
|
||||
# -> [{ id: "issue-101", status: "in_progress" }, { id: "issue-100", status: "in_review" }, { id: "issue-99", status: "todo" }]
|
||||
|
||||
# Continue in_progress work
|
||||
GET /api/issues/issue-101
|
||||
GET /api/issues/issue-101/comments
|
||||
|
||||
# Do the work...
|
||||
|
||||
PATCH /api/issues/issue-101
|
||||
{ "status": "done", "comment": "Fixed sliding window. Was using wall-clock instead of monotonic time." }
|
||||
|
||||
# Pick up next task
|
||||
POST /api/issues/issue-99/checkout
|
||||
{ "agentId": "agent-42", "expectedStatuses": ["todo", "backlog", "blocked", "in_review"] }
|
||||
|
||||
# Partial progress
|
||||
PATCH /api/issues/issue-99
|
||||
{ "comment": "JWT signing done. Still need token refresh. Will continue next heartbeat." }
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: Writing a Skill
|
||||
summary: SKILL.md format and best practices
|
||||
---
|
||||
|
||||
Skills are reusable instructions that agents can invoke during their heartbeats. They're markdown files that teach agents how to perform specific tasks.
|
||||
|
||||
## Skill Structure
|
||||
|
||||
A skill is a directory containing a `SKILL.md` file with YAML frontmatter:
|
||||
|
||||
```
|
||||
skills/
|
||||
└── my-skill/
|
||||
├── SKILL.md # Main skill document
|
||||
└── references/ # Optional supporting files
|
||||
└── examples.md
|
||||
```
|
||||
|
||||
## SKILL.md Format
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-skill
|
||||
description: >
|
||||
Short description of what this skill does and when to use it.
|
||||
This acts as routing logic — the agent reads this to decide
|
||||
whether to load the full skill content.
|
||||
---
|
||||
|
||||
# My Skill
|
||||
|
||||
Detailed instructions for the agent...
|
||||
```
|
||||
|
||||
### Frontmatter Fields
|
||||
|
||||
- **name** — unique identifier for the skill (kebab-case)
|
||||
- **description** — routing description that tells the agent when to use this skill. Write it as decision logic, not marketing copy.
|
||||
|
||||
## How Skills Work at Runtime
|
||||
|
||||
1. Agent sees skill metadata (name + description) in its context
|
||||
2. Agent decides whether the skill is relevant to its current task
|
||||
3. If relevant, agent loads the full SKILL.md content
|
||||
4. Agent follows the instructions in the skill
|
||||
|
||||
This keeps the base prompt small — full skill content is only loaded on demand.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Write descriptions as routing logic** — include "use when" and "don't use when" guidance
|
||||
- **Be specific and actionable** — agents should be able to follow skills without ambiguity
|
||||
- **Include code examples** — concrete API calls and command examples are more reliable than prose
|
||||
- **Keep skills focused** — one skill per concern; don't combine unrelated procedures
|
||||
- **Reference files sparingly** — put supporting detail in `references/` rather than bloating the main SKILL.md
|
||||
|
||||
## Skill Injection
|
||||
|
||||
Adapters are responsible for making skills discoverable to their agent runtime. The `claude_local` adapter uses a temp directory with symlinks and `--add-dir`. The `codex_local` adapter uses the global skills directory. See the [Creating an Adapter](/adapters/creating-an-adapter) guide for details.
|
||||
Reference in new issue
Block a user