25 KiB
Paperclip V1 Implementation Spec
Status: Implementation contract for first release (V1)
Date: 2026-02-17
Audience: Product, engineering, and agent-integration authors
Source inputs: GOAL.md, PRODUCT.md, SPEC.md, DATABASE.md, current monorepo code
1. Document Role
SPEC.md remains the long-horizon product spec.
This document is the concrete, build-ready V1 contract.
When there is a conflict, SPEC-implementation.md controls V1 behavior.
2. V1 Outcomes
Paperclip V1 must provide a full control-plane loop for autonomous agents:
- A human board creates a company and defines goals.
- The board creates and manages agents in an org tree.
- Agents receive and execute tasks via heartbeat invocations.
- All work is tracked through tasks/comments with audit visibility.
- Token/cost usage is reported and budget limits can stop work.
- The board can intervene anywhere (pause agents/tasks, override decisions).
Success means one operator can run a small AI-native company end-to-end with clear visibility and control.
3. Explicit V1 Product Decisions
These decisions close open questions from SPEC.md for V1.
| Topic | V1 Decision |
|---|---|
| Tenancy | Single-tenant deployment, multi-company data model |
| Company model | Company is first-order; all business entities are company-scoped |
| Board | Single human board operator per deployment |
| Org graph | Strict tree (reports_to nullable root); no multi-manager reporting |
| Visibility | Full visibility to board and all agents in same company |
| Communication | Tasks + comments only (no separate chat system) |
| Task ownership | Single assignee; atomic checkout required for in_progress transition |
| Recovery | No automatic reassignment; work recovery stays manual/explicit |
| Agent adapters | Built-in process and http adapters |
| Auth | Mode-dependent human auth (local_trusted implicit board in current code; authenticated mode uses sessions), API keys for agents |
| Budget period | Monthly UTC calendar window |
| Budget enforcement | Soft alerts + hard limit auto-pause |
| Deployment modes | Canonical model is local_trusted + authenticated with private/public exposure policy (see doc/DEPLOYMENT-MODES.md) |
4. Current Baseline (Repo Snapshot)
As of 2026-02-17, the repo already includes:
- Node + TypeScript backend with REST CRUD for
agents,projects,goals,issues,activity - React UI pages for dashboard/agents/projects/goals/issues lists
- PostgreSQL schema via Drizzle with embedded PostgreSQL fallback when
DATABASE_URLis unset
V1 implementation extends this baseline into a company-centric, governance-aware control plane.
5. V1 Scope
5.1 In Scope
- Company lifecycle (create/list/get/update/archive)
- Goal hierarchy linked to company mission
- Agent lifecycle with org structure and adapter configuration
- Task lifecycle with parent/child hierarchy and comments
- Atomic task checkout and explicit task status transitions
- Board approvals for hires and CEO strategy proposal
- Heartbeat invocation, status tracking, and cancellation
- Cost event ingestion and rollups (agent/task/project/company)
- Budget settings and hard-stop enforcement
- Board web UI for dashboard, org chart, tasks, agents, approvals, costs
- Agent-facing API contract (task read/write, heartbeat report, cost report)
- Auditable activity log for all mutating actions
5.2 Out of Scope (V1)
- Plugin framework and third-party extension SDK
- Revenue/expense accounting beyond model/token costs
- Knowledge base subsystem
- Public marketplace (ClipHub)
- Multi-board governance or role-based human permission granularity
- Automatic self-healing orchestration (auto-reassign/retry planners)
6. Architecture
6.1 Runtime Components
server/: REST API, auth, orchestration servicesui/: Board operator interfacepackages/db/: Drizzle schema, migrations, DB clients (Postgres)packages/shared/: Shared API types, validators, constants
6.2 Data Stores
- Primary: PostgreSQL
- Local default: embedded PostgreSQL at
~/.paperclip/instances/default/db - Optional local prod-like: Docker Postgres
- Optional hosted: Supabase/Postgres-compatible
- File/object storage:
- local default:
~/.paperclip/instances/default/data/storage(local_disk) - cloud: S3-compatible object storage (
s3)
- local default:
6.3 Background Processing
A lightweight scheduler/worker in the server process handles:
- heartbeat trigger checks
- stuck run detection
- budget threshold checks
Separate queue infrastructure is not required for V1.
7. Canonical Data Model (V1)
All core tables include id, created_at, updated_at unless noted.
7.0 Auth Tables
Human auth tables (users, sessions, and provider-specific auth artifacts) are managed by the selected auth library. This spec treats them as required dependencies and references users.id where user attribution is needed.
7.1 companies
iduuid pknametext not nulldescriptiontext nullstatusenum:active | paused | archived
Invariant: every business record belongs to exactly one company.
7.2 agents
iduuid pkcompany_iduuid fkcompanies.idnot nullnametext not nullroletext not nulltitletext nullstatusenum:active | paused | idle | running | error | terminatedreports_touuid fkagents.idnullcapabilitiestext nulladapter_typeenum:process | httpadapter_configjsonb not nullcontext_modeenum:thin | fatdefaultthinbudget_monthly_centsint not null default 0spent_monthly_centsint not null default 0last_heartbeat_attimestamptz null
Invariants:
- agent and manager must be in same company
- no cycles in reporting tree
terminatedagents cannot be resumed
7.3 agent_api_keys
iduuid pkagent_iduuid fkagents.idnot nullcompany_iduuid fkcompanies.idnot nullnametext not nullkey_hashtext not nulllast_used_attimestamptz nullrevoked_attimestamptz null
Invariant: plaintext key shown once at creation; only hash stored.
7.4 goals
iduuid pkcompany_iduuid fk not nulltitletext not nulldescriptiontext nulllevelenum:company | team | agent | taskparent_iduuid fkgoals.idnullowner_agent_iduuid fkagents.idnullstatusenum:planned | active | achieved | cancelled
Invariant: at least one root company level goal per company.
7.5 projects
iduuid pkcompany_iduuid fk not nullgoal_iduuid fkgoals.idnullnametext not nulldescriptiontext nullstatusenum:backlog | planned | in_progress | completed | cancelledlead_agent_iduuid fkagents.idnulltarget_datedate null
7.6 issues (core task entity)
iduuid pkcompany_iduuid fk not nullproject_iduuid fkprojects.idnullgoal_iduuid fkgoals.idnullparent_iduuid fkissues.idnulltitletext not nulldescriptiontext nullstatusenum:backlog | todo | in_progress | in_review | done | blocked | cancelledpriorityenum:critical | high | medium | lowassignee_agent_iduuid fkagents.idnullcreated_by_agent_iduuid fkagents.idnullcreated_by_user_iduuid fkusers.idnullrequest_depthint not null default 0billing_codetext nullstarted_attimestamptz nullcompleted_attimestamptz nullcancelled_attimestamptz null
Invariants:
- single assignee only
- task must trace to company goal chain via
goal_id,parent_id, or project-goal linkage in_progressrequires assignee- terminal states:
done | cancelled
7.7 issue_comments
iduuid pkcompany_iduuid fk not nullissue_iduuid fkissues.idnot nullauthor_agent_iduuid fkagents.idnullauthor_user_iduuid fkusers.idnullbodytext not null
7.8 heartbeat_runs
iduuid pkcompany_iduuid fk not nullagent_iduuid fk not nullinvocation_sourceenum:scheduler | manual | callbackstatusenum:queued | running | succeeded | failed | cancelled | timed_outstarted_attimestamptz nullfinished_attimestamptz nullerrortext nullexternal_run_idtext nullcontext_snapshotjsonb null
7.9 cost_events
iduuid pkcompany_iduuid fk not nullagent_iduuid fkagents.idnot nullissue_iduuid fkissues.idnullproject_iduuid fkprojects.idnullgoal_iduuid fkgoals.idnullbilling_codetext nullprovidertext not nullmodeltext not nullinput_tokensint not null default 0output_tokensint not null default 0cost_centsint not nulloccurred_attimestamptz not null
Invariant: each event must attach to agent and company; rollups are aggregation, never manually edited.
7.10 approvals
iduuid pkcompany_iduuid fk not nulltypeenum:hire_agent | approve_ceo_strategyrequested_by_agent_iduuid fkagents.idnullrequested_by_user_iduuid fkusers.idnullstatusenum:pending | approved | rejected | cancelledpayloadjsonb not nulldecision_notetext nulldecided_by_user_iduuid fkusers.idnulldecided_attimestamptz null
7.11 activity_log
iduuid pkcompany_iduuid fk not nullactor_typeenum:agent | user | systemactor_iduuid/text not nullactiontext not nullentity_typetext not nullentity_iduuid/text not nulldetailsjsonb nullcreated_attimestamptz not null default now()
7.12 company_secrets + company_secret_versions
- Secret values are not stored inline in
agents.adapter_config.env. - Agent env entries should use secret refs for sensitive values.
company_secretstracks identity/provider metadata per company.company_secret_versionsstores encrypted/reference material per version.- Default provider in local deployments:
local_encrypted.
Operational policy:
- Config read APIs redact sensitive plain values.
- Activity and approval payloads must not persist raw sensitive values.
- Config revisions may include redacted placeholders; such revisions are non-restorable for redacted fields.
7.13 Required Indexes
agents(company_id, status)agents(company_id, reports_to)issues(company_id, status)issues(company_id, assignee_agent_id, status)issues(company_id, parent_id)issues(company_id, project_id)cost_events(company_id, occurred_at)cost_events(company_id, agent_id, occurred_at)heartbeat_runs(company_id, agent_id, started_at desc)approvals(company_id, status, type)activity_log(company_id, created_at desc)assets(company_id, created_at desc)assets(company_id, object_key)uniqueissue_attachments(company_id, issue_id)company_secrets(company_id, name)uniquecompany_secret_versions(secret_id, version)unique
7.14 assets + issue_attachments
assetsstores provider-backed object metadata (not inline bytes):iduuid pkcompany_iduuid fk not nullproviderenum/text (local_disk | s3)object_keytext not nullcontent_typetext not nullbyte_sizeint not nullsha256text not nulloriginal_filenametext nullcreated_by_agent_iduuid fk nullcreated_by_user_iduuid/text fk null
issue_attachmentslinks assets to issues/comments:iduuid pkcompany_iduuid fk not nullissue_iduuid fk not nullasset_iduuid fk not nullissue_comment_iduuid fk null
8. State Machines
8.1 Agent Status
Allowed transitions:
idle -> runningrunning -> idlerunning -> errorerror -> idleidle -> pausedrunning -> paused(requires cancel flow)paused -> idle* -> terminated(board only, irreversible)
8.2 Issue Status
Allowed transitions:
backlog -> todo | cancelledtodo -> in_progress | blocked | cancelledin_progress -> in_review | blocked | done | cancelledin_review -> in_progress | done | cancelledblocked -> todo | in_progress | cancelled- terminal:
done,cancelled
Side effects:
- entering
in_progresssetsstarted_atif null - entering
donesetscompleted_at - entering
cancelledsetscancelled_at
8.3 Approval Status
pending -> approved | rejected | cancelled- terminal after decision
9. Auth and Permissions
9.1 Board Auth
- Session-based auth for human operator
- Board has full read/write across all companies in deployment
- Every board mutation writes to
activity_log
9.2 Agent Auth
- Bearer API key mapped to one agent and company
- Agent key scope:
- read org/task/company context for own company
- read/write own assigned tasks and comments
- create tasks/comments for delegation
- report heartbeat status
- report cost events
- Agent cannot:
- bypass approval gates
- modify company-wide budgets directly
- mutate auth/keys
9.3 Permission Matrix (V1)
| Action | Board | Agent |
|---|---|---|
| Create company | yes | no |
| Hire/create agent | yes (direct) | request via approval |
| Pause/resume agent | yes | no |
| Create/update task | yes | yes |
| Force reassign task | yes | limited |
| Approve strategy/hire requests | yes | no |
| Report cost | yes | yes |
| Set company budget | yes | no |
| Set subordinate budget | yes | yes (manager subtree only) |
10. API Contract (REST)
All endpoints are under /api and return JSON.
10.1 Companies
GET /companiesPOST /companiesGET /companies/:companyIdPATCH /companies/:companyIdPOST /companies/:companyId/archive
10.2 Goals
GET /companies/:companyId/goalsPOST /companies/:companyId/goalsGET /goals/:goalIdPATCH /goals/:goalIdDELETE /goals/:goalId(soft delete optional, hard delete board-only)
10.3 Agents
GET /companies/:companyId/agentsPOST /companies/:companyId/agentsGET /agents/:agentIdPATCH /agents/:agentIdPOST /agents/:agentId/pausePOST /agents/:agentId/resumePOST /agents/:agentId/terminatePOST /agents/:agentId/keys(create API key)POST /agents/:agentId/heartbeat/invoke
10.4 Tasks (Issues)
GET /companies/:companyId/issuesPOST /companies/:companyId/issuesGET /issues/:issueIdPATCH /issues/:issueIdPOST /issues/:issueId/checkoutPOST /issues/:issueId/releasePOST /issues/:issueId/commentsGET /issues/:issueId/commentsPOST /companies/:companyId/issues/:issueId/attachments(multipart upload)GET /issues/:issueId/attachmentsGET /attachments/:attachmentId/contentDELETE /attachments/:attachmentId
10.4.1 Atomic Checkout Contract
POST /issues/:issueId/checkout request:
{
"agentId": "uuid",
"expectedStatuses": ["todo", "backlog", "blocked"]
}
Server behavior:
- single SQL update with
WHERE id = ? AND status IN (?) AND (assignee_agent_id IS NULL OR assignee_agent_id = :agentId) - if updated row count is 0, return
409with current owner/status - successful checkout sets
assignee_agent_id,status = in_progress, andstarted_at
10.5 Projects
GET /companies/:companyId/projectsPOST /companies/:companyId/projectsGET /projects/:projectIdPATCH /projects/:projectId
10.6 Approvals
GET /companies/:companyId/approvals?status=pendingPOST /companies/:companyId/approvalsPOST /approvals/:approvalId/approvePOST /approvals/:approvalId/reject
10.7 Cost and Budgets
POST /companies/:companyId/cost-eventsGET /companies/:companyId/costs/summaryGET /companies/:companyId/costs/by-agentGET /companies/:companyId/costs/by-projectPATCH /companies/:companyId/budgetsPATCH /agents/:agentId/budgets
10.8 Activity and Dashboard
GET /companies/:companyId/activityGET /companies/:companyId/dashboard
Dashboard payload must include:
- active/running/paused/error agent counts
- open/in-progress/blocked/done issue counts
- month-to-date spend and budget utilization
- pending approvals count
10.9 Error Semantics
400validation error401unauthenticated403unauthorized404not found409state conflict (checkout conflict, invalid transition)422semantic rule violation500server error
11. Heartbeat and Adapter Contract
11.1 Adapter Interface
interface AgentAdapter {
invoke(agent: Agent, context: InvocationContext): Promise<InvokeResult>;
status(run: HeartbeatRun): Promise<RunStatus>;
cancel(run: HeartbeatRun): Promise<void>;
}
11.2 Process Adapter
Config shape:
{
"command": "string",
"args": ["string"],
"cwd": "string",
"env": {"KEY": "VALUE"},
"timeoutSec": 900,
"graceSec": 15
}
Behavior:
- spawn child process
- stream stdout/stderr to run logs
- mark run status on exit code/timeout
- cancel sends SIGTERM then SIGKILL after grace
11.3 HTTP Adapter
Config shape:
{
"url": "https://...",
"method": "POST",
"headers": {"Authorization": "Bearer ..."},
"timeoutMs": 15000,
"payloadTemplate": {"agentId": "{{agent.id}}", "runId": "{{run.id}}"}
}
Behavior:
- invoke by outbound HTTP request
- 2xx means accepted
- non-2xx marks failed invocation
- optional callback endpoint allows asynchronous completion updates
11.4 Context Delivery
thin: send IDs and pointers only; agent fetches context via APIfat: include current assignments, goal summary, budget snapshot, and recent comments
11.5 Scheduler Rules
Per-agent schedule fields in adapter_config:
enabledbooleanintervalSecinteger (minimum 30)maxConcurrentRunsfixed at1for V1
Scheduler must skip invocation when:
- agent is paused/terminated
- an existing run is active
- hard budget limit has been hit
12. Governance and Approval Flows
12.1 Hiring
- Agent or board creates
approval(type=hire_agent, status=pending, payload=agent draft). - Board approves or rejects.
- On approval, server creates agent row and initial API key (optional).
- Decision is logged in
activity_log.
Board can bypass request flow and create agents directly via UI; direct create is still logged as a governance action.
12.2 CEO Strategy Approval
- CEO posts strategy proposal as
approval(type=approve_ceo_strategy). - Board reviews payload (plan text, initial structure, high-level tasks).
- Approval unlocks execution state for CEO-created delegated work.
Before first strategy approval, CEO may only draft tasks, not transition them to active execution states.
12.3 Board Override
Board can at any time:
- pause/resume/terminate any agent
- reassign or cancel any task
- edit budgets and limits
- approve/reject/cancel pending approvals
13. Cost and Budget System
13.1 Budget Layers
- company monthly budget
- agent monthly budget
- optional project budget (if configured)
13.2 Enforcement Rules
- soft alert default threshold: 80%
- hard limit: at 100%, trigger:
- set agent status to
paused - block new checkout/invocation for that agent
- emit high-priority activity event
- set agent status to
Board may override by raising budget or explicitly resuming agent.
13.3 Cost Event Ingestion
POST /companies/:companyId/cost-events body:
{
"agentId": "uuid",
"issueId": "uuid",
"provider": "openai",
"model": "gpt-5",
"inputTokens": 1234,
"outputTokens": 567,
"costCents": 89,
"occurredAt": "2026-02-17T20:25:00Z",
"billingCode": "optional"
}
Validation:
- non-negative token counts
costCents >= 0- company ownership checks for all linked entities
13.4 Rollups
Read-time aggregate queries are acceptable for V1. Materialized rollups can be added later if query latency exceeds targets.
14. UI Requirements (Board App)
V1 UI routes:
/dashboard/companiescompany list/create/companies/:id/orgorg chart and agent status/companies/:id/taskstask list/kanban/companies/:id/agents/:agentIdagent detail/companies/:id/costscost and budget dashboard/companies/:id/approvalspending/history approvals/companies/:id/activityaudit/event stream
Required UX behaviors:
- global company selector
- quick actions: pause/resume agent, create task, approve/reject request
- conflict toasts on atomic checkout failure
- no silent background failures; every failed run visible in UI
15. Operational Requirements
15.1 Environment
- Node 20+
DATABASE_URLoptional- if unset, auto-use PGlite and push schema
15.2 Migrations
- Drizzle migrations are source of truth
- no destructive migration in-place for V1 upgrade path
- provide migration script from existing minimal tables to company-scoped schema
15.3 Logging and Audit
- structured logs (JSON in production)
- request ID per API call
- every mutation writes
activity_log
15.4 Reliability Targets
- API p95 latency under 250 ms for standard CRUD at 1k tasks/company
- heartbeat invoke acknowledgement under 2 s for process adapter
- no lost approval decisions (transactional writes)
16. Security Requirements
- store only hashed agent API keys
- redact secrets in logs (
adapter_config, auth headers, env vars) - CSRF protection for board session endpoints
- rate limit auth and key-management endpoints
- strict company boundary checks on every entity fetch/mutation
17. Testing Strategy
17.1 Unit Tests
- state transition guards (agent, issue, approval)
- budget enforcement rules
- adapter invocation/cancel semantics
17.2 Integration Tests
- atomic checkout conflict behavior
- approval-to-agent creation flow
- cost ingestion and rollup correctness
- pause while run is active (graceful cancel then force kill)
17.3 End-to-End Tests
- board creates company -> hires CEO -> approves strategy -> CEO receives work
- agent reports cost -> budget threshold reached -> auto-pause occurs
- task delegation across teams with request depth increment
17.4 Regression Suite Minimum
A release candidate is blocked unless these pass:
- auth boundary tests
- checkout race test
- hard budget stop test
- agent pause/resume test
- dashboard summary consistency test
18. Delivery Plan
Milestone 1: Company Core and Auth
- add
companiesand company scoping to existing entities - add board session auth and agent API keys
- migrate existing API routes to company-aware paths
Milestone 2: Task and Governance Semantics
- implement atomic checkout endpoint
- implement issue comments and lifecycle guards
- implement approvals table and hire/strategy workflows
Milestone 3: Heartbeat and Adapter Runtime
- implement adapter interface
- ship
processadapter with cancel semantics - ship
httpadapter with timeout/error handling - persist heartbeat runs and statuses
Milestone 4: Cost and Budget Controls
- implement cost events ingestion
- implement monthly rollups and dashboards
- enforce hard limit auto-pause
Milestone 5: Board UI Completion
- add company selector and org chart view
- add approvals and cost pages
Milestone 6: Hardening and Release
- full integration/e2e suite
- seed/demo company templates for local testing
- release checklist and docs update
19. Acceptance Criteria (Release Gate)
V1 is complete only when all criteria are true:
- A board user can create multiple companies and switch between them.
- A company can run at least one active heartbeat-enabled agent.
- Task checkout is conflict-safe with
409on concurrent claims. - Agents can update tasks/comments and report costs with API keys only.
- Board can approve/reject hire and CEO strategy requests in UI.
- Budget hard limit auto-pauses an agent and prevents new invocations.
- Dashboard shows accurate counts/spend from live DB data.
- Every mutation is auditable in activity log.
- App runs with embedded PostgreSQL by default and with external Postgres via
DATABASE_URL.
20. Post-V1 Backlog (Explicitly Deferred)
- plugin architecture
- richer workflow-state customization per team
- milestones/labels/dependency graph depth beyond V1 minimum
- realtime transport optimization (SSE/WebSockets)
- public template marketplace integration (ClipHub)
21. Company Portability Package (V1 Addendum)
V1 supports company import/export using a portable package contract:
- markdown-first package rooted at
COMPANY.md - implicit folder discovery by convention
.paperclip.yamlsidecar for Paperclip-specific fidelity- canonical base package is vendor-neutral and aligned with
docs/companies/companies-spec.md - common conventions:
agents/<slug>/AGENTS.mdteams/<slug>/TEAM.mdprojects/<slug>/PROJECT.mdprojects/<slug>/tasks/<slug>/TASK.mdtasks/<slug>/TASK.mdskills/<slug>/SKILL.md
Export/import behavior in V1:
- export emits a clean vendor-neutral markdown package plus
.paperclip.yaml - projects and starter tasks are opt-in export content rather than default package content
- export strips environment-specific paths (
cwd, local instruction file paths, inline prompt duplication) - export never includes secret values; env inputs are reported as portable declarations instead
- import supports target modes:
- create a new company
- import into an existing company
- import supports collision strategies:
rename,skip,replace - import supports preview (dry-run) before apply
- GitHub imports warn on unpinned refs instead of blocking