agentsclimarketplace

Paperclip api

Skill Yesterday-AI/skills/skills/operations/paperclip-api

Yesterday's PUBLIC plugin catalog for Claude Code and Cursor

Install
npx -y skills add Yesterday-AI/skills --skill paperclip-api

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Manage Paperclip AI companies, agents, issues, projects, goals, routines, costs, and secrets via REST API. Use when creating companies, hiring agents, assigning tasks, managing budgets, approving hires, or checking dashboards on a Paperclip instance.

SKILL.md

52.0 KB, as published. Nobody here has run it

Paperclip AI

Manage zero-human AI companies on a Paperclip instance. Companies have org charts, agents, issues (tickets), projects, goals, budgets, routines, and governance.

How Paperclip Works -- The Mental Model

Paperclip is a control plane, not an execution plane. It orchestrates agents but doesn't run them -- agents run externally via adapters and phone home through the REST API.

You (Board)
  └── Company (Mission + Budget)
        └── Goals (company → team → agent → task)
              └── Projects (scoped work, linked to goal)
                    └── Issues (tickets -- the unit of work)
                          └── Sub-issues (delegation down the org chart)

The key insight: Every issue traces back to the company mission through its goal ancestry. Agents always know why they're doing something, not just what.

Heartbeat Protocol -- How Agents Work

Agents don't run continuously. They wake up on heartbeats (scheduled or event-triggered) and execute a fixed protocol:

1. GET /api/agents/me          → Who am I? What company? What budget?
2. GET /api/issues?status=todo → What's assigned to me?
3. POST /api/issues/{id}/checkout  → Claim the task (atomic -- 409 if taken)
4. GET /api/issues/{id}         → Read full context + goal ancestry
5. Do the work...
6. PATCH /api/issues/{id}       → Update status + comment with result
7. POST /api/issues (optional)  → Delegate subtasks to other agents

Heartbeat triggers: Schedule (cron), task assignment, @-mention in comment, manual from UI, approval resolution.

Assignment is the dispatcher. As soon as an issue has status >= todo AND assigneeAgentId set, the assigned agent wakes up and starts working — no routine, no patrol loop, no manual wakeup needed. Routines exist for scheduled work (recurring reports, audits), not as a queue dispatcher. A "review patrol" routine being paused does NOT block the review queue: the assigned reviewer still gets woken on every assignment.

Checkout is critical: POST /api/issues/{id}/checkout atomically claims a task. If another agent already has it → 409 Conflict. Never retry a 409 -- pick a different task.

Routines -- Scheduled Work Without LLM Overhead

Routines are recurring tasks triggered by cron schedule, webhook, or API call. They replace expensive always-on LLM sessions with efficient scheduled heartbeats.

# Create a routine (cron-based)
paperclipai routine create --name "Daily Standup" --schedule "0 9 * * *" --assignee-agent-id <agent-id> --company-id <id>

# Trigger manually
paperclipai routine run <routine-id>

When to use Routines vs Issues:

  • Routine = recurring, scheduled, predictable (daily reports, syncs, digests)
  • Issue = discrete unit of work with a start and end

Governance -- You're the Board

  • Agent hires require Board approval (you)
  • CEO strategy requires Board review before execution
  • You can pause/resume/terminate any agent at any time
  • Budget enforcement is automatic -- agent is paused when monthly budget is exhausted

Adapters -- How Agents Connect

AdapterRuntime
openclaw_gatewayOpenClaw agents (WebSocket)
claude_localClaude Code CLI
codex_localOpenAI Codex CLI
cursorCursor IDE
processShell command
httpAny HTTP endpoint
opencode_local, hermes_localOther local runtimes

Agent Companies Format (agentcompanies.io)

Paperclip implements the Agent Companies open protocol -- a vendor-neutral, markdown-first format for portable AI company packages. Built on top of Agent Skills (SKILL.md).

Package Structure

company-package/
├── COMPANY.md       # Root entrypoint: company boundary + defaults
├── teams/
│   └── engineering/TEAM.md    # Reusable org subtree
├── agents/
│   └── ceo/AGENTS.md          # Single role: instructions + skills + reporting
├── projects/
│   └── q2-launch/PROJECT.md   # Work grouping
├── tasks/
│   └── monday-review/TASK.md  # Portable starter task
└── skills/
    └── review/SKILL.md        # Agent Skills capability (unchanged)

File Roles

FilePurpose
COMPANY.mdCompany boundary, defaults, goals
TEAM.mdReusable org subtree (e.g., Engineering team)
AGENTS.mdOne role -- instructions, reportsTo, attached skills
PROJECT.mdPlanned work grouping
TASK.mdPortable starter task with assignee + schedule
SKILL.mdAgent capability (standard Agent Skills, unchanged)

Key Rules

  • AGENTS.md body = canonical default instructions for that role
  • Never put adapter/runtime config or secrets in the base package
  • SKILL.md stays unchanged -- Agent Companies never redefines it
  • External skills can be referenced (with provenance: repo URL, commit SHA, path)

Minimal COMPANY.md

name: My Company
description: Short description
slug: my-company
schema: agentcompanies/v1

Spec: https://agentcompanies.io/specification

Company Templates (Clipmart)

Ready-to-import company templates from github.com/paperclipai/companies:

# Import a template directly from GitHub
npx companies.sh add paperclipai/companies/gstack
paperclipai company import org/repo/companies/acme

# Export your own company as template
paperclipai company export <company-id> --out ./my-company --include company,agents,projects,skills

Notable templates: superpowers (dev shop, 4 agents), product-compass-consulting (PM, 48 agents), trail-of-bits-security (security, 28 agents), gstack (engineering modes, 5 agents).

Ecosystem -- Plugins & Tools

Full list: https://github.com/gsxdsm/awesome-paperclip

Plugins

PluginWhat it does
paperclip-plugin-acpACP runtime -- run Claude Code, Codex, Gemini CLI from any chat platform
paperclip-plugin-github-issuesBidirectional GitHub Issues sync
paperclip-plugin-discordDiscord notifications + slash commands
paperclip-plugin-slackSlack notifications
paperclip-plugin-telegramTelegram notifications
paperclip-plugin-chatInteractive AI chat copilot for tasks/agents/workspaces
paperclip-plugin-avpTrust layer: DID identity, EigenTrust reputation, signed attestations
paperclip-plugin-company-wizardAI-powered company setup assistant with presets

Tools

ToolWhat it does
oh-my-paperclipPlugin bundle -- the oh-my-zsh for Paperclip
paperclip-apertureAlternative Focus view -- ranks approvals, activity into now/next/ambient
paperclip-discord-botDiscord community bot with GitHub OAuth and AI summaries

Learning

  • Headcount Zero -- open-source book: How to Build an AI-Run Company with Paperclip

Quick Reference

All commands go through the wrapper script:

{baseDir}/scripts/paperclip.sh <command> [subcommand] [options]

Environment

Recommended (bearer token — no rate limit):

export PAPERCLIP_API_URL="https://your-instance.up.railway.app"
export PAPERCLIP_API_TOKEN="pcp_board_..."   # mint via `paperclipai auth login`
export PAPERCLIP_COMPANY_ID="optional-default-company-id"

Fallback (email + password — rate-limited at ~10 sign-ins/min):

export PAPERCLIP_API_URL="https://your-instance.up.railway.app"
export PAPERCLIP_EMAIL="your-board-email"
export PAPERCLIP_PASSWORD="your-board-password"
export PAPERCLIP_COMPANY_ID="optional-default-company-id"

The wrapper picks bearer when PAPERCLIP_API_TOKEN is set; otherwise it signs in per call via email/password and uses the cookie. Bearer is strongly preferred for any non-trivial scripted use — cookie sign-in trips a 429 rate limit on the auth endpoint after roughly 10 fresh sign-ins per minute, and our wrapper signs in fresh on every call.


Companies

# List all companies
{baseDir}/scripts/paperclip.sh company list

# Create a company
{baseDir}/scripts/paperclip.sh company create "Atlas Corp" "Map every job in DACH"

# Get company details
{baseDir}/scripts/paperclip.sh company get <company-id>

# Update company (all flags optional)
{baseDir}/scripts/paperclip.sh company update <company-id> \
  --name "New Name" \
  --description "New desc" \
  --status active \
  --budget-monthly-cents 500000 \
  --require-board-approval true \
  --brand-color "#FF5733"

# Archive company
{baseDir}/scripts/paperclip.sh company archive <company-id>

# Delete company
{baseDir}/scripts/paperclip.sh company delete <company-id>

# Export company (portability)
{baseDir}/scripts/paperclip.sh company export <company-id>

Company statuses: active, paused, archived

Company fields (create/update)

FieldTypeCreateUpdateNotes
namestringrequiredoptional
descriptionstringoptionaloptional
budgetMonthlyCentsnumberoptionaloptionalMonthly budget in cents
statusenum--optionalactive/paused/archived
requireBoardApprovalForNewAgentsboolean--optional
feedbackDataSharingEnabledboolean--optional
brandColorstring--optionalHex color
logoAssetIdstring--optional

Agents

Basic CRUD

# List agents in a company
{baseDir}/scripts/paperclip.sh agent list --company-id <id>

# Create an agent directly
{baseDir}/scripts/paperclip.sh agent create "Research Lead" "researcher" \
  --title "Senior Researcher" \
  --adapter claude_local \
  --icon "🔬" \
  --capabilities "web search, document analysis" \
  --budget-monthly-cents 50000 \
  --reports-to <manager-agent-id> \
  --company-id <id>

# Hire via governance (triggers Board approval)
{baseDir}/scripts/paperclip.sh agent hire "Research Lead" "researcher" \
  --title "Senior Researcher" \
  --adapter claude_local \
  --company-id <id>

# Get agent details
{baseDir}/scripts/paperclip.sh agent get <agent-id>

# Update agent (all flags optional)
{baseDir}/scripts/paperclip.sh agent update <agent-id> \
  --name "New Name" \
  --role engineer \
  --title "Staff Engineer" \
  --icon "⚙️" \
  --capabilities "coding, testing, deployment" \
  --adapter-type openclaw_gateway \
  --reports-to <manager-agent-id> \
  --budget-monthly-cents 100000

# Delete agent permanently
{baseDir}/scripts/paperclip.sh agent delete <agent-id>

Agent fields (create/update)

FieldTypeCreateUpdateNotes
namestringrequiredoptional
roleenumrequiredoptionalSee roles below
titlestringoptionaloptional
adapterTypestringrequiredoptionalSee adapters below
adapterConfigobjectoptionaloptionalAdapter-specific config (JSON)
runtimeConfigobjectoptionaloptionalRuntime-specific config (JSON)
iconstringoptionaloptionalEmoji or icon key
capabilitiesstringoptionaloptionalFree-text capability description
budgetMonthlyCentsnumberoptionaloptionalAgent monthly budget
reportsTostringoptionaloptionalManager agent ID
metadataobject--optionalArbitrary key-value metadata

Agent roles: ceo, cto, cmo, cfo, engineer, designer, pm, qa, devops, researcher, general

Adapter types: claude_local, codex_local, gemini_local, cursor, openclaw_gateway, process, http, opencode_local, pi_local

Agent statuses: active, paused, idle, running, error, pending_approval, terminated

Agent Lifecycle

{baseDir}/scripts/paperclip.sh agent pause <agent-id>
{baseDir}/scripts/paperclip.sh agent resume <agent-id>
{baseDir}/scripts/paperclip.sh agent terminate <agent-id>

# Wakeup with optional parameters
{baseDir}/scripts/paperclip.sh agent wakeup <agent-id>
{baseDir}/scripts/paperclip.sh agent wakeup <agent-id> \
  --source on_demand \
  --trigger-detail manual \
  --reason "Need to process new data"

Wakeup sources: timer, assignment, on_demand, automation Wakeup trigger details: manual, ping, callback, system

Agent Configuration

# Get current configuration
{baseDir}/scripts/paperclip.sh agent config <agent-id>

# List config revisions (audit trail)
{baseDir}/scripts/paperclip.sh agent config-revisions <agent-id>

# Rollback to a specific revision
{baseDir}/scripts/paperclip.sh agent config-rollback <agent-id> <revision-id>

Agent Instructions (Managed Prompt Files)

Agents have a managed instructions bundle -- a set of files (like AGENTS.md) that define the agent's behavior. The bundle can be in managed mode (edited via API) or external mode (loaded from disk/repo).

# Get instructions bundle metadata + file list
{baseDir}/scripts/paperclip.sh agent instructions-get <agent-id>

# Get a specific instructions file content
{baseDir}/scripts/paperclip.sh agent instructions-file <agent-id> --path "AGENTS.md"

# Write/update an instructions file
{baseDir}/scripts/paperclip.sh agent instructions-set <agent-id> --path "AGENTS.md" --content "# Agent Instructions\n..."
{baseDir}/scripts/paperclip.sh agent instructions-set <agent-id> --path "AGENTS.md" --file ./local-agents.md

# Delete an instructions file
{baseDir}/scripts/paperclip.sh agent instructions-delete <agent-id> --path "AGENTS.md"

# Update bundle settings (mode, root path, entry file)
{baseDir}/scripts/paperclip.sh agent instructions-update <agent-id> \
  --mode managed \
  --entry-file "AGENTS.md"

Instructions bundle modes: managed (API-edited), external (loaded from disk/repo)

Agent Skills

# Get current skills snapshot
{baseDir}/scripts/paperclip.sh agent skills <agent-id>

# Sync skills (set desired skill list)
{baseDir}/scripts/paperclip.sh agent skills-sync <agent-id> --skills "web-design,qa,github-workflow"

Agent API Keys

# List keys
{baseDir}/scripts/paperclip.sh agent keys <agent-id>

# Create a new key (token shown only once!)
{baseDir}/scripts/paperclip.sh agent keys-create <agent-id> --name "production-key"

# Revoke a key
{baseDir}/scripts/paperclip.sh agent keys-revoke <agent-id> <key-id>

Agent Runtime & Sessions

# Get runtime state (current execution, sessions)
{baseDir}/scripts/paperclip.sh agent runtime-state <agent-id>

# List task sessions
{baseDir}/scripts/paperclip.sh agent task-sessions <agent-id>

# Reset session
{baseDir}/scripts/paperclip.sh agent reset-session <agent-id>
{baseDir}/scripts/paperclip.sh agent reset-session <agent-id> --task-key "some-task"

# Invoke heartbeat manually
{baseDir}/scripts/paperclip.sh agent heartbeat <agent-id>

Adapter Discovery

# List available models for an adapter type
{baseDir}/scripts/paperclip.sh adapter models <adapter-type> --company-id <id>

# Detect current model for adapter
{baseDir}/scripts/paperclip.sh adapter detect-model <adapter-type> --company-id <id>

# Test adapter environment
{baseDir}/scripts/paperclip.sh adapter test-env <adapter-type> --company-id <id>

Projects

Basic CRUD

# List projects
{baseDir}/scripts/paperclip.sh project list --company-id <id>

# Create project
{baseDir}/scripts/paperclip.sh project create \
  --name "Phase 1" \
  --description "Initial research" \
  --goal-ids "<goal-id-1>,<goal-id-2>" \
  --lead-agent-id <agent-id> \
  --target-date "2026-06-01" \
  --color "#3B82F6" \
  --company-id <id>

# Get project details
{baseDir}/scripts/paperclip.sh project get <project-id>

# Update project (all flags optional)
{baseDir}/scripts/paperclip.sh project update <project-id> \
  --name "Phase 1 - Extended" \
  --status in_progress \
  --lead-agent-id <agent-id> \
  --target-date "2026-07-01" \
  --color "#10B981"

# Delete project
{baseDir}/scripts/paperclip.sh project delete <project-id>

Project fields (create/update)

FieldTypeCreateUpdateNotes
namestringrequiredoptional
descriptionstringoptionaloptional
goalIdsstring[]optional--Array of linked goal IDs
goalIdstringoptional--DEPRECATED -- use goalIds
leadAgentIdstringoptionaloptionalProject lead
targetDatestringoptionaloptionalISO date
colorstringoptionaloptionalHex color
statusenumoptionaloptionalSee statuses below

Project statuses: backlog, planned, in_progress, completed, cancelled

Project Workspaces

Projects can have multiple workspaces (local paths, git repos, remote managed environments).

# List workspaces for a project
{baseDir}/scripts/paperclip.sh workspace list <project-id>

# Create workspace
{baseDir}/scripts/paperclip.sh workspace create <project-id> \
  --name "Main Repo" \
  --source-type git_repo \
  --repo-url "https://github.com/org/repo" \
  --repo-ref "main" \
  --setup-command "pnpm install"

# Update workspace
{baseDir}/scripts/paperclip.sh workspace update <project-id> <workspace-id> \
  --repo-ref "develop" \
  --setup-command "pnpm install && pnpm build"

# Delete workspace
{baseDir}/scripts/paperclip.sh workspace delete <project-id> <workspace-id>

# Control workspace runtime services
{baseDir}/scripts/paperclip.sh workspace start <project-id> <workspace-id>
{baseDir}/scripts/paperclip.sh workspace stop <project-id> <workspace-id>
{baseDir}/scripts/paperclip.sh workspace restart <project-id> <workspace-id>

Workspace source types: local_path, git_repo, remote_managed, non_git_path

Workspace fields (create/update)

FieldTypeCreateUpdateNotes
namestringrequiredoptional
sourceTypeenumrequiredoptionallocal_path/git_repo/remote_managed/non_git_path
cwdstringoptionaloptionalWorking directory path
repoUrlstringoptionaloptionalGit repository URL
repoRefstringoptionaloptionalBranch/tag/commit
setupCommandstringoptionaloptionalRun after workspace init
cleanupCommandstringoptionaloptionalRun before workspace teardown
remoteProviderstringoptionaloptionalFor remote_managed type
remoteWorkspaceRefstringoptionaloptionalFor remote_managed type

Goals

# List goals
{baseDir}/scripts/paperclip.sh goal list --company-id <id>

# Create goal (hierarchical)
{baseDir}/scripts/paperclip.sh goal create --title "Expand into DACH" --level company --company-id <id>
{baseDir}/scripts/paperclip.sh goal create --title "Research Immobilien" --level team \
  --parent-id <goal-id> --owner-agent-id <agent-id> --company-id <id>

# Get goal details
{baseDir}/scripts/paperclip.sh goal get <goal-id>

# Update goal (all flags optional)
{baseDir}/scripts/paperclip.sh goal update <goal-id> \
  --title "New title" \
  --description "Updated description" \
  --status achieved \
  --parent-id <parent-goal-id> \
  --owner-agent-id <agent-id>

# Delete goal
{baseDir}/scripts/paperclip.sh goal delete <goal-id>

Goal fields (create/update)

FieldTypeCreateUpdateNotes
titlestringrequiredoptional
descriptionstringoptionaloptional
levelenumoptional--company/team/agent/task (default: company)
statusenumoptionaloptionalplanned/active/achieved/cancelled
parentIdstringoptionaloptionalParent goal for hierarchy
ownerAgentIdstringoptionaloptionalResponsible agent

Goal levels: company, team, agent, task Goal statuses: planned, active, achieved, cancelled


Issues (Tasks)

Basic CRUD

# List issues (many filters available)
{baseDir}/scripts/paperclip.sh issue list --company-id <id>
{baseDir}/scripts/paperclip.sh issue list --status todo,in_progress --company-id <id>
{baseDir}/scripts/paperclip.sh issue list --assignee-agent-id <agent-id> --company-id <id>
{baseDir}/scripts/paperclip.sh issue list --project-id <project-id> --company-id <id>
{baseDir}/scripts/paperclip.sh issue list --label-id <label-id> --company-id <id>
{baseDir}/scripts/paperclip.sh issue list --q "search term" --company-id <id>

# Create an issue
# ⚠️ REQUIRED: Always set --assignee-agent-id. An issue without an assignee
# will never be picked up -- agents only process issues assigned to them.
# If unsure who to assign, list agents first: issue list + agent list.
{baseDir}/scripts/paperclip.sh issue create \
  --title "Research Immobilienwirtschaft" \
  --description "Phase 1: Identify all company types" \
  --priority high \
  --assignee-agent-id <agent-id> \
  --project-id <project-id> \
  --goal-id <goal-id> \
  --label-ids "<label-id-1>,<label-id-2>" \
  --billing-code "R&D-2026" \
  --company-id <id>

# Create a sub-issue
{baseDir}/scripts/paperclip.sh issue create --title "WEG-Hausverwaltungen" \
  --parent-id <parent-issue-id> --company-id <id>

# Get issue details
{baseDir}/scripts/paperclip.sh issue get <issue-id>

# Update issue (all flags optional)
{baseDir}/scripts/paperclip.sh issue update <issue-id> \
  --status in_progress \
  --assignee-agent-id <agent-id> \
  --project-id <project-id> \
  --goal-id <goal-id> \
  --priority high \
  --label-ids "<id1>,<id2>" \
  --billing-code "OPS-2026"

# Delete issue
{baseDir}/scripts/paperclip.sh issue delete <issue-id>

Issue fields (create/update)

FieldTypeCreateUpdateNotes
titlestringrequiredoptional
descriptionstringoptionaloptional
priorityenumoptionaloptionalcritical/high/medium/low
statusenumoptionaloptionalSee statuses below
projectIdstringoptionaloptional
goalIdstringoptionaloptional
parentIdstringoptionaloptionalCreates sub-issue
assigneeAgentIdstringoptionaloptionalAgent assignee
assigneeUserIdstringoptionaloptionalHuman assignee
executionWorkspaceIdstringoptionaloptionalWorkspace for execution
labelIdsstring[]optionaloptionalLabel IDs
billingCodestringoptionaloptionalCost attribution code

Issue statuses: backlog, todo, in_progress, in_review, done, blocked, cancelled Priority: critical, high, medium, low

Issue list filter parameters

FilterDescription
--statusFilter by status (comma-separated)
--project-idFilter by project
--assignee-agent-idFilter by agent assignee
--assignee-user-idFilter by human assignee
--participant-agent-idFilter by participant agent
--label-idFilter by label
--origin-kindFilter by origin (manual/routine_execution)
--qFull-text search
--include-routine-executionsInclude routine-generated issues

Issue Comments

Comments are immutable -- no edit or delete endpoints exist.

# List comments (supports pagination)
{baseDir}/scripts/paperclip.sh issue comments <issue-id>
{baseDir}/scripts/paperclip.sh issue comments <issue-id> --order asc --limit 50
{baseDir}/scripts/paperclip.sh issue comments <issue-id> --after <comment-id> --limit 20

# Get a single comment
{baseDir}/scripts/paperclip.sh issue comment-get <issue-id> <comment-id>

# Add comment
{baseDir}/scripts/paperclip.sh issue comment <issue-id> --body "Research complete, 25 Spielwiesen identified"

# Comment that reopens a done/cancelled issue
{baseDir}/scripts/paperclip.sh issue comment <issue-id> --body "Found another category" --reopen

# Comment that interrupts the current agent execution
{baseDir}/scripts/paperclip.sh issue comment <issue-id> --body "Stop and pivot to X" --interrupt

Comment create fields: body (required), reopen (optional bool), interrupt (optional bool, board only)

Comment response fields: id, companyId, issueId, authorAgentId, authorUserId, createdByRunId, body, createdAt, updatedAt

Attachments can be linked to a specific comment via --comment-id on issue attachment-upload.

Atomic Checkout (Task Locking)

# Checkout (lock for agent -- prevents double-work)
{baseDir}/scripts/paperclip.sh issue checkout <issue-id> --agent-id <agent-id>

# Release (unlock)
{baseDir}/scripts/paperclip.sh issue release <issue-id>

Issue Documents (Versioned Markdown)

Each issue can have multiple versioned markdown documents (e.g. plans, reports, specs).

# List documents on an issue
{baseDir}/scripts/paperclip.sh issue documents <issue-id>

# Get document content by key
{baseDir}/scripts/paperclip.sh issue document-get <issue-id> <key>

# Create or update document (upsert)
{baseDir}/scripts/paperclip.sh issue document-set <issue-id> <key> \
  --title "Research Plan" \
  --body "# Plan\n\n1. Identify segments\n2. ..."

# List document revisions
{baseDir}/scripts/paperclip.sh issue document-revisions <issue-id> <key>

# Restore a revision
{baseDir}/scripts/paperclip.sh issue document-restore <issue-id> <key> <revision-id>

# Delete document
{baseDir}/scripts/paperclip.sh issue document-delete <issue-id> <key>

Issue Labels

# List company labels
{baseDir}/scripts/paperclip.sh label list --company-id <id>

# Create label
{baseDir}/scripts/paperclip.sh label create --name "urgent" --color "#EF4444" --company-id <id>

# Delete label
{baseDir}/scripts/paperclip.sh label delete <label-id>

Issue Attachments

# List attachments on an issue
{baseDir}/scripts/paperclip.sh issue attachments <issue-id>

# Upload attachment (multipart/form-data, max 10MB)
{baseDir}/scripts/paperclip.sh issue attachment-upload <issue-id> --file ./report.pdf --company-id <id>

# Download attachment content
{baseDir}/scripts/paperclip.sh issue attachment-content <attachment-id>

# Delete attachment
{baseDir}/scripts/paperclip.sh issue attachment-delete <attachment-id>

Allowed content types: images (png/jpeg/webp/gif), PDF, markdown, plain text, JSON, CSV, HTML. Configurable per instance.

Issue Runs (Execution History)

# List all execution runs for an issue
{baseDir}/scripts/paperclip.sh issue runs <issue-id>

# List currently active (queued/running) runs
{baseDir}/scripts/paperclip.sh issue live-runs <issue-id>

# Get the single active run (or null)
{baseDir}/scripts/paperclip.sh issue active-run <issue-id>

Run fields: runId, status, agentId, invocationSource, startedAt, finishedAt, usageJson, resultJson

Note: There is no GET /api/agents/:id/runs endpoint. Execution history is per-issue, not per-agent. To get an agent's run history, query issues assigned to that agent.

Issue Feedback

# List feedback votes on an issue
{baseDir}/scripts/paperclip.sh issue feedback-votes <issue-id>

# Submit feedback vote (thumbs up/down)
{baseDir}/scripts/paperclip.sh issue feedback-vote <issue-id> --value up
{baseDir}/scripts/paperclip.sh issue feedback-vote <issue-id> --value down --comment "Output was incomplete"

# List feedback traces on an issue
{baseDir}/scripts/paperclip.sh issue feedback-traces <issue-id>

# Get feedback trace details / bundle
{baseDir}/scripts/paperclip.sh feedback-trace get <trace-id>
{baseDir}/scripts/paperclip.sh feedback-trace bundle <trace-id>

# List company-wide feedback traces (filterable)
{baseDir}/scripts/paperclip.sh feedback-trace list --company-id <id>
{baseDir}/scripts/paperclip.sh feedback-trace list --status pending --vote-value down --company-id <id>

Issue Read Status & Inbox

# Mark issue as read
{baseDir}/scripts/paperclip.sh issue mark-read <issue-id>

# Mark issue as unread
{baseDir}/scripts/paperclip.sh issue mark-unread <issue-id>

# Archive from inbox
{baseDir}/scripts/paperclip.sh issue inbox-archive <issue-id>

# Unarchive from inbox
{baseDir}/scripts/paperclip.sh issue inbox-unarchive <issue-id>

Issue Lifecycle Gotchas

The full state machine and transition rules live in the canonical Issues docs. The most common pitfalls when scripting against the API:

Status state machine (allowed transitions)

backlog ──ready──▶ todo ──checkout──▶ in_progress ──submit──▶ in_review
                    ▲                    │ │ │                  │   │
                    │   blocker──────────┘ │ │                  │   │ changes
                    │                      │ │ submit/done      │   │ requested
                    │                blocked│ ▼                  ▼   │
                    └──unblock/release─────┘ done ◀─approve─── (stage)
                                              ▲
        any non-terminal ──cancel──▶ cancelled ┘
        terminal (done/cancelled) ──reopen: true──▶ todo

Required headers on agent-side mutations

When an agent (not board) updates a checked-out issue — comment, status change, document write — the request must include:

X-Paperclip-Run-Id: <current-run-id>

Without it, the server rejects the mutation as a checkout-ownership violation. Board users don't need this header.

Reopening terminal issues

# Wrong — rejected by the server
issue update <id> --status todo            # done/cancelled is terminal

# Right — only reopen unlocks terminal status
PATCH /api/issues/{id}  { "reopen": true, "comment": "Re-opening because…" }

The reopen: true flag also accepts an explicit non-default status if you want to reopen as e.g. in_review instead of the default todo.

blockedByIssueIds — first-class blocker links

Don't write blockers as free-text comments ("blocked by FLE-1234"). Use the structured field:

issue update <id> --label-ids "..."
# Direct API call needed for blockedByIssueIds (not yet exposed via wrapper):
PATCH /api/issues/{id}  { "blockedByIssueIds": ["uuid-1", "uuid-2"] }

When every blocker reaches done, the server fires an issue_blockers_resolved wake on the dependent. Cancelled blockers do not count as resolved — replace or remove them explicitly. Free-text comments never auto-wake.

GET /api/issues/{id}/heartbeat-context

Compact payload for agent wakeups: reduced issue summary + ancestors + project/goal summaries + comment cursor + optional wakeComment + attachment summaries. Cheaper than the full issue detail; designed for the heartbeat path.

curl -H "Authorization: Bearer $PAPERCLIP_API_TOKEN" \
  "$PAPERCLIP_API_URL/api/issues/$ISSUE_ID/heartbeat-context"

hiddenAt field — declutter without status change

PATCH /api/issues/{id} { "hiddenAt": "2026-05-05T12:00:00Z" } removes the issue from default list responses without changing its status or history. Set to null to unhide. Use for stale duplicates you don't want to cancel.

Common mistakes

MistakeWhat goes wrongDo this instead
PATCH status: "in_progress" to claim a taskSkips checkout, leaves checkoutRunId empty, race-proneAlways claim via POST /api/issues/{id}/checkout with expectedStatuses and X-Paperclip-Run-Id
Retrying a 409 Conflict from checkoutIssue is owned by another agent — retrying steals/thrashes the lockTreat 409 as terminal — pick a different issue
Free-text "blocked by FLE-XXXX" commentDependent never auto-wakes when blocker resolvesSet blockedByIssueIds on create or PATCH
Cancelling a blocker, expecting auto-unblockcancelled blockers do not count as resolvedReplace or remove the cancelled id from blockedByIssueIds
Approving an in_review issue you're not the current participant forServer returns 422Inspect executionState.currentParticipant first
PATCH status: "todo" on a done issueRejected — terminal transitions require reopenSend PATCH { reopen: true, comment: "…" }
Forgetting X-Paperclip-Run-Id on agent mutationsRejected as checkout-ownership violationAlways pass current heartbeat run id on agent PATCH/POST
PATCH status: "cancelled" while executionState is pendingReturns HTTP 200 but silently drops the cancel — status stays unchanged. No 422, no error message.First clear policy: PATCH executionPolicy: null (returns issue to original executor with status in_progress), then PATCH status: "cancelled".

Routines (Scheduled Tasks)

Routines create issues on a schedule (cron), via webhook, or via API trigger. Each routine has one or more triggers that control when it fires.

Routine CRUD

# List routines
{baseDir}/scripts/paperclip.sh routine list --company-id <id>

# Create routine (title + projectId + assigneeAgentId required)
{baseDir}/scripts/paperclip.sh routine create \
  --title "Daily standup" \
  --description "Check issues and report status" \
  --project-id <project-id> \
  --assignee-agent-id <agent-id> \
  --priority medium \
  --concurrency-policy coalesce_if_active \
  --catch-up-policy skip_missed \
  --company-id <id>

# Get routine details (includes triggers, recent runs)
{baseDir}/scripts/paperclip.sh routine get <routine-id>

# Update routine (all flags optional)
{baseDir}/scripts/paperclip.sh routine update <routine-id> \
  --title "Weekly standup" \
  --assignee-agent-id <new-agent-id> \
  --priority high \
  --status paused \
  --concurrency-policy skip_if_active

# Delete routine
{baseDir}/scripts/paperclip.sh routine delete <routine-id>

# Manually trigger routine
{baseDir}/scripts/paperclip.sh routine run <routine-id>

Routine fields (create/update)

FieldTypeCreateUpdateNotes
titlestringrequiredoptional
descriptionstringoptionaloptional
projectIdstringrequired--Parent project
goalIdstringoptional--Linked goal
parentIssueIdstringoptional--Parent issue for generated issues
assigneeAgentIdstringrequiredoptionalAgent that executes
priorityenumoptionaloptionalcritical/high/medium/low
statusenumoptionaloptionalactive/paused/archived
concurrencyPolicyenumoptionaloptionalSee below
catchUpPolicyenumoptionaloptionalSee below
variablesarrayoptionaloptionalParameterized variables

Routine statuses: active, paused, archived

Concurrency policies:

  • coalesce_if_active -- merge with running issue if one exists (default)
  • always_enqueue -- always create a new issue
  • skip_if_active -- skip if an issue is already running

Catch-up policies:

  • skip_missed -- don't fire for missed schedules (default)
  • enqueue_missed_with_cap -- enqueue missed runs up to a cap

Routine Variables

Routines can have parameterized variables that get injected into the generated issue. Pass as JSON array:

{baseDir}/scripts/paperclip.sh routine create \
  --title "Report Generator" \
  --project-id <id> \
  --assignee-agent-id <id> \
  --variables '[{"name": "region", "label": "Target Region", "type": "select", "required": true, "options": ["DACH", "US", "APAC"], "defaultValue": "DACH"}]' \
  --company-id <id>

Variable fields:

FieldTypeDescription
namestringVariable identifier
labelstringDisplay label
typeenumtext/textarea/number/boolean/select
defaultValuemixedDefault value
requiredbooleanRequired?
optionsstring[]Choices (for select type)

Routine Triggers

Triggers define WHEN a routine fires. A routine can have multiple triggers.

# Create a cron schedule trigger
{baseDir}/scripts/paperclip.sh trigger create <routine-id> \
  --kind schedule \
  --cron "0 9 * * *" \
  --timezone "Europe/Berlin" \
  --label "Daily 9am Berlin"

# Create a webhook trigger
{baseDir}/scripts/paperclip.sh trigger create <routine-id> \
  --kind webhook \
  --label "GitHub Push Hook" \
  --signing-mode hmac_sha256

# Create an API trigger (callable via POST /routines/{id}/run)
{baseDir}/scripts/paperclip.sh trigger create <routine-id> \
  --kind api \
  --label "Manual API"

# Update trigger (all flags optional)
{baseDir}/scripts/paperclip.sh trigger update <trigger-id> \
  --enabled false \
  --cron "0 */6 * * *"

# Delete trigger
{baseDir}/scripts/paperclip.sh trigger delete <trigger-id>

# Rotate webhook secret
{baseDir}/scripts/paperclip.sh trigger rotate-secret <trigger-id>

Trigger kinds: schedule, webhook, api Signing modes (webhook): bearer, hmac_sha256

Trigger fields (create/update)

FieldTypeCreateUpdateNotes
kindenumrequired--schedule/webhook/api
labelstringoptionaloptionalDisplay name
enabledbooleanoptionaloptionalDefault: true
cronExpressionstringrequired (schedule)optionalCron expression
timezonestringoptionaloptionalIANA timezone
signingModeenumoptional (webhook)optionalbearer/hmac_sha256
replayWindowSecnumberoptional (webhook)optionalReplay window

Routine Runs

# List recent runs
{baseDir}/scripts/paperclip.sh routine runs <routine-id>

Run statuses: received, coalesced, skipped, issue_created, completed, failed


Approvals (Governance)

# List pending approvals
{baseDir}/scripts/paperclip.sh approval list --status pending --company-id <id>

# Get approval details
{baseDir}/scripts/paperclip.sh approval get <approval-id>

# Approve / reject
{baseDir}/scripts/paperclip.sh approval approve <approval-id> --note "Looks good"
{baseDir}/scripts/paperclip.sh approval reject <approval-id> --note "Too expensive"

# Request revision / resubmit
{baseDir}/scripts/paperclip.sh approval request-revision <approval-id> --note "Needs more detail on budget"
{baseDir}/scripts/paperclip.sh approval resubmit <approval-id>

# Comment on approval
{baseDir}/scripts/paperclip.sh approval comment <approval-id> --body "What's the expected ROI?"

# List linked issues
{baseDir}/scripts/paperclip.sh approval issues <approval-id>

Approval types: hire_agent, approve_ceo_strategy, budget_override_required Approval statuses: pending, revision_requested, approved, rejected, cancelled


Cost & Budget

# Company cost summary (optional --from/--to ISO dates)
{baseDir}/scripts/paperclip.sh cost summary --company-id <id>
{baseDir}/scripts/paperclip.sh cost summary --from 2026-01-01 --to 2026-03-31 --company-id <id>

# Cost breakdowns
{baseDir}/scripts/paperclip.sh cost by-agent --company-id <id>
{baseDir}/scripts/paperclip.sh cost by-agent-model --company-id <id>
{baseDir}/scripts/paperclip.sh cost by-project --company-id <id>
{baseDir}/scripts/paperclip.sh cost by-provider --company-id <id>
{baseDir}/scripts/paperclip.sh cost by-biller --company-id <id>

# Finance reports
{baseDir}/scripts/paperclip.sh cost finance --company-id <id>
{baseDir}/scripts/paperclip.sh cost finance-by-biller --company-id <id>
{baseDir}/scripts/paperclip.sh cost finance-by-kind --company-id <id>
{baseDir}/scripts/paperclip.sh cost finance-events --company-id <id> --limit 50

# Current spending window & provider quotas
{baseDir}/scripts/paperclip.sh cost window-spend --company-id <id>
{baseDir}/scripts/paperclip.sh cost quota-windows --company-id <id>

# Budget overview (policies + active incidents)
{baseDir}/scripts/paperclip.sh budget overview --company-id <id>

# Budget management
{baseDir}/scripts/paperclip.sh budget update --company-id <id> --budget-monthly-cents 1000000
{baseDir}/scripts/paperclip.sh budget reset --company-id <id>
{baseDir}/scripts/paperclip.sh budget soft-reset --company-id <id>

# Agent-level budget
{baseDir}/scripts/paperclip.sh budget agent-update <agent-id> --budget-monthly-cents 100000

# Log cost events (for agents tracking their own usage)
{baseDir}/scripts/paperclip.sh cost log-cost-event --company-id <id> --data '{"agentId":"...","provider":"anthropic","model":"claude-sonnet-4-20250514","inputTokens":1000,"outputTokens":500,"costCents":2}'
{baseDir}/scripts/paperclip.sh cost log-finance-event --company-id <id> --data '{"kind":"subscription","billerName":"Anthropic","amountCents":5000}'

Secrets

# List secrets (values are never returned)
{baseDir}/scripts/paperclip.sh secret list --company-id <id>

# List available secret providers
{baseDir}/scripts/paperclip.sh secret providers --company-id <id>

# Create secret
{baseDir}/scripts/paperclip.sh secret create \
  --name "OPENAI_KEY" \
  --value "sk-..." \
  --description "OpenAI API key for research agents" \
  --provider local_encrypted \
  --company-id <id>

# Update secret metadata (not the value)
{baseDir}/scripts/paperclip.sh secret update <secret-id> \
  --name "OPENAI_API_KEY" \
  --description "Updated description"

# Rotate secret value (creates new version)
{baseDir}/scripts/paperclip.sh secret rotate <secret-id> --value "sk-new..."

# Delete secret
{baseDir}/scripts/paperclip.sh secret delete <secret-id> --company-id <id>

Secret providers: local_encrypted, aws_secrets_manager, gcp_secret_manager, vault

Secret fields

FieldTypeCreateUpdateNotes
namestringrequiredoptionalSecret name
valuestringrequired--Secret value (use rotate to change)
providerenumoptional--Storage backend (default: local_encrypted)
descriptionstringoptionaloptional
externalRefstringoptionaloptionalReference in external secret manager

Company Import & Export (Portability)

# Export company (Board or CEO)
{baseDir}/scripts/paperclip.sh company export <company-id>

# Preview export before executing (CEO)
{baseDir}/scripts/paperclip.sh company export-preview <company-id>

# Import company from bundle (Board only)
{baseDir}/scripts/paperclip.sh company import --data '{"bundleJson":{...},"target":{"mode":"new_company"},"collisionStrategy":"merge"}'

# Preview import before applying (Board only)
{baseDir}/scripts/paperclip.sh company import-preview --data '{"bundleJson":{...},"target":{"mode":"new_company"}}'

# CEO-level safe import (restricted: own company only, no "replace" strategy)
{baseDir}/scripts/paperclip.sh company safe-import-preview <company-id> --data '...'
{baseDir}/scripts/paperclip.sh company safe-import <company-id> --data '...'

Import collision strategies: merge, skip, replace (replace forbidden for CEO-level safe imports) Import target modes: new_company, existing_company


Plugin Webhooks

Plugins can receive external webhooks at a public endpoint (no auth required):

POST /api/plugins/:pluginId/webhooks/:endpointKey

Prerequisites: Plugin must be in "ready" status and declare webhooks.receive capability. Endpoint must be declared in plugin manifest. Every delivery is recorded with full payload, headers, status, and timing.


WebSocket Live Events

Real-time event stream for company-wide events:

ws(s)://PAPERCLIP_API_URL/api/companies/:companyId/events/ws

Authentication

  • Agent API key: ?token=<api_key> query param or Authorization: Bearer <api_key> header
  • Board session: Session cookie (browser)
  • Local trusted mode: No auth required

Event Types

EventDescription
heartbeat.run.queuedRun entered queue
heartbeat.run.statusRun status changed
heartbeat.run.eventRun event occurred
heartbeat.run.logLog output from run
agent.statusAgent status changed
activity.loggedActivity event recorded
plugin.ui.updatedPlugin UI updated
plugin.worker.crashedPlugin worker crashed
plugin.worker.restartedPlugin worker restarted

Event payload: {"id": <num>, "companyId": "...", "type": "<event-type>", "createdAt": "...", "payload": {...}}

Server sends ping every 30s -- clients must respond with pong or connection terminates.


Dashboard, Activity & Org Chart

{baseDir}/scripts/paperclip.sh dashboard --company-id <id>

# Activity log (all filters optional)
{baseDir}/scripts/paperclip.sh activity --company-id <id>
{baseDir}/scripts/paperclip.sh activity --agent-id <id> --company-id <id>
{baseDir}/scripts/paperclip.sh activity --entity-type issue --action created --company-id <id>

# Org chart
{baseDir}/scripts/paperclip.sh org --company-id <id>

# Instance health
{baseDir}/scripts/paperclip.sh health

Concepts

  • Company = autonomous AI business with a mission, org chart, and budget
  • Agent = AI employee (Claude, Codex, Gemini, etc.) with a role, title, adapter, instructions, and skills
  • Goal = hierarchical objective (company → team → agent → task)
  • Project = scoped work with a lead agent, target date, linked goals, and workspaces
  • Issue = unit of work (ticket). Has status, priority, assignee, parent/children, documents, labels
  • Routine = recurring task generator with triggers (cron/webhook/API), concurrency policies, and variables
  • Trigger = schedule/webhook/API definition that fires a routine
  • Approval = governance gate. Agent hires and CEO strategy require Board approval
  • Workspace = execution environment for a project (local path, git repo, or remote managed)
  • Cost event = token usage tracked per agent, per issue, per project, per goal, per biller
  • Budget policy = spending limit with auto-pause enforcement
  • Feedback = thumbs up/down votes and execution traces on issues for quality tracking
  • Attachment = file attached to an issue (images, PDFs, etc., max 10MB)
  • Plugin = extensible integration that can receive webhooks and provide UI widgets
  • Live Events = real-time WebSocket stream of company-wide events (run status, agent status, activity)

Task Hierarchy

Goal (company) → Goal (team) → Project → Issue → Sub-issue

All work traces back to company goals for alignment and cost attribution.

Workflow: Creating a Company

  1. company create -- creates the company
  2. goal create --level company -- set the company mission goal
  3. agent hire for the CEO -- triggers Board approval
  4. approval approve -- Board approves the hire
  5. project create -- create a project linked to the goal
  6. routine create + trigger create -- set up recurring tasks
  7. issue create -- give the CEO their first strategic task
  8. CEO breaks it down into sub-issues, hires team, delegates

Auth

Paperclip exposes three authentication paths (per API Authentication docs):

PathWhen to useHeader
Board API key (bearer)Scripted access, CI, our wrapperAuthorization: Bearer pcp_board_<token>
Session cookieBrowser UI, manual curl in trusted modeCookie sent via -b cookies.txt
Agent API key / run JWTAgent-side calls (heartbeats)Authorization: Bearer <agent-key>

Bearer always wins over cookies — a request with a valid bearer token is not treated as a session request, even if a cookie is also sent.

Minting a board API key

Use the official CLI device-code flow (CLI Auth docs):

paperclipai auth login                          # default mode
paperclipai auth login --instance-admin         # admin scope
paperclipai auth login --api-base https://...   # specific server

The CLI opens a browser for approval and stores a pcp_board_* token. Export it as PAPERCLIP_API_TOKEN for our wrapper.

Mutation requests still need Origin

CSRF protection requires the Origin header on all mutating requests (POST/PATCH/DELETE), regardless of auth method. The wrapper sets it automatically. Without it: {"error":"Board mutation requires trusted browser origin"}.

Agent-authenticated mutations need X-Paperclip-Run-Id

When an agent posts to a checked-out issue (comment, status update), the request must include X-Paperclip-Run-Id: <current-run-id>. The server uses it to verify checkout ownership; without it, mutations are rejected as ownership violations.

Fallback: email + password sign-in

If you can't mint a bearer token (e.g. local dev, no paperclipai CLI), the wrapper falls back to POST /api/auth/sign-in/email (BetterAuth) and uses the returned session cookie. The session token returned in that response is not a board API key — it only works as a cookie, not as a bearer header. Set PAPERCLIP_EMAIL and PAPERCLIP_PASSWORD.

⚠️ Rate limit: the sign-in endpoint returns 429 after roughly 10 fresh sign-ins per minute. Since the wrapper signs in per CLI call, a tight loop (e.g. fan-out reads across many resources) will trip it almost immediately. Use the bearer path instead.

Critical Rules

  • Always assign issues on creation. Set assigneeAgentId in the POST body. An unassigned issue is invisible to agents -- they only see issues assigned to them. Never create an issue and assign it in a separate step; do it atomically in the POST.
  • Set status todo, not backlog. Only todo issues trigger agent invocation. backlog is planning-only -- the agent will never pick it up. Default is backlog, so always pass --status todo when you want the agent to act immediately.
  • List agents before creating issues if you don't have the agent ID cached: agent list --company-id <id>.
  • Routines are not dispatchers. assigneeAgentId + status>=todo already wakes the assigned agent. A paused "patrol" routine never causes a backlog of assigned issues — only schedule-triggered work (audits, digests) is affected. Don't recommend re-enabling routines to "unblock the review queue" — diagnose the assignee or status instead.
  • Use a bearer token for scripted access. The cookie sign-in endpoint rate-limits at ~10 fresh sign-ins per minute, and our wrapper signs in per call. Mint a board API key via paperclipai auth login and export it as PAPERCLIP_API_TOKEN. Cookie auth stays only as a fallback for trusted-mode local dev.

API Notes

  • All responses are JSON
  • All endpoints are under /api/ prefix
  • Issues support single-assignee atomic checkout (prevents double-work)
  • Costs are tracked per agent, per issue, per project, per goal
  • Budget policies auto-pause agents when spending limits are exceeded
  • Routines use separate trigger objects (schedule/webhook/api) instead of inline cron
  • Routines support concurrency policies and parameterized variables
  • Agents have managed instruction bundles with versioned files
  • Agents can have skills synced via the skills-sync endpoint
  • Company export/import enables portability and templating
  • Secret rotation creates new versions (audit trail)
  • Issue execution history is per-issue (/issues/:id/runs), not per-agent
  • Real-time events available via WebSocket (/companies/:id/events/ws)
  • Feedback votes and traces track issue quality and agent performance
  • Budgets can be managed at company level and per-agent level
  • Plugin webhooks are public endpoints (no auth) -- plugins must declare the capability

Praktische Erkenntnisse aus echten Instanzen

Siehe references/api-notes.md für:

  • Cookie-Auth vs Bearer Token (was wirklich funktioniert)
  • CSRF: Origin Header Pflicht bei allen Mutations
  • Skills: zweistufig (Company Catalog → Agent Assignment)
  • Secrets: Company-scoped, kein Agent-Level
  • Private Repos: funktionieren nicht ohne Token
  • Was fehlt / nicht funktioniert

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.