99 KiB
Paperclip V1 Implementation Spec
Status: Implementation contract for first release (V1)
Date: 2026-04-28
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). An effective task or ancestor pause replaces the message composer with an amber Resume takeover. New board messages, including updates with comments, are rejected until the hold is released. Drafts survive pause and resume.
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 | Company-scoped visibility: board + all in-company agents can see all work objects by default; public/private deployment flags affect external exposure only and do not imply project/issue privacy |
| Communication | Tasks + comments only (no separate chat system) |
| Task ownership | Single assignee; atomic checkout required for in_progress transition |
| Task watchdogs | A task watchdog is an explicitly configured, issue-subtree-scoped verification and recovery capacity. It may restore live task paths inside the watched subtree; for issue-thread interaction resolution it is an ordinary agent subject to the same audience and containment checks, not board authority, active-run output monitoring, or general liveness recovery. |
| Recovery | Liveness/watchdog recovery preserves explicit ownership: continue interrupted local conversations with bounded fresh turns and preserved history, never replay tool calls automatically; retain native ownership and real execution gates; preserve verified stop evidence and reconsider saved post-stop user messages after cleanup; otherwise open visible source-scoped recovery actions by default, use issue-backed recovery only for independent repair work, or require human escalation (see doc/execution-semantics.md) |
| Agent adapters | Built-in process, http, local CLI/session adapters, and OpenClaw gateway support; external adapters can also be loaded through the adapter plugin flow |
| Plugin framework | Local/self-hosted early plugin runtime is in scope; cloud marketplace and packaged public distribution remain out of scope |
| 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) |
Low-trust agent presets are containment controls for hostile automated work, not
general project or issue privacy controls. The core preset resolver contract is
documented in doc/LOW-TRUST-PRESETS.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)
- Cloud-grade plugin marketplace/distribution beyond the local/self-hosted plugin runtime
- Revenue/expense accounting beyond model/token costs
- Knowledge base subsystem
- Public marketplace (ClipHub)
- Multi-board governance (multiple board UIs for a single company)
- Automatic self-healing orchestration (auto-reassign/retry planners)
Role-based human permission granularity is V1 — see the humans-and-permissions
plan, the principal_permission_grants table, and the PERMISSION_KEYS set
in packages/shared/src/constants.ts.
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 | archivedpause_reasontext nullpaused_attimestamptz nullissue_prefixtext not nullissue_counterint not nullbudget_monthly_centsint not null default 0spent_monthly_centsint not null default 0require_board_approval_for_new_agentsboolean not null default false- feedback sharing consent fields
Invariant: every business record belongs to exactly one company.
7.2 agents
iduuid pkcompany_iduuid fkcompanies.idnot nullnametext not nullroletext not nulltitletext nullicontext nullstatusenum:active | paused | idle | running | error | pending_approval | terminatedreports_touuid fkagents.idnullcapabilitiestext nulladapter_typetext; built-ins includeprocess,http,claude_local,codex_local,gemini_local,opencode_local,pi_local,cursor,hermes_local,hermes_gateway, andopenclaw_gatewayadapter_configjsonb not nullruntime_configjsonb not null default{}; contains Paperclip runtime policy such as heartbeat scheduling and debug settingsdefault_environment_iduuid fkenvironments.idnullcontext_modeenum:thin | fatdefaultthinbudget_monthly_centsint not null default 0spent_monthly_centsint not null default 0- pause fields:
pause_reason,paused_at permissionsjsonb not null default{}last_heartbeat_attimestamptz nullmetadatajsonb 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 nullenvjsonb null (same secret-aware env binding format used by agent config)
Invariant:
- project env is merged into run environment for issues in that project and overrides conflicting agent env keys before Paperclip runtime-owned keys are injected
Routine execution issues add a routine-scoped env overlay after project env and before Paperclip runtime-owned keys. Routine env uses the same secret-aware binding format, is stored on routines.env, is snapshotted in routine revisions, and resolves secret refs against the routine binding target so routine-owned secrets do not require direct bindings on the executing agent.
Project source repositories use the existing project_workspaces collection.
Each selected GitHub repository has a canonical repo_url and stable provider ID
in metadata.githubRepositoryId; the first workspace remains the execution default.
The board can select multiple repositories from its usable personal and shared
GitHub grants. Selection does not grant runtime credential access. Legacy workspace
URLs remain valid. Project creation and repository replacement are transactional.
See doc/project-repositories.md for the API and UI contract.
7.6 issues (core task entity)
iduuid pkcompany_iduuid fk not nullproject_iduuid fkprojects.idnullproject_workspace_iduuid fkproject_workspaces.idnullgoal_iduuid fkgoals.idnullparent_iduuid fkissues.idnulltitletext not nulldescriptiontext nullstatusenum:backlog | todo | in_progress | in_review | done | blocked | cancelledpriorityenum:critical | high | medium | lowreview_policynullable enum:anyone | not_creator | human_only; null is equivalent toanyoneassignee_agent_iduuid fkagents.idnullassignee_user_idtext null- checkout/execution locks:
checkout_run_id,execution_run_id,execution_agent_name_key,execution_locked_at created_by_agent_iduuid fkagents.idnullcreated_by_user_iduuid fkusers.idnull- identifier fields:
issue_number,identifier - origin fields:
origin_kind,origin_id,origin_run_id,origin_fingerprint - Creation stores the actor run in
origin_run_idunless an explicit origin run is supplied.GET /api/companies/:companyId/issues?createdFromIssueId=<uuid>selects tasks created by runs bound to that source task, using native run issue identity or persisted legacy task context. Historical rows without an origin run may use their recorded creation activity; comments and shared creators do not establish provenance. Source, run, activity and result are company-scoped. - Relation lists can use
sortField=id&sortDir=asc&afterId=<uuid>for stable pagination. The cursor excludes earlier IDs and cannot be combined with an offset or activity-based order. - The streamlined task page's Tasks tab keeps two independent memberships: the existing subtask tree, and created tasks grouped by their current project (or No project). A created subtask appears in both. Only Subtasks has completion progress; groups collapse independently and unfinished tasks sort above finished tasks.
request_depthint not null default 0work_modetext not null defaultstandard; supported values:standard: normal autonomous execution. Agents may investigate, edit files, create artifacts, and complete the task.ask: answer-only execution. Agents may use tools for investigation or temporary scratch work, but the deliverable is an issue-thread answer; they must not write implementation code or produce an implementation plan.planning: plan-only execution. Agents create or revise the plan without implementation work. Accepting a fresh confirmation for the issue's currentplanrevision atomically changes this mode tostandard, so the continuation may implement the approved plan on the source issue.
billing_codetext nullassignee_adapter_overridesjsonb nullexecution_policyjsonb nullexecution_statejsonb null- execution workspace fields:
execution_workspace_id,execution_workspace_preference,execution_workspace_settings started_attimestamptz nullcompleted_attimestamptz nullcancelled_attimestamptz nullhidden_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- an
in_review -> done | cancelledverdict is authorized against the current review policy while the issue row is locked; a policy change in the same request or a concurrent request cannot relax that verdict gate - accepting or rejecting the review-confirmation interaction locks the issue row before resolving the interaction and reauthorizes against the current review policy in that transaction
- accepting a fresh
request_confirmationfor the current issue'splanrevision changeswork_mode = planningtowork_mode = standardin the same transaction as the accepted interaction; the existing agent-return transition also moves an eligiblein_reviewissue totodowithout changing its agent owner - while a restrictive review policy is stored, changing it requires an actor who is allowed by that row-locked policy
- the transition into
in_reviewand its requester activity record commit atomically, including transitions without an explicit review-interaction binding - 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 nullcost_statustext not null defaultreported;unpricedwhen usage exists but no price was reportedinput_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_strategy | budget_override_required | request_board_approvalrequested_by_agent_iduuid fkagents.idnullrequested_by_user_iduuid fkusers.idnullstatusenum:pending | revision_requested | 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 project_memberships + agent_memberships
Per-user project/agent membership is personal visibility state for board users. It only controls whether a resource appears in the current user's sidebar; it must not grant or revoke access to all-pages, detail pages, selectors, assignment flows, search, or existing permissions.
project_memberships:
iduuid pkcompany_iduuid fkcompanies.idnot nullproject_iduuid fkprojects.idnot nulluser_idtext not nullstateenum-like text:joined | leftcreated_attimestamptz not null default now()updated_attimestamptz not null default now()- unique
(company_id, user_id, project_id)
agent_memberships mirrors the same shape with agent_id instead of project_id and unique (company_id, user_id, agent_id).
Invariants:
- Missing membership rows mean
joinedfor backward compatibility. - Mutations are board-user-only
/meoperations; agent API keys are rejected. - Viewer-role board users may update only their own membership rows through the narrow self-service helper.
- Target project/agent ownership is checked against the path company before mutation.
- Successful state changes write
resource_membership.joinedorresource_membership.leftactivity entries.
7.13 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.14 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)uniqueproject_memberships(company_id, user_id)project_memberships(company_id, user_id, project_id)uniqueagent_memberships(company_id, user_id)agent_memberships(company_id, user_id, agent_id)unique
7.15 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
- V1 attachment serving contract:
- Default upload allowlist includes common images, PDF, plain text/markdown/JSON/CSV/HTML, ZIP, and video artifacts (
video/mp4,video/webm,video/quicktime). - Attachment reads are company-scoped and expose stable path metadata:
contentPath/openPathfor inline-safe viewing anddownloadPathfor forced download. - Inline-safe responses use
Content-Disposition: inline; unsafe types and explicit download requests useattachment. - Script-capable content such as HTML is always served as an attachment with
X-Content-Type-Options: nosniffand a sandboxed, deny-by-default CSP; it is never rendered inline on the Paperclip origin. - Video attachments are inline-safe and support single
Range: bytes=start-endrequests with206,Content-Range, andAccept-Ranges: bytesfor browser playback/seeking.
- Default upload allowlist includes common images, PDF, plain text/markdown/JSON/CSV/HTML, ZIP, and video artifacts (
- Attachment-backed artifact work products use
type: "artifact",provider: "paperclip", and metadata withattachmentId,contentType,byteSize,contentPath,openPath,downloadPath, and optionaloriginalFilename. - Workspace-only file references use work product
metadata.resourceRefwithkind: "workspace_file",issueId,workspaceKind(execution_workspaceorproject_workspace),workspaceId,relativePath, optionalline/column, anddisplayPath. These references point at files in a workspace; they do not replace attachment-backed artifacts for deliverables that must be inspectable without workspace access.
7.15 documents + document_revisions + issue_documents
documentsstores editable text-first documents:iduuid pkcompany_iduuid fk not nulltitletext nullformattext not null (markdown)latest_bodytext not nulllatest_revision_iduuid nulllatest_revision_numberint not nullcreated_by_agent_iduuid fk nullcreated_by_user_iduuid/text fk nullupdated_by_agent_iduuid fk nullupdated_by_user_iduuid/text fk nulllocked_attimestamptz nulllocked_by_agent_iduuid fk nulllocked_by_user_iduuid/text fk null- Locked documents are immutable until unlocked. Board operators can lock/unlock; agent writes to a locked key create a new issue document with a derived key instead of overwriting the locked document.
document_revisionsstores append-only history:iduuid pkcompany_iduuid fk not nulldocument_iduuid fk not nullrevision_numberint not nullbodytext not nullchange_summarytext null
issue_documentslinks documents to issues with a stable workflow key:iduuid pkcompany_iduuid fk not nullissue_iduuid fk not nulldocument_iduuid fk not nullkeytext not null (plan,design,notes, etc.)
7.16 Current Implementation Addenda
The current implementation includes additional V1-control-plane tables beyond the original February snapshot:
- Issue structure and review:
issue_relationsfor blockers,labels/issue_labels,issue_thread_interactions,issue_approvals,issue_execution_decisions,issue_work_products,issue_inbox_archives,issue_read_states, and issue reference mention indexes. - Execution and workspace control:
execution_workspaces,project_workspaces,workspace_runtime_services,workspace_operations,environments,environment_leases,agent_task_sessions,agent_runtime_state,agent_wakeup_requests, heartbeat events, and watchdog decision tables. - Plugins and routines:
plugins, plugin config/state/entities/jobs/logs/webhooks, plugin database namespaces/migrations, plugin company settings,routines,routine_revisions,routine_triggers, androutine_runs. - Access and operations: company memberships, instance roles, principal permission grants, invites, join requests, board API keys, CLI auth challenges, budget policies/incidents, feedback exports/votes, company skills, sidebar preferences, and company logos.
Decision-desk triage uses company-scoped sidecars rather than adding queue fields to every attention source:
decision_queuesstores durable named queues, optional retention overrides, server-derived creator/run provenance, and data-backed seed rules.decision_queue_itemskeys membership by(queue_id, source_kind, source_id)and repeatscompany_idfor company-consistent joins.decision_triagekeys current decide-by/snooze state by(company_id, source_kind, source_id)and preserves the latest setter attribution.decision_triage_eventsis the immutable mutation history for queue membership and triage overrides, including actor, run, API-key, and responsible-user provenance.decision_retentionstores the attention source's last observed activity timestamp, monotonic version, Keep flag, and reversible archive provenance. Queueretention_daysoverrides use the shortest assigned queue threshold; otherwise the shelf threshold is 30 days.decision_archive_notification_outboxrecords one retry-safe origin-agent notification per source/archive version. The 90-day internal sweeper archives only unkept rows and coalesces delivery per origin agent.- Queue membership never grants source visibility. Item writes re-authorize the referenced source, and queue reads re-authorize every member before returning rows or counts.
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
V1 non-terminal liveness rule:
- agent-owned
todo,in_progress,in_review, andblockedissues must have a live execution path, an explicit waiting path, or an explicit recovery path in_reviewis healthy only when a typed execution participant, pending issue-thread interaction or approval, user owner, active run, queued wake, or explicit recovery action owns the next action- a blocked chain is covered only when each unresolved leaf issue is live or explicitly waiting
- external waits are durable only when persisted as a bounded monitor/scheduled wake, a first-class blocker with a named owner and action, or healthy delegated child work connected by a blocker edge when the source must wait; parent/child structure alone is not a wait path
- unmanaged shell jobs, detached sessions, adapter child processes, local polling loops, PIDs, logs, and comments are evidence rather than liveness; a managed runtime service counts only when paired with a persisted monitor, wake, blocker, or delegated issue that owns the next check
- heartbeat finalization evaluates liveness from persisted Paperclip state; an issue cannot remain healthy
in_progresssolely because the exiting heartbeat started a local/background watcher - a continuation cancelled as
issue_continuation_waiting_on_reviewfirst converts a current typed wait target into a first-class wait; without a current target it is classified asdeliberate_wait_without_targetand gives the invokable original owner five normal-model disposition-repair attempts (immediate, then after 60, 120, 240, and 480 seconds, with up to 10 percent jitter) - disposition repair revalidates blockers, children, interactions, approvals, monitors, execution stages, queued wakes, active runs, work products, owner invokability, budgets, and governance before every attempt; the attempt bound is keyed by durable source state, so comments or equivalent parked prose do not reset it while durable source-state changes may establish a new fingerprint
- backwards-compatible upgrades count consecutive historical
issue_continuation_waiting_on_reviewcancellations for the unchanged accepted-interaction source state against the same five-attempt disposition-repair ceiling; missing pre-upgrade recovery-action rows do not reset the budget - the source fingerprint, source-attempt count, next due time, source owner, and return owner persist in the recovery action; startup and periodic reconciliation resume that exact lineage without duplicate wakes, fold it when a current typed wait appears, and reschedule or escalate an expired action that has no live scheduled run
- source-attempt exhaustion opens one board-owned source-scoped recovery action without changing the source assignee and without waking a substitute agent; the board explicitly chooses whether to repair, retry the original owner, reassign, or resolve
- an active recovery action counts as a live source or blocker-chain path only while its owner has a live run, queued wake, scheduled retry, typed wait, or explicit board escalation; source and blocker projections consume the same nested recovery-path result
- when Paperclip cannot safely infer the next action, it surfaces the problem through visible blocked/recovery work instead of silently completing or reassigning work
- explicit recovery actions are the liveness primitive; source-scoped actions are the default form, issue-backed recovery is a fallback for independent repair work or safety boundaries, and comments alone are evidence rather than a healthy liveness path
- recovery-action ownership is separate from source-task ownership: automatic repair and board escalation preserve both source assignee fields; reassignment requires an explicit board decision or a policy-defined serious failure
- source-scoped recovery routing is cause-keyed: bounded continuity and disposition repair may retry only the original agent; provider-quota failures create/reuse a scheduled wait-recovery monitor; every other exhausted or unsafe path creates/reuses a board-owned recovery action with
routingPolicy: board_escalation_no_takeover_v1and no substitute-agent wake - legacy active agent-owned recovery actions remain readable, resolvable, and API-compatible after upgrade, but reconciliation does not enqueue another takeover wake for them
- active-run output silence is an informational board UI signal at one hour (
suspicious) and four hours (critical); it does not create or update issues or recovery actions, comment on or block source work, change assignments, or wake an agent - board snooze and continue decisions suppress the run signal until their stored re-arm time; a false-positive decision suppresses it permanently for that run; open legacy evaluation issues remain readable and manually resolvable without automatic refresh
Detailed ownership, execution, blocker, active-run watchdog, crash-recovery, and non-terminal liveness semantics are documented in doc/execution-semantics.md.
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 company-visible tasks and comments
- comment on and update visible tasks under the shared write rule
- create child tasks and assign visible work for delegation under the same rule
- 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 | pause: no; resume: direct agents:configure grant only |
| 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) |
| Manage responsible user's inbox state | yes | yes (default-open policy) |
| Manage another user's inbox state | yes | saved target-user opt-in or scoped inbox:manage grant |
| Set work-object visibility (issue/project) | no | no (pro gate) |
Agent resume is the only grant-gated exception in the lifecycle-route group. An
agent actor calling POST /agents/:agentId/resume must pass the protected
agent_config:update decision with scope.requiresChangeGrant: true; self
access does not bypass that decision, and agents:suggest-changes alone cannot
apply the lifecycle change. Pause, clear-error, terminate, approval, and
key-management routes remain board-only.
9.3.1 Shared default-open issue writes
For standard-trust agents, issue comments, issue field/status updates, child creation under a parent, and assignment share one authorization rule: the target issue must be visible to the agent and the responsible user represented by the run must also be authorized. In V1, issue visibility defaults to the whole company, so these writes are company-wide by default.
The shared rule does not widen low-trust, skill_test, or task_bridge key
scopes. It also does not replace run-lifecycle controls: checkout ownership,
active-run conflicts, status-transition validation, interaction ownership,
budget gates, and pause gates remain independently enforced. Comment access is
structurally downstream of issue read access (issue:comment is a subset of
issue:read).
Cross-issue writes are contained per heartbeat run. An agent-authored comment
may wake the target assignee, including an explicit resume: true comment on a
done or cancelled issue, but the wake remains agent-class and is subject to
the normal agent rewake throttle; comment presentation cannot give it human
wake privileges. Agent issue comments and updates require a persisted heartbeat
run bound to the authenticated agent and company; missing, invalid, or mismatched
run context fails closed before mutation. A run may attempt at most 20 cross-issue comments, issue
updates, or issue-thread interaction resolutions across one shared counter. The
server records each attempt with its source issue, target issue, run, count, and
rollout mode, and fails closed with the cap in the error once enforcement is
active. Writes to the run's own source issue are not counted. Assignee self-comments do not
wake the assignee, and a non-assignee comment cannot mint a mention grant.
Agent-authored issue comments persist the responsible user derived from the
authenticated actor; clients cannot choose that attribution. Each comment also
records the write-policy reason, and spoof attempts fail with an audited 422.
Every issue PATCH emits an issue.updated activity receipt containing the
actor, responsible user, run, authorization reason, and field-level before/after
changes so both agent and board edits are visible in the issue activity stream.
9.4 Permission Terminology and Default Visibility Rule
Paperclip V1 keeps a company-scoped visibility model as the default because centralized authorization and scoped work-object controls are not yet a core V1 control surface.
The approved term set is:
- Agent profile visibility: identity-level facts needed for delegation and governance (name, role, capabilities, reporting lines).
- Agent config visibility: adapter/runtime config metadata and secret-access policy.
- Assignment/invocation permission: who may modify or execute a task.
- Work-object visibility: who can read/write issues, comments, projects, and attachments.
- Tool/secret policy: what tools and secret-backed credentials an agent can use and what appears in logs.
- Escalation authority: where refusal/blocked decisions route (manager, then board).
9.5 Core V1 Rule: what “private” means
- A private marker on an agent profile (where represented) does not make company-visible work private.
- Company-visible work objects (issues, comments, work products, costs, activity, project/task state) remain visible to the board and in-company agents by default.
- Project/issue-level privacy, scoped assignment-only object visibility, and organization-wide custom ACLs are deferred to Pro/Enterprise controls.
9.6 V1 vs Pro/Enterprise Controls (recommended target split)
| Permission area | Free / V1 default | Pro / Enterprise |
|---|---|---|
| Company boundary | Hard boundary only (company_id) |
Multi-company policy overlays (membership, project, and task scopes) |
| Simple roles | Board + agent roles with existing approval/budget gates | Additional role aliases + scoped approver roles |
| Profile visibility | Full profile visibility for coordination and audit | Optional profile redaction / selective sharing for external surfaces |
| Config visibility | Board full read with redacted secret fields; agent config read/write constrained by own agent identity | Scoped config visibility controls and central policy enforcement |
| Assignment/invocation | Assignment creates execution authority; board can reassign or force release | Delegation policies and scoped invokers with deny-listed tool classes |
| Work-object visibility | All issues and projects in-company are visible to board and agents | Project/issue ACLs and reviewer-only channels |
| Tool/secret policy | Secret refs, log redaction, and adapter-level command/webhook restrictions | Tool allowlists with centralized policy evaluation |
| Company skills | Open to authenticated company agents; core enforces invariants and any stored restriction policy | Paperclip EE policy editor, protected-skill controls, presets, simulation, and policy audit UX |
| Inbox management | Responsible agent may archive/unarchive its responsible user's Mine items under a default-open user policy; explicit cross-user access requires saved target-user opt-in or inbox:manage; all mutations are audited |
Policy administration UX, organization presets, simulations, bulk controls, and richer audit/reporting surfaces |
| Escalation | Escalate from agent to manager to board; board approval/budget gates remain authoritative | Escalation routing and SLA windows |
9.7 Recommended first-slice implementation order
- Lock route-level checks for existing company boundaries, actor extraction, and approval/budget gates.
- Treat profile privacy as external-facing signal only; do not use it to hide company-visible work objects.
- Enforce assignment/invocation coupling (
assignee/agentchecks, checkout semantics, invocation checks). - Standardize read-path redaction for secrets and secret references, including logs and activity.
- Standardize escalation paths (
blockedand refusal) so non-board agents hand off by manager/board with immutable audit.
9.8 Scoped Task Assignment Grants
tasks:assign remains the broad assignment permission. Existing unscoped grants preserve compatibility and allow the principal to assign any visible company task within normal company-boundary checks.
tasks:assign_scope is the constrained assignment permission. Its principal_permission_grants.scope JSON must include at least one recognized constraint:
- Project scope:
projectId,projectIds, orallow: ["project:<projectId>"]. - Target-agent allowlist:
agentId,agentIds,assigneeAgentId,assigneeAgentIds,targetAgentId,targetAgentIds, orallow: ["agent:<agentId>"]. - Managed-subtree scope:
managerAgentId,managerAgentIds,managedSubtreeAgentId,managedSubtreeAgentIds,subtreeAgentId,subtreeAgentIds,subtreeRootAgentId,subtreeRootAgentIds, orallow: ["subtree:<agentId>"].
When multiple constraint families are present, assignment must satisfy all of them. Denials return 403 with a generic scope explanation and do not disclose details about hidden or unrelated resources.
A protected-agent hard block is represented canonically as
authorizationPolicy.protectedAgent.blockAssignment: true. It denies assignment
even when the caller has a broad or scoped assignment grant. A company
administrator must remove the block before assignment can be retried; no pending
approval is created. The legacy fields protectedAgent.requiresApproval and
assignmentPolicy.protectedAgentRequiresApproval remain fail-closed compatibility
aliases for the same hard block, but API denial copy must describe the block and
administrator remediation rather than promising a nonexistent approval step.
9.8.1 Issue-thread interaction resolver contract
Issue-thread interactions are coordination records, not grants of authority. Every
interaction kind defaults to resolver policy anyone when the create request omits
resolverPolicy. Restrictions are opt-in.
Canonical resolver policies are:
anyone: any authenticated actor in the interaction's company who can read the issue and use the normal resolution route. For agents this includes the creator agent and the creating/source run.not_creator: the explicit independent-review policy. It excludes the creator agent and creating/source run while otherwise using the ordinary agent resolver path.human_only: only an authorized human/board actor may resolve the interaction.
board_or_agents and board_only are deprecated migration and API-input aliases.
For new writes they normalize to anyone and human_only, respectively. API reads
return canonical requested/effective policies, compatibility aliases, and immutable
provenance. The persisted provenance is explicit, inherited, or
legacy_inherited_restriction; the effective-policy source is requested,
company_cap, or governed_action.
Historical rows predate explicit-vs-inherited provenance. Migration must never
silently widen an ambiguous pending card: legacy board_or_agents rows retain the
old creator-excluding behavior as canonical not_creator, legacy board_only rows
become human_only, and both are marked legacy_inherited_restriction. Resolved
outcomes and resolver attribution are immutable.
An explicit named agent or user addressee and a company-configured cap may narrow
the effective audience. Only the exact named addressee may resolve an addressed
interaction; a human does not override a user addressee. A cap never widens the
requested audience. Tool-action confirmations and
other hard-governed action cards remain human_only (or move to the formal approval
system) regardless of a requested open audience.
Surfaces that offer a resolution must state the effective audience before the
operator acts, from server metadata rather than a client-side policy inference.
Issue-thread cards read it from the interaction snapshot; attention rows read it
from the feed item's resolverAudience (canonical requested/effective policy,
effective-policy source, provenance, and the addressee/creator identities the
evaluator compares against), because a collapsed row carries decision verbs
before the interaction itself is fetched. A failed resolution keeps the server's
denial reason in visible, assertively announced feedback and names who may
respond; an audience denial is permanent, so it must not degrade to a retry
prompt. Neither surface may enable or disable a control on its own authority.
Every resolution remains company-scoped, run-attributed for agent actors, low-trust/task-bridge contained, target-current, and exact-once. Target staleness, supersession, continuation idempotency, and activity attribution remain mandatory. An open audience is not an uncapped one: when an agent run resolves an interaction on an issue other than its own source issue, the resolution is a cross-issue mutation and consumes the per-run cross-issue influence budget in §9.3, charged after audience authorization and before the interaction mutation, child tasks, continuation, tool action, or wake. Same-issue resolutions and board/user resolutions are outside that counter. Accepting or answering an interaction records a response only: suggested-task creation, provider/tool calls, deployment, spend, hiring, secrets, execution-policy decisions, and every other downstream effect must re-run its own authorization and approval checks. Mislabeling a governed action as an open interaction grants no downstream capability.
9.9 Task Watchdog Authority Contract
A task watchdog is a scoped execution capacity for a configured watchdog agent on one watched issue subtree. It is not a separate principal, does not inherit board auth, and does not expand the selected agent's company boundary. The server must enforce the watchdog contract from persisted watchdog configuration and run context; custom instructions and prompt text can narrow the mandate but cannot expand it.
The watched subtree is the source issue plus descendants reached through parent_id, excluding every issue whose origin_kind = 'task_watchdog' and excluding all descendants below those watchdog issues. The generated reusable watchdog issue is outside the watched work subtree for scan purposes, but the watchdog agent may update that reusable watchdog issue to record its own review disposition.
Task-watchdog wakes must include server-derived capability metadata that names the watched root, reusable watchdog issue, excluded task_watchdog origin branches, allowed operations, and denied operations. Watchdogs must use that metadata and server denials for capability discovery; they must not create visible probe issues, comments, or throwaway tasks to learn their permissions.
Allowed watchdog mutations
Within the watched subtree, a watchdog run may perform only mutations that restore or clarify the next live/waiting path:
- add comments that explain findings, evidence, and next action
- create descendant follow-up issues under an included subtree issue, inheriting company, project, goal, and workspace context from that subtree
- assign or reassign included issues to active, invokable, same-company agents when normal assignment checks and scoped assignment grants allow it
- move included issues among
todo,in_progress,in_review, andblockedwhen the transition is needed to restore a valid action path - reopen
doneorcancelledincluded issues only with explicit resume metadata and an audit comment when evidence shows the stopped disposition is wrong or incomplete - add, replace, or clear blockers on included issues when the blocker target is in the same company and the change makes the waiting path more accurate
- set or refresh a one-shot monitor on an included issue when the current assignee owns the future check
- resolve issue-thread interactions through the ordinary resolver-audience path when the watchdog agent otherwise has issue access and the effective policy allows it
- update the reusable watchdog issue itself to
done,in_review, orblockedwith the evidence for the watchdog decision
Every watchdog-triggered mutation must write activity with the watchdog id, source issue id, watchdog issue id when present, run id, and stop fingerprint. Mutations still use the normal status-transition, blocker, assignment, budget, and company-boundary guards.
Atomic recovery batch
A watchdog run may submit an atomic recovery batch of at most 3 mutations drawn from the allowed-mutation list above, validated against the stop fingerprint that run observed. The server applies the batch all-or-nothing: if the subtree's stop fingerprint changed between observation and application — the subtree went live concurrently — the entire remainder of the batch is aborted and the staleness is recorded as evidence on the reusable watchdog issue. The batch is single-shot per watchdog run. This replaces the exactly-one-fresh-write model: the stale-guard's purpose (never mutate a subtree that concurrently went live) is preserved by fingerprint validation on the whole batch rather than by capping the run at one write, so a restoration that needs both a state-restoring PATCH and an explanatory comment cannot forfeit the restoration by ordering the comment first.
Restoration verification and escalation
Reviewed-fingerprint suppression is disposition-aware. A watchdog disposition of "stopped state is legitimate" suppresses re-fire for that fingerprint as today. A disposition of "live path restored" arms a bounded verification instead:
- if a later scan observes the subtree stopped with a fingerprint equal to the one the restoration claimed to fix, the watchdog re-fires with an incremented attempt count for that fingerprint lineage
- restoration-attempt lineage (attempt number, claimed-fixed fingerprint, restoration actions) is persisted durable watchdog state
- the stop fingerprint (or the lineage check) must account for intermediate-node durable updates so a restoration that changes no stopped leaf is classified as a failed restoration, not as a reviewed stop
- after N attempts (N = 2–3, configuration-bounded) on the same fingerprint lineage, the platform stops re-firing and escalates to a human — the watchdog owner or a board notification — with the attempt history attached
Escalation is terminal for the automatic loop: no further watchdog wakes fire for that lineage until a human or a new durable subtree change produces a different fingerprint.
Disallowed watchdog mutations
A task watchdog must not:
- mutate issues outside the watched subtree, except for comments or newly created follow-up issues that are children of included subtree issues
- mutate company, project, goal, agent, auth, API key, budget, secret, environment, plugin, or deployment settings
- approve or reject rows in the
approvalstable, including hiring, CEO strategy, spend, budget override, orrequest_board_approvaldecisions - resolve execution-policy decisions unless the watchdog agent is the typed participant under that policy outside of its watchdog capacity
- force-release checkout/execution locks, cancel active runs, terminate processes, or perform active-run output watchdog decisions
- create visible probe issues, comments, or throwaway tasks to discover whether an operation is allowed
- delete issue documents, comments, attachments, work products, or activity records
- change the watchdog configuration, select a different watchdog agent, or create nested watchdog configurations
- treat custom instructions as authority to bypass approval gates, cross company boundaries, access secrets, or override this contract
When the safe next action needs one of these disallowed mutations, the watchdog must leave a valid waiting path by commenting, creating an in-subtree escalation/follow-up issue, assigning to the correct owner, or leaving the source issue blocked on a first-class blocker.
Interaction resolution
A task-watchdog run has no special resolver audience, plan-purpose marker, or
interaction-kind allowlist. The task-watchdog context neither widens nor
categorically removes the selected agent's ordinary interaction authority. The
same evaluator used for every agent applies anyone, not_creator, human_only,
named-addressee, company-cap, company-boundary, run-attribution, low-trust,
task-bridge, target-staleness, and exact-once checks.
Resolving an interaction does not authorize its downstream effect. In particular, an accepted plan still passes normal decomposition/idempotency checks, and a governed action still requires its own typed reviewer, permission, or formal approval. A watchdog may not use an open coordination response to bypass any item in the disallowed-mutations list above.
Downstream acceptance criteria
Implementation, security, UI, and QA work for task watchdogs must prove these contract points:
- server tests deny cross-company watched issues, watchdog agents, watchdog issues, blockers, interactions, and assignment targets
- server tests deny paused, terminated, pending-approval, budget-blocked, or otherwise uninvokable watchdog agents
- watchdog-scoped mutations can touch only the watched subtree and the reusable watchdog issue, with activity records for each mutation
- interaction tests prove watchdog runs use the same resolver policy as ordinary agents, without a watchdog-only kind or purpose-marker exception
- interaction tests cover
anyone,not_creator,human_only, named addressees, company caps, stale targets, governed actions, newer user comments, low-trust/task-bridge containment, and cross-company denial - scheduler tests prove live runs, queued wakes, and scheduled retries suppress watchdog wakeups, while terminal, cancelled, blocked, and review leaves are still verified when the subtree has no live path
- tests prove
task_watchdogorigin issues and descendants are excluded from scans so watchdogs do not trigger themselves - recovery-batch tests prove batches are capped at 3 allowed mutations, applied all-or-nothing, and aborted with recorded evidence when the observed stop fingerprint went stale mid-batch
- restoration-verification tests prove a "live path restored" disposition re-fires on an unchanged fingerprint with an incremented attempt count, a failed intermediate-node restoration is not treated as a reviewed stop, and the N-attempt bound escalates to a human with attempt history instead of firing forever
- regression tests prove watchdog capability discovery comes from wake metadata/denials and denied probes do not create visible issues
- UI copy and badges distinguish task watchdogs from active-run output watchdogs, monitors, reviewers, approvers, and liveness recovery
- prompt/context tests prove custom instructions are appended after non-overridable safety constraints and cannot expand authority
- QA validates a full create/edit/remove/run/reuse flow with screenshots for UI changes
No unresolved policy decision blocks implementation once CTO and Security accept this contract. Deliberately deferred and disallowed for the first implementation: letting watchdogs cancel active runs, approving board/governance actions, mutating outside the watched subtree, or allowing watchdog agents to modify their own watchdog configuration. Any expansion of those capabilities requires a new product/security review.
9.10 Company Skill Policy Contract
Product default
An authenticated agent may perform normal company-skill work without a skill-specific grant when the target company has no explicit skill policy. This includes creating, importing, installing, editing, updating, testing, resetting, and removing skills. Core MUST NOT introduce a skills:author prerequisite, a draft-only default, or an activation-approval default.
Authorization order is fixed:
- Enforce non-configurable platform invariants.
- Evaluate the company's explicit skill policy when one exists.
- Otherwise allow the authenticated company agent.
Non-configurable invariants include authenticated actor identity, exact company scoping, source and workspace path containment, package and frontmatter validation, secret redaction/non-export, immutable audit attribution, and any hard runtime isolation rule. A policy rule, legacy grant, plugin, or EE configuration cannot override these invariants.
For avoidance of doubt:
- Local-path imports, updates, resets, and project scans MUST resolve under a Paperclip-known local workspace root or a Paperclip-managed skill root. Arbitrary host filesystem paths are invalid even when the caller is otherwise authorized. Caller-supplied
source,sourceLocator, or similar path strings are descriptive input only; they MUST NOT expand authority beyond those approved roots. - Remote imports and updates MUST normalize to a known source category, require validated HTTPS or catalog sources, and resolve immutable content before install (for example pinned Git commit/content hash or pinned package version). Unknown schemes, unknown source categories, symlink escapes, and out-of-tree files fail closed before persistence.
- Unsafe executable content, fetch-and-exec patterns, and secret exfiltration or non-redacted secret material are platform safety failures. Policy cannot waive them; the route MUST reject the operation before any new skill version, install, update, or reset is persisted.
- Mandatory activity attribution is part of the invariant boundary. If the required audit record for a skill mutation or policy mutation cannot be persisted, the mutation MUST fail or roll back; do not return success with missing auditability.
Canonical actions and resources
The version 1 evaluator uses these stable action identifiers:
skills.create: create or fork a company-authored skill and create skill versionsskills.import: import or scan skills from a workspace, Git source, URL, or packageskills.install: install a catalog or externally sourced skill into the companyskills.edit: change skill metadata, name, files, test inputs, or test templatesskills.update: install a newer upstream revisionskills.test: start, cancel, or remove a skill test run and run a skill auditskills.reset: restore the installed/upstream revisionskills.remove: delete a company skill
Policy resources may include skillId, stable skillKey, sourceType, and sourceLocator. The stable source categories are workspace, catalog, git, external_package, generated, and unknown; adapters may preserve a more specific source value as metadata, but policy evaluation MUST normalize it to one of these categories. Core derives actor and company identity from authentication and derives known resource fields from stored data; a mutation client cannot authorize itself by supplying actor or resource identity fields.
Version 1 policy document
Absence of a policy record is semantically equivalent to the following document, but core SHOULD avoid materializing records for untouched companies:
{
"schemaVersion": 1,
"revision": 0,
"defaultEffect": "allow",
"rules": []
}
An explicit policy has a monotonically increasing revision, a defaultEffect of allow or deny, and ordered rules. Each rule contains a stable id, integer priority, effect (allow or deny), a subject selector (all_agents, agent ids, or role names), one or more canonical actions, and optional resource selectors for skill ids/keys and normalized source types/locators. An omitted resource selector matches every resource for the listed action.
Rules are evaluated by ascending priority, then stable rule id; the first matching rule decides. If no rule matches, defaultEffect decides. This supports both the normal open policy with targeted deny rules and an opt-in restricted preset with default deny plus explicit allow rules. Core MUST validate policy documents atomically and reject ambiguous, unknown-version, unknown-action, cross-company, or malformed selectors with 422.
Every decision returned by the evaluator has this stable shape:
{
"allowed": false,
"action": "skills.install",
"reason": "explicit_rule",
"policyRevision": 7,
"matchedRuleId": "deny-external-packages",
"remediation": "Contact a company administrator to change the skill policy."
}
reason is one of platform_invariant, no_policy_default, explicit_rule, policy_default, or legacy_compatibility. Mutation routes MUST use this evaluator and return 403 with code skill_policy_denied and the non-sensitive decision fields when an explicit restriction denies an operation. Denials must identify the action and remediation without exposing hidden rule data, secrets, or another company's policy.
Platform-invariant failures are not policy denials and MUST use stable machine-readable error codes so clients can distinguish non-overridable safety failures from optional administrative restrictions. Version 1 requires a finite code set covering at least:
skill_authentication_requiredskill_company_boundary_deniedskill_workspace_boundary_deniedskill_source_validation_failedskill_unsafe_content_blockedskill_secret_handling_blockedskill_policy_admin_required
Core Skill Studio and Paperclip EE MUST treat those codes as hard platform failures, not as prompts to loosen policy.
Core API and ownership boundary
Core owns and ships these company-scoped endpoints:
GET /companies/:companyId/skill-policyreturns the effective versioned policy, its revision, and whether it is materialized or the open default.PUT /companies/:companyId/skill-policyatomically replaces the policy and requires the caller's expected revision; stale writes return409.DELETE /companies/:companyId/skill-policyremoves explicit configuration and restores the open default.POST /companies/:companyId/skill-policy/evaluatesimulates decisions for administrative tooling without performing a skill mutation.
Policy reads, writes, deletion, and simulation enforce company access. Policy mutation and cross-principal simulation require board administration authority or the existing users:manage_permissions capability; ordinary skill access does not. Every policy mutation writes an activity event containing the actor, previous revision, new revision, and a redacted change summary. Skill mutation activity logging remains required independently of the policy decision.
Paperclip EE owns the detailed editor, presets, protected-skill management, policy simulation UX, and policy-specific audit views. EE consumes the core endpoints and does not implement a second evaluator. Core may expose a concise effective-policy summary and denial state, but MUST NOT depend on EE for enforcement or make EE installation a prerequisite for normal skill work.
Compatibility and availability
- Existing companies with no explicit restriction adopt the open default, including companies that previously depended on missing grants to deny skill changes. Release notes and upgrade guidance MUST call out this behavior change.
- Existing explicit restriction policies remain effective after migration.
- Legacy
skills:createandskills:suggest-changespositive grants remain accepted in APIs and portability packages. Historically either positive grant authorized the broad company-skill mutation surface, so in an explicit restricted policy either grant remains a compatibility allow fallback for all eight canonical skill actions only when no explicit rule matched. They never override an explicit deny or a platform invariant. With no explicit policy they are redundant because the default already allows the action. - Legacy
skills:suggest-changesconsent state is not a platform invariant for company skills and does not add a second mutation gate under the open-default policy. Companies that require approval or consent before skill changes must express that restriction through explicit skill-policy rules; authentication, company boundaries, source containment, validation, auditability, and runtime safety remain non-configurable invariants. - Import preview MUST report whether a package contains an explicit skill policy or legacy grants and how each will map. Import apply MUST preserve explicit policies, normalize supported legacy grants, and reject unknown policy versions rather than silently weakening them.
- Export MUST include explicit skill policy configuration and retained legacy grants in
.paperclip.yaml, never secret values or environment-specific paths. An unconfigured company exports no synthetic restriction. - If Paperclip EE is unavailable or removed, core continues to enforce stored policies and expose the policy API. Normal skill work remains available under the open default; explicit denials use core remediation text rather than a broken EE-only link.
Required regression tests
Phase 2 server tests and Phase 4 UI tests must prove:
- unauthenticated actors and authenticated actors from another company are denied for all skill mutation routes and all skill-policy routes
- local-path imports and project scans reject paths outside approved workspace or managed-skill roots, including symlink escapes and out-of-tree files
- remote imports and updates reject unknown schemes/categories, unpinned mutable refs, unsafe executable content, and secret exfiltration patterns before persistence
- policy mutation, policy reset, and cross-principal policy simulation require board administration authority or
users:manage_permissions; ordinary open-default skill access never grants those actions - explicit policy denials return
skill_policy_denied, while platform safety failures return the stable invariant denial codes above - successful skill mutations and policy mutations persist activity records with actor, company, run attribution, normalized action, and revision/change summary; audit-write failures do not leave successful unaudited mutations behind
9.11 Inbox Management Permission and Ownership Contract
inbox:manage is the permission key for agent-driven per-user inbox archive state. Inbox archive state changes presentation in a user's Mine inbox; it does not change issue status, assignment, visibility, or the underlying work record.
Core authorization follows these rules:
- Board users may archive or unarchive inbox entries for users in the company.
- An agent may manage the responsible user's inbox without an explicit grant when the authenticated run resolves that user and the user's inbox-agent policy permits the agent. This is the default-open path.
- A user may set inbox-agent policy to
disabledorallowlist. Policy restrictions override the default-open path, and low-trust agents are denied. - An agent targeting any user other than its resolved responsible user requires either a materialized target-user policy that permits that agent (
openor matchingallowlist) or an explicitinbox:managegrant. The implicit default-open policy for a missing row remains responsible-user-only, so it never becomes a blanket cross-user grant. Grants may be unscoped or constrained byscope.userIdsand act as administrative overrides, including over a disabled target-user policy. - Archive and unarchive operations are company-scoped, reversible, and activity logged with actor, agent, run, target user, target-resolution source, and policy mode.
- New qualifying issue activity may invalidate an archive so the item resurfaces; archival is not a substitute for resolving or closing work.
- Viewing an issue may update its per-user read receipt, but read receipts alone do not enroll the issue in Mine. Mine participation begins with a user-authored comment, issue creation/assignment, or another audited user mutation; explicit product actions such as manually running a routine may record an audited inbox touch.
Ownership split:
- Core / Free: permission key and scoped-grant enforcement; responsible-user resolution; default-open, disabled, and allowlist policy modes; archive/unarchive APIs; per-user archive persistence; resurfacing behavior; activity audit records; and stable denial codes.
- Paperclip EE / Enterprise: centralized policy administration beyond the per-user controls, organization-wide presets, policy simulation, bulk inbox operations, advanced compliance reporting, and richer administrative audit UX. EE may extend policy management surfaces but must not weaken core company boundaries, user policy restrictions, scoped grants, or audit requirements.
10. API Contract (REST)
All endpoints are under /api and return JSON.
10.1 Companies
GET /companiesPOST /companiesGET /companies/:companyIdPATCH /companies/:companyIdPATCH /companies/:companyId/brandingPOST /companies/:companyId/archive
On a Paperclip Cloud-managed instance, POST /companies returns 403 with
code cloud_managed; the trusted-header provisioning path and company import
routes remain the only company-creation paths there.
10.1.1 Cloud Stack Portfolio
GET /cloud/stacks
The route exists only on a Cloud-managed instance, requires a trusted
cloud_tenant actor, and proxies the current actor's user id plus the current
stack id to the Cloud tenant portfolio endpoint. Client-supplied user ids are
never forwarded. Successful responses are cached briefly per user; self-hosted
instances return 404.
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/:issueIdGET /issues/:issueId/documentsGET /issues/:issueId/documents/:keyPUT /issues/:issueId/documents/:keyPOST /issues/:issueId/documents/:key/lockPOST /issues/:issueId/documents/:key/unlockGET /issues/:issueId/documents/:key/revisionsDELETE /issues/:issueId/documents/:keyPOST /issues/:issueId/checkoutPOST /issues/:issueId/releasePOST /issues/:issueId/admin/force-release(board-only lock recovery)POST /issues/:issueId/commentsGET /issues/:issueId/commentsPOST /companies/:companyId/issues/:issueId/attachments(multipart upload)GET /issues/:issueId/attachmentsGET /attachments/:attachmentId/contentDELETE /attachments/:attachmentIdGET /issues/:issueId/runner-goal?agentId=...POST /issues/:issueId/runner-goal/actions
The runner-goal endpoints control an issue-scoped durable agent-session goal,
not a row in the company goals hierarchy. Reads return the effective agent,
negotiated capability, normalized goal snapshot, active-run state, pending
action, and revision. Mutations require a request id, assigned agent, expected
revision, and a negotiated action; they return 202, replay the original result
for a duplicate request id, and return 409 with the current projection for a
stale revision or an unconfirmed unfinished-goal replacement. These controls do
not create issue comments.
10.4.1 Atomic Checkout Contract
POST /issues/:issueId/checkout request:
{
"agentId": "uuid",
"expectedStatuses": ["todo", "backlog", "blocked", "in_review"]
}
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
POST /issues/:issueId/admin/force-release is an operator recovery endpoint for stale harness locks. It requires board access to the issue company, clears checkout and execution run lock fields, and may clear the agent assignee when clearAssignee=true is passed. The route must write an issue.admin_force_release activity log entry containing the previous checkout and execution run IDs.
10.5 Projects
GET /companies/:companyId/projectsPOST /companies/:companyId/projectsGET /projects/:projectIdPATCH /projects/:projectId
10.6 Current-user Resource Memberships
GET /companies/:companyId/resource-memberships/mePUT /companies/:companyId/resource-memberships/me/projects/:projectIdPUT /companies/:companyId/resource-memberships/me/agents/:agentId
Request payload:
{ "state": "joined" }
Allowed states are joined and left. Endpoints require a concrete board user and active company membership, reject agent API keys, and only mutate the caller's own sidebar visibility state. Joining/leaving is idempotent; missing rows read as joined.
10.7 Approvals
GET /companies/:companyId/approvals?status=pendingPOST /companies/:companyId/approvalsPOST /approvals/:approvalId/approvePOST /approvals/:approvalId/reject
10.8 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.9 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.10 Error Semantics
400validation error401unauthenticated403unauthorized404not found409state conflict (checkout conflict, invalid transition)422semantic rule violation500server error
10.11 Current Implementation API Addenda
The current app also exposes V1-supporting surfaces for:
- company-scoped summary slots for projects, the workspaces overview, project workspaces, and individual execution workspaces; execution-workspace slots are keyed by execution workspace id so a new workspace never inherits another workspace's summary
- issue thread interactions (
suggest_tasks,ask_user_questions,request_confirmation,request_checkbox_confirmation,request_item_verdicts) with the open-default resolver contract in §9.8.1 - issue approvals, issue references/search, labels, read state, inbox/archive state, and work products
- task search uses shared PostgreSQL matching/ranking for company search and task-list quick search;
all query terms contribute, quoted phrases stay literal, exact identifiers and direct title matches
lead relevance ordering, and the UI preserves server result order (see
doc/SEARCH.md) - company search through
GET /companies/:companyId/searchplus agent-oriented bulk extraction throughGET /companies/:companyId/search/extract; extraction accepts a server-escaped literalcontains, optional server-owned URL expansion, issue/comment/document scopes, status/date filters, issue-level pagination, a boundedmatchesPerIssueoverride for machine consumers, and explicit issue/match truncation flags - execution workspaces, project workspaces, workspace runtime services, and workspace operations. Workspace reads
derive
deliveryStateasmerged_via_pr | merged_by_ancestry | unmerged | unknown; terminal issue trees with a merged delivery and no active checkout run become cleanup-eligible with reasonissue_terminaland are archived through the workspace cleanup path. Reopening the source issue records activity but does not restore that workspace. - task watchdog configuration and reusable watchdog issue orchestration for explicitly watched issue subtrees
- routines and scheduled/API/webhook triggers
- plugin installation, configuration, state, jobs, logs, webhooks, and plugin database namespace migration
- company import/export preview/apply, feedback export/vote routes, instance backup/config routes, invites, join requests, memberships, and permission grants
- company skill policy read/replace/reset/simulation, enforced by the same core evaluator used by skill mutation routes
- decision queues and per-attention-item triage:
GET|POST /companies/:companyId/decision-queuesPATCH /companies/:companyId/decision-queues/:keyGET|POST /companies/:companyId/decision-queues/:key/itemsDELETE /companies/:companyId/decision-queues/:key/items/:sourceKind/:sourceIdGET /companies/:companyId/decision-queue-seed-rulesGET|PUT /companies/:companyId/decision-triage/:sourceKind/:sourceIdPATCH /companies/:companyId/decision-retention/:sourceKind/:sourceId(Keep)POST /companies/:companyId/decision-retention/:sourceKind/:sourceId/archive|revivePOST /companies/:companyId/decision-archive-proposals
Queue and triage mutations accept board non-viewers and active standard-scope agents, apply responsible-user intersection for run JWTs, and reject low-trust, task_bridge, and skill_test contexts. Missing, cross-company, and unauthorized attention sources share the same not-found response.
The attention feed returns server-computed shelf, retentionDays, keep, archivedAt, and retentionVersion fields. Archived rows are excluded by default and selected with archived=true. Bulk archive proposals bind the exact source identities, per-item reasons, activity timestamps, and expected retention versions into the signed decisions-v1 target snapshots; acceptance re-authorizes both proposer and decider and commits all rows or none.
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>;
}
Local adapter engine availability
For the legacy Codex, Claude, Gemini, and Kimi local adapters, an omitted engine
or legacy auto value selects ACP deterministically. Missing prerequisites or
ACP execution failures fail the run; they must not launch a different engine
with different session, permission, or sandbox semantics. CLI execution requires
explicit selection. Environment tests report the same engine availability error
as execution. Codex CLI defaults permit workspace writes and network access for
Paperclip coordination without disabling its sandbox; explicit operator
restrictions and execution-target network denials remain effective.
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 Recovery Work Classes
Status-only recovery coordination must include guard context that prevents deliverable work and document or plan updates (allowDeliverableWork: false, allowDocumentUpdates: false, resumeRequiresNormalModel: true). Recovery work classes do not select or change the agent model.
Failed source-work retries, process-loss retries, transient or scheduled retries, max-turn continuations, source-assignee continuations, and downstream source-work child, requeue, or resume contexts use the agent's configured model. If status-only recovery repairs liveness while actual work remains, the next live continuation path must be a separate worker run.
11.6 Scheduler Rules
Per-agent schedule fields in adapter_config:
enabledbooleanintervalSecinteger (minimum 30)maxConcurrentRunsinteger; new agents default to20; scheduler clamps configured values to1..50
Scheduler must skip invocation when:
- agent is paused/terminated
- an existing run is active
- hard budget limit has been hit
Legacy execution records a renewable controller lease when claiming a queued run, before provisioning. A live lease protects the run during overlapping service deployments. An expired controller loses dispatch authority; a recovery worker must establish that the previous execution stopped before starting a successor.
11.7 Durable agent session goals
Runner Protocol v2 negotiates a required sessionGoals capability and typed
session.goal.* commands and events. PRP v1 sessions remain supported and are
goal unsupported. The Codex app-server driver maps controls to
thread/goal/get, thread/goal/set, and thread/goal/clear; it observes
provider-created goal notifications and reconciles with an authoritative get
after each turn. An active goal suppresses premature run terminalization while
autonomous turns continue. The Paperclip runner's persistent ACP backend opts
in through the _session/goal extension and advertises its exact action subset.
Its pinned Codex/Claude executables retain the runner's Linux x64 qualification
requirement. Direct codex_local and claude_local adapters currently have no
live goal controller and remain unsupported, even when their underlying ACP
package exposes goals. Goal actions never change an agent's adapter, model,
permission policy, or rollout settings to manufacture support. CLI, one-shot
ACP, and providers without the structured extension remain unsupported.
When a goal heartbeat settles, the runner suspends its durable authority even under a warm lifecycle policy. Paused, blocked, completed, and rollover goals must survive controller restart without relying on an in-memory warm owner. The next run resumes the same provider session through the existing verified checkpoint and authority-rotation path.
The board composer treats /goal as an action command rather than Markdown or
comment text. It is capability-aware, and the issue thread renders durable goal
status and controls immediately above the composer. Goal completion enters the
normal run-result/completion arbitration path and does not directly close the
issue.
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
12.4 Connection Tool Reviews
Ask-first connection calls use a server-owned tool-action confirmation linked to the authoritative action request. The task feed retains a stable record; dismissal only hides the composer takeover. Task and Connections decisions share one transaction. Approval runs stored, signed arguments once; decline runs nothing. The human decision remains distinct from provider execution success or failure.
Always allow remembers the same agent, connection, and action, restricted to the current project when present, with future argument values permitted. Explicit denials, revoked access, catalog-definition changes, and formal approval gates remain effective. A durable continuation receipt resumes eligible task context with the recorded outcome after the agent yields. Uncertain interrupted execution is surfaced without automatic replay. See Task reviews for contracts, recovery behavior, Storybook, and acceptance workflows.
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 24.11+
DATABASE_URLoptional- if unset, auto-use embedded PostgreSQL under
~/.paperclip/instances/default/db
15.2 Migrations
- Drizzle migrations are source of truth
- local/dev startup applies pending migrations automatically where supported
pnpm db:migrateapplies pending migrations manually- no destructive migration in-place for V1 upgrade path
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
- restricted
skill_testandtask_bridgekeys cannot enumerate company-wide run telemetry, workspace-operation logs, or the company secret catalog - HTTP adapters use DNS-pinned outbound requests, reject redirects and link-local/metadata targets, and require an exact server-owner origin allowlist for private destinations
- external instruction bundle roots and exports that read them require instance-admin access; managed company-scoped bundles remain available through normal company authorization
- agent-authenticated callers cannot persist host-executed workspace commands, and restricted keys cannot invoke preconfigured workspace runtime controls
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
Current implementation note: the milestones below describe the original V1 sequencing. Several systems originally framed as future work have since shipped or advanced materially, including issue documents/interactions, blockers, routines, execution workspaces, import/export portability, authenticated deployment modes, multi-user basics, and the local/self-hosted plugin runtime.
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)
- cloud-grade plugin marketplace/distribution
- 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
- recurring
TASK.mdentries userecurring: truein the base package and Paperclip routine fidelity in.paperclip.yaml - Paperclip imports recurring task packages as routines instead of downgrading them to one-time issues
- export strips environment-specific paths (
cwd, local instruction file paths, inline prompt duplication) while preserving portable project repo/workspace metadata such asrepoUrl, refs, and workspace-policy references keyed in.paperclip.yaml - export never includes secret values; env inputs are reported as portable declarations instead
- export preserves explicit company skill policy and retained legacy skill grants in
.paperclip.yaml; absence of policy remains the open default - import supports target modes:
- create a new company
- import into an existing company
- import recreates exported project workspaces and remaps portable workspace keys back to target-local workspace ids
- import forces imported agent timer heartbeats off so packages never start scheduled runs implicitly
- import supports collision strategies:
rename,skip,replace - import supports preview (dry-run) before apply
- import preview reports skill-policy and legacy-grant mappings before apply and rejects unknown policy schema versions
- GitHub imports warn on unpinned refs instead of blocking
Experimental task-backed agent chat (2026-09-10)
enableAgentChat is an instance experimental flag, default false. Conversation containers remain issues, unique by (company_id, conversation_agent_id, conversation_user_id). The authenticated board actor supplies ownership; local trusted mode uses local-board. Ordinary company task access applies. A conversation's agent assignment and identity are immutable through ordinary updates; terminal status mutations are rejected.
GET /api/companies/:companyId/chats/:agentRef reads an existing conversation or null. POST atomically resolves its issue on first send/upload. Existing issue comment, attachment, document, interaction, and run APIs apply thereafter. User chat comments require an idempotent UUID clientRequestId. Conversation delivery preserves comment order through the existing issue execution queue; the durable comment outbox repairs the commit-to-enqueue crash window.
The server owns conversation state: waiting plus in_review denotes a healthy idle conversation, and active denotes an unanswered or executing turn. Successful replies settle a turn; they do not finish the issue. Idle containers are excluded from execution-work counts, ordinary task lists, timer work, and recovery invocations. Failed/unanswered turns retain normal handling. Child completion never wakes or completes the conversation. Search and direct task access preserve history.
Standalone /new is an ordered queue command with no model response. It advances a durable session generation and boundary comment, resets only this issue's provider context, and preserves the issue ID and history. Generation checks reject stale context writes and replies. Fresh replay excludes earlier messages and summaries. The shared transcript renders a session divider.
Chat prompts retain agent instructions and tools while directing clarification and task creation. Substantial execution belongs to linked, assigned ordinary issues. Ask mode remains non-mutating. Feature disablement prevents new turns and resets while retaining data and lifecycle protection; already-running turns may settle normally.
Agent chat project handoff (2026-09-11)
Chat supports research and full plan drafting/revision in its existing plan document. On handoff, each ordinary assigned task receives the relevant plan in its own plan document, committed with task creation before execution is scheduled. The source plan remains in the conversation. Plan acceptance hands off execution; it never switches the conversation into implementation.
Chat instructions require selecting a suitable project, reusing an existing one where appropriate. The project requirement is prompt-only; ordinary projectless tasks remain supported. New parent relationships beneath conversation tasks are rejected by task services, including direct API creation and reparenting. Existing children remain readable/editable and can be moved elsewhere. The Subtasks panel is unchanged.
The create_project runtime tool uses the normal project API with durable idempotency. list_projects and list_project_repositories support selection. Multiple repositoryIds select authorized catalog entries; multiple HTTPS GitHub repositoryUrls register existing repositories absent from the catalog. IDs and URLs may be combined, but cannot accompany an explicit workspace. URLs do not create repositories on GitHub or grant credentials. Execution uses normal repository access rules. Repository IDs are revalidated against the authenticated run's responsible user and connection grants. Agents should consider proper available repositories, clarify material ambiguity, and use repository-free projects when appropriate for non-code work.
Confirmed project creation appears as a durable card in the shared task transcript, including selected repository links. Tasks are linked inline. Failed creation never produces a success card. Tool evals cover planning/handoff, project/repository selection, retries, permission and mode denials, and ordinary delegation regressions using the production chat directive.
User continuation after execution recovery stops
An authenticated user message or an exact failed-run Retry can start a fresh
native or legacy conversation turn once the prior execution is confirmed stopped. Retain the source history and uncertain
action outcomes; do not replay tool calls or reset the failed incident's automatic
retry budget. Existing pause, approval, budget, ownership, and dependency gates
remain in effect. See doc/execution-semantics.md for admission and stop-proof
requirements.
Managed AI authentication
AI credentials can be adopted into the existing Connections system. A typed
runtimeConfig.aiConnection selects the responsible user’s personal default, an
explicit shared grant. The existing human-audience and agent-access permissions
apply; AI credentials have no separate agent-delegation exception. Selection preserves
harness/model routing and fails closed without ambient credential fallback.
Legacy agents retain their authentication until validated adoption. See
AI Connections for company isolation, compatible
methods, lifecycle, runtime enforcement, and migration details.
Experimental task-bound email
AgentMail channel connections extend the experimental conversation/task pipeline with explicit email publication. Each owned inbox/provider thread binds one task; external email senders do not gain board authority. Incoming correspondence uses the assigned agent's normal execution controls. Internal task activity never implicitly sends email. New outgoing conversations create child tasks and durable send intents before provider contact. The board directs email work through the normal task conversation; rich email cards show the correspondence and delivery outcomes without a separate email composer. See AgentMail connections for setup, transports, recovery, authorization, and the API/CLI contract.
Experimental iMessage Photon channel
A Photon Cloud project can represent one agent through the existing experimental channel subsystem. DMs and explicitly enabled groups create or continue task-bound conversations. Linked sender identity is the default; telephone numbers, email addresses, names, and group membership do not grant Paperclip authority. Photos/files and ordinary questions/confirmations use the existing attachment, interaction, continuation, and publication contracts. Pause and Disconnect govern runtime behavior independently of the UI gate. Local Mac access, unsolicited conversations, and SMS/RCS fallback are excluded. Live qualification is required before release readiness. Pro shared allocation supports DMs only, with sender enrollment in Photon and separate identity linking in Paperclip. Shared channels reserve one project, not a pool phone number; group admission and publication are disabled. Dedicated allocation retains one selected number and individually enabled groups.
iMessage task completion ends a turn, not its conversation. Subsequent messages
reopen the same task, including after restart; only explicit /new or /close
allows the next message to start another task. The open task receives committed
inbound comments live, with “Sent from iMessage” attribution on user bubbles.
See iMessage Photon for the implementation contract, setup, recovery, boundaries, and qualification status.
Native task completion
For ordinary low-risk tasks, accept the current agent's structured done claim
subject to explicit workflow constraints. Missing independent evidence or a
needs_review label alone must not create a human approval. Require a concrete
reviewer decision for a new review request. Keep unfinished work with the agent,
with bounded continuation and visible recovery. Preserve explicit approvals,
current task ownership, cancellation, dependencies, and newer task state. See
doc/architecture/native-status-arbitration.md for finish feedback and the
provenance-checked cleanup of historical automatic completion reviews.