Paperclip AI Task Inbox Classification and Archive System: Complete Technical Guide
The Paperclip AI task inbox classification and archive system ingests work items, classifies them by type, assigns them to agents via the Wakeup Coordinator, and archives completed runs with immutable audit trails.
Paperclip is an open-source control plane that transforms collections of AI agents into fully-scoped "companies." At the heart of this architecture lies the Task Inbox—a ticket system that orchestrates how work flows from creation through classification, execution, and final archival. This deep dive explores the complete lifecycle, from packages/db/src/schema/issue.ts to the WebSocket-powered real-time dashboard.
How the Task Inbox Receives and Classifies Work
Ingestion: Creating Tasks from Multiple Sources
The inbox accepts work through three primary channels: GitHub issues, incoming webhooks, or manual UI actions. Each creates a row in the issue table defined in packages/db/src/schema/issue.ts.
A task stores:
goal— the objective descriptionproject— organizational groupingparentlinks — for hierarchical task trees
This structure supports complex workflows where large initiatives decompose into sub-tasks.
Classification: Tagging by Type and Scope
Once ingested, the Issue Service applies a type tag. According to the Agent Runs specification, common classifications include:
bug— defects requiring fixesfeature— new capability developmentroutine— scheduled, repetitive work
The classification logic is company-scoped, meaning each deployed "company" maintains independent label taxonomies. This isolation prevents cross-contamination between organizations sharing the same Paperclip instance.
Classification triggers automatically based on source patterns. For example, GitHub issues labeled bug in the source repository propagate that classification into the inbox.
Agent Assignment and the Wakeup Coordinator
From Classification to Execution Queue
When an assigneeAgentId is set—either manually or via automation rules—the Wakeup Coordinator enqueues an assignment source request in agent_wakeup_requests. This table functions as the central nervous system for agent activation.
The coordinator supports four wakeup sources per doc/spec/agent-runs.md#8-8-wakeup-sources:
| Source | Trigger Condition |
|---|---|
timer |
Scheduled intervals for periodic agents |
assignment |
Task explicitly assigned to agent |
on_demand |
Manual API trigger |
automation |
Rule-based reactive triggers |
Atomic Checkout Prevents Double Work
The system guarantees exactly-once execution through database-level row locking. When the Run Executor claims a wakeup request, it performs an atomic update to heartbeat_runs. This transaction locks the row, ensuring no other executor can claim the same work—even under high concurrency.
Heartbeat Execution and Session Management
The Run Executor Pipeline
The Run Executor—defined in doc/spec/agent-runs.md#6-architecture-overview—handles the complete execution flow:
- Claims the wakeup request from the queue
- Creates a
heartbeat_runsrow to track this execution - Spawns the configured adapter (e.g.,
claude_localorcodex_local) - Streams stdout/stderr to the RunLogStore
- Persists outcome, token usage, cost, and
log_refupon completion
Session Resume Across Heartbeats
Multi-step agent workflows require continuity. Paperclip solves this through session persistence in agent_task_sessions.
Each adapter type manages its own session identifier:
claude_local— Claude CLI session IDcodex_local— Codex CLI session ID
When a subsequent heartbeat arrives for the same taskKey, the executor retrieves the stored session and resumes execution context. This enables agents to maintain state across minutes, hours, or days of intermittent operation.
The Archive System: Immutable Audit Trails
What Gets Archived
Upon run completion, the archival process captures:
| Data | Storage Location | Purpose |
|---|---|---|
| Run outcome | heartbeat_runs.status |
Success/failure classification |
| Token usage | heartbeat_runs.token_count |
Cost tracking and budgeting |
| Cost | heartbeat_runs.cost_usd |
Financial accounting |
| Full log | RunLogStore via log_ref |
Debug and compliance |
| Event timeline | heartbeat_run_events |
Lightweight audit trail |
RunLogStore: Pluggable Log Storage
The RunLogStore protocol defined in doc/spec/agent-runs.md#6-3-run-log-storage-protocol abstracts where full execution logs live. Implementations include:
- Local filesystem — default for development
- S3-compatible object storage — production scale
- Custom adapters — enterprise audit systems
The UI's Archive view renders tasks in read-only mode, preserving an immutable history even as active inboxes churn with new work.
Real-Time Status Delivery
WebSocket Event Architecture
The Realtime Event Hub at /api/companies/:companyId/events/ws pushes lightweight events to connected clients. Per doc/spec/agent-runs.md#11-11-1-transport, three core event types drive the UI:
heartbeat.run.status— execution phase changesagent.status.changed— agent availability transitionsissue.updated— task metadata modifications
This architecture eliminates polling. The inbox board reflects state changes within milliseconds of database commits.
Company Isolation and Governance
Multi-Tenant Safety
Every table in packages/db/src/schema/ includes company_id as a partition key. A single Paperclip deployment safely hosts thousands of independent companies with complete data isolation.
Governance Gates
Before any wakeup executes, the system enforces:
- Approval workflows — required sign-offs for sensitive task types
- Budget hard-stops — spend limits per agent or company
- Audit logging — immutable record of who triggered what
These controls transform raw agent execution into enterprise-grade operations.
Practical Code Examples
Starting a Local Development Instance
git clone https://github.com/paperclipai/paperclip.git
cd paperclip
pnpm install
pnpm dev # API + UI on http://localhost:3100
Creating a Classified Task via REST API
curl -X POST http://localhost:3100/api/companies/:companyId/issues \
-H "Authorization: Bearer <board-token>" \
-H "Content-Type: application/json" \
-d '{
"title": "Generate weekly report",
"description": "Collect sales data and produce a PDF",
"labels": ["routine","report"],
"assigneeAgentId": "<agent-uuid>"
}'
This request creates an inbox entry, classifies it as routine, and immediately enqueues an assignment wakeup for the target agent.
Manually Triggering a Heartbeat
curl -X POST http://localhost:3100/api/agents/<agent-id>/wakeup \
-H "Authorization: Bearer <board-token>" \
-d '{"source":"on_demand","triggerDetail":"manual"}'
The endpoint enqueues an on_demand request; the executor will run the agent and update task status accordingly.
Retrieving Archived Run Logs
curl http://localhost:3100/api/heartbeat-runs/<run-id>/log \
-H "Authorization: Bearer <board-token>"
The API streams the raw log from the configured RunLogStore implementation.
Subscribing to Live Events
const ws = new WebSocket(
"ws://localhost:3100/api/companies/<company-id>/events/ws?auth=<ws-token>"
);
ws.onmessage = e => console.log("Event:", JSON.parse(e.data));
Received events include structured payloads for immediate UI state updates.
Key Source Files
| File | Role |
|---|---|
packages/db/src/schema/issue.ts |
Inbox task entity definition |
packages/db/src/schema/heartbeat_runs.ts |
Per-execution outcome persistence |
packages/db/src/schema/agent_wakeup_requests.ts |
Wakeup Coordinator queue table |
packages/db/src/schema/agent_task_sessions.ts |
Resumable session storage |
packages/adapters/claude-local/* |
Claude CLI adapter implementation |
packages/adapters/codex-local/* |
Codex CLI adapter implementation |
server/src/routes/agent.ts |
Wakeup and heartbeat API endpoints |
ui/src/pages/Inbox.tsx |
React inbox, classification, and archive UI |
doc/spec/agents-runtime.md |
Heartbeat model and session handling |
doc/spec/agent-runs.md |
Runs subsystem complete specification |
Summary
- The Task Inbox in Paperclip AI functions as a company-scoped ticket system with full classification, assignment, and archival capabilities.
- Classification occurs at ingestion via the Issue Service, tagging tasks as
bug,feature,routine, or custom types. - The Wakeup Coordinator manages four trigger sources (
timer,assignment,on_demand,automation) throughagent_wakeup_requests. - Atomic checkout via
heartbeat_runsrow locking guarantees exactly-once execution even under contention. - Session resume in
agent_task_sessionsenables multi-step agent workflows to persist across intermittent heartbeats. - The Archive system combines lightweight
heartbeat_run_eventswith immutable full logs in the pluggable RunLogStore. - Real-time updates flow through company-scoped WebSockets at
/api/companies/:companyId/events/ws. - All components respect company isolation via
company_idpartitioning and enforce governance gates before execution.
Frequently Asked Questions
How does Paperclip AI prevent duplicate task execution?
The Run Executor uses database-level atomic transactions when claiming work from agent_wakeup_requests. The claim operation updates heartbeat_runs with row-level locking, ensuring only one executor instance succeeds. Failed claims receive immediate feedback and skip to the next available task.
Can agents resume work after being interrupted?
Yes. Through the session resume mechanism in agent_task_sessions, adapters persist their session identifiers (Claude CLI ID, Codex CLI ID, etc.) across heartbeats. When a task's taskKey recieves a new heartbeat, the executor retrieves the stored session and continues execution context rather than starting fresh.
What storage options exist for archived run logs?
The RunLogStore protocol supports pluggable implementations. The default uses local filesystem storage suitable for development. Production deployments typically configure S3-compatible object storage. Organizations with strict compliance requirements can implement custom adapters targeting their audit systems.
How does the inbox handle multiple companies on one deployment?
Every database table—including issue, heartbeat_runs, agent_wakeup_requests, and agent_task_sessions—includes company_id as a mandatory partition key. All queries filter by this scope, and the WebSocket hub at /api/companies/:companyId/events/ws isolates connections per company. This architecture enables secure multi-tenancy without separate infrastructure per tenant.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →