(chore): cleanup

This commit is contained in:
Aron Prins committed 2026-04-17 20:17:49 +02:00
1 parent 5af237ac10
commit 5b2367875c
53 files changed
+21 -9314

No files matched your search

-46
View File
@@ -1,46 +0,0 @@
name: Support request
description: Ask for help using the docs, desktop flow, or documented setup.
title: "[Support]: "
labels: ["support"]
body:
- type: markdown
attributes:
value: |
This repository is community-maintained. Include enough detail to reproduce your setup and where the docs stopped helping.
- type: input
id: docs_page
attributes:
label: Docs page
description: Which page were you following?
placeholder: https://aronprins.github.io/paperclip-docs/#/installation
validations:
required: true
- type: dropdown
id: install_type
attributes:
label: Install path
options:
- Paperclip Desktop
- Terminal / local dev
- Docker
- Other
validations:
required: true
- type: input
id: upstream_ref
attributes:
label: Upstream version / branch / commit
placeholder: master, a tag, or a commit SHA
- type: textarea
id: problem
attributes:
label: What do you need help with?
description: Include the exact step where things diverged from the docs.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Error text or screenshots
render: shell
-43
View File
@@ -1,43 +0,0 @@
name: Bug report
description: Report a docs bug, site bug, or a product issue reproducible from the documented flow.
title: "[Bug]: "
labels: ["bug"]
body:
- type: input
id: docs_page
attributes:
label: Docs page
placeholder: https://aronprins.github.io/paperclip-docs/#/your-first-agent
- type: input
id: upstream_ref
attributes:
label: Upstream version / branch / commit
placeholder: master, a tag, or a commit SHA
validations:
required: true
- type: input
id: platform
attributes:
label: Platform
placeholder: macOS 15.4 / Windows 11 / Ubuntu 24.04
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to reproduce
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected result
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual result
validations:
required: true
@@ -1,32 +0,0 @@
name: Docs feedback
description: Suggest changes to content, structure, clarity, screenshots, or missing topics.
title: "[Docs]: "
labels: ["docs"]
body:
- type: input
id: docs_page
attributes:
label: Docs page
placeholder: https://aronprins.github.io/paperclip-docs/#/dashboard
validations:
required: true
- type: dropdown
id: feedback_type
attributes:
label: Feedback type
options:
- Incorrect content
- Missing detail
- Broken link or image
- Outdated docs
- Structure or navigation
- New guide request
validations:
required: true
- type: textarea
id: suggestion
attributes:
label: What should change?
validations:
required: true
-6
View File
@@ -1,6 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Upstream Paperclip Repository
url: https://github.com/paperclipai/paperclip
about: Check the upstream project for official code changes, issues, and pull requests.
-3
View File
@@ -1,6 +1,3 @@
.site/
.tmp/
references/upstream-paperclip/
node_modules/
.DS_Store
-244
View File
@@ -1,244 +0,0 @@
# Maintaining paperclip-docs
This repository is a community-maintained documentation and support layer for Paperclip. It is intentionally local-first:
- source content lives on `main`
- the published static site lives on `gh-pages`
- publishing happens from your machine with a local script
- upstream reference syncing happens from your machine with a local script
- GitHub Issues are used for support and docs feedback
This document is the maintainer playbook for keeping the repo current.
## Purpose
This repo exists to solve a specific problem:
- upstream Paperclip docs and support are not currently good enough for the user experience you want
- you want to maintain a better docs site independently
- you still need a local upstream checkout for comparison and fact-checking
- you do not want to depend on recurring GitHub Actions usage
This is not the official upstream repo. Keep that visible in the docs and in issue responses.
## Branch model
- `main`: source branch for markdown docs, screenshots, support forms, and local scripts
- `gh-pages`: built static site only
Rules:
- edit only on `main`
- never hand-edit `gh-pages`
- regenerate and publish `gh-pages` from `main` with `npm run docs:publish`
## Local workflow
From the repo root:
```sh
cd /Users/aronprins/Documents/Development/paperclip-docs
```
Sync the local upstream reference checkout:
```sh
npm run references:sync
```
Build the static site bundle:
```sh
npm run docs:build
```
Preview the built bundle locally:
```sh
npm run docs:serve
```
That serves the built site at:
```text
http://localhost:4321
```
Publish the current build to GitHub Pages:
```sh
npm run docs:publish
```
## Site URL model
The published site uses hash routing so GitHub Pages does not need rewrite rules.
Example:
```text
https://aronprins.github.io/paperclip-docs/#/installation
https://aronprins.github.io/paperclip-docs/#/api/issues
```
Deep links should always be shared in hash-route form.
## What lives where
- `docs/`: public docs source, screenshots, and site shell
- `docs/docs-website/`: custom docs app and release builder
- `docs/user-guides/screenshots/`: light and dark screenshot assets used by the public guides
- `references/upstream-paperclip/`: local upstream checkout for comparison
- `references/upstream.json`: records the current synced upstream commit
- `references/tools/`: copied maintenance helpers from the Paperclip repo
- `notes/`: planning notes and working documents for future docs work
More detail:
- content structure: [docs/README.md](docs/README.md)
- site shell details: [docs/docs-website/README.md](docs/docs-website/README.md)
- reference checkout details: [references/README.md](references/README.md)
- planning notes details: [notes/README.md](notes/README.md)
## Updating the docs
Typical maintenance loop:
1. Run `npm run references:sync`
2. Inspect upstream changes in `references/upstream-paperclip/`
3. Update the relevant markdown pages in `docs/`
4. Rebuild with `npm run docs:build`
5. Preview with `npm run docs:serve`
6. Commit changes on `main`
7. Publish with `npm run docs:publish`
Good sources for truth-checking:
- upstream implementation and source in `references/upstream-paperclip/`
- copied planning notes in `notes/`
- your own fork if you are documenting fork-specific behavior
If you are documenting your fork rather than upstream, say so explicitly in the relevant page.
## Updating screenshots
Screenshots are already checked in under:
- `docs/user-guides/screenshots/light/`
- `docs/user-guides/screenshots/dark/`
The public guide markdown uses `../images/...` paths, and the custom viewer remaps those at runtime to the themed screenshot folders.
Practical screenshot workflow:
1. sync upstream or your fork reference
2. run the product locally from the codebase you are documenting
3. seed or prepare the data needed for the target UI state
4. capture replacement screenshots into the existing light/dark folder structure
5. rebuild and preview the docs site
6. verify that the affected pages still render the screenshots correctly
Reference material for this work lives in:
- [notes/prompt-screenshots.md](notes/prompt-screenshots.md)
- [references/tools/seed-screenshots.ts](references/tools/seed-screenshots.ts)
Important:
- `seed-screenshots.ts` is a copied helper, not a guaranteed turnkey script for every future upstream version
- if upstream schema or UI changes, update your screenshot process accordingly
## Support triage
Support intake is handled through GitHub Issue Forms in `.github/ISSUE_TEMPLATE/`.
Current buckets:
- support request
- bug report
- docs feedback
Suggested handling:
- answer docs-only issues directly in this repo
- fix wording, broken links, and missing steps here
- forward upstream product bugs to `paperclipai/paperclip` when needed
- keep a visible distinction between upstream bugs and docs gaps
When replying, ask for:
- docs page URL
- upstream branch, tag, or commit
- platform
- install path used
- exact divergence from the documented flow
## GitHub Pages maintenance
This repo intentionally avoids depending on recurring Actions minutes.
The Pages model is:
- source branch: `gh-pages`
- publish method: local script
- build output: generated into a temporary directory, then pushed to `gh-pages`
The script used is:
- [scripts/publish-gh-pages.sh](scripts/publish-gh-pages.sh)
Do not edit `gh-pages` manually unless you are recovering from a publish failure.
## Reference sync maintenance
Use:
```sh
npm run references:sync
```
That script:
- clones upstream into `references/upstream-paperclip/` if missing
- fetches the configured branch if it already exists
- writes the synced commit SHA and timestamp to `references/upstream.json`
Defaults:
- upstream URL: `https://github.com/paperclipai/paperclip.git`
- upstream branch: `master`
Override them when needed:
```sh
UPSTREAM_URL=https://github.com/your-user/paperclip.git UPSTREAM_REF=feature/docs npm run references:sync
```
## Files you usually should not touch casually
- `docs/docs-website/index.html`
This is the custom site shell. Change it only when you need routing, rendering, layout, or runtime behavior changes.
- `docs/docs-website/build-release.mjs`
This is the release bundler. Change it only when the publish bundle contents or base-path behavior need to change.
- `gh-pages`
Generated output branch only.
## Known repo conventions
- this repo is local-first by design
- the published site is static
- the current production docs surface is the custom site under `docs/docs-website/`
- `docs/docs.json` is retained from the imported docs set, but the custom site is the active publishing path
## Recommended checklist before publishing
- upstream reference synced if this change depends on product behavior
- modified pages reviewed locally
- screenshots render in the right theme folders
- internal markdown links still work
- site builds cleanly with `npm run docs:build`
- changes committed to `main`
- published with `npm run docs:publish`
+20 -48
View File
@@ -1,68 +1,40 @@
# paperclip-docs
Community-maintained Paperclip docs and support site.
Lean source repo for the Paperclip documentation site.
This repository is not the upstream `paperclipai/paperclip` repository. It exists to host improved public-facing documentation, screenshots, and a lightweight support queue while keeping a live upstream checkout under `references/` for comparison.
## Commands
## Maintainer docs
- repo maintenance workflow: [MAINTAINING.md](MAINTAINING.md)
- docs tree overview: [docs/README.md](docs/README.md)
- custom site shell details: [docs/docs-website/README.md](docs/docs-website/README.md)
- reference checkout details: [references/README.md](references/README.md)
- planning notes overview: [notes/README.md](notes/README.md)
## Repo layout
- `docs/` source docs, screenshots, and the custom docs viewer
- `notes/` planning/reference docs copied from the original documentation work
- `references/upstream-paperclip/` local reference checkout of upstream Paperclip
- `references/tools/` helper files copied from the Paperclip repo for screenshot and docs maintenance
- `scripts/` local-first maintenance scripts
## Local workflow
Build the static site bundle locally:
Build the static site into `.site/`:
```sh
npm run docs:build
```
Preview the built bundle locally:
Preview the built site locally:
```sh
npm run docs:serve
```
Publish the built bundle to the `gh-pages` branch locally:
Publish the current site to `gh-pages`:
```sh
npm run docs:publish
```
Refresh the upstream reference checkout locally:
## Repo Layout
```sh
npm run references:sync
```
## GitHub Pages
This repo is set up for hash routing so GitHub Pages does not need rewrite rules. The intended published URL shape is:
```text
https://aronprins.github.io/paperclip-docs/#/installation
```
The local publish script writes the built site to the `gh-pages` branch and adds `.nojekyll` so GitHub Pages can serve the static bundle directly.
## Support
GitHub Issues in this repo are intended for:
- docs feedback
- install/setup help
- support questions
- bugs reproducible from the documented experience
Upstream product bugs may still need to be forwarded to `paperclipai/paperclip`.
- `docs/docs-website/`
Static site shell, navigation manifest, and release builder.
- `docs/user-guides/`
User-facing guide pages and screenshots.
- `docs/adapters/`
Adapter documentation.
- `docs/api/`
API reference pages.
- `docs/deploy/`
Deployment documentation.
- `docs/cli/`
CLI reference pages.
- `scripts/publish-gh-pages.sh`
Local publish script for GitHub Pages.
-77
View File
@@ -1,77 +0,0 @@
# Docs Structure
This file documents the public documentation tree in this repository.
## Main areas
- `start/`
High-level introductory material.
- `user-guides/guides/`
Task-oriented end-user documentation. This is the most important user-facing section for the custom docs site.
- `api/`
API reference pages.
- `adapters/`
Adapter reference and implementation notes intended for more technical users.
- `deploy/`
Deployment and runtime environment documentation.
- `cli/`
CLI command documentation.
- `docs-website/`
The custom static docs app used for publishing this repo to GitHub Pages.
- `user-guides/screenshots/`
Screenshot assets used by the user guide pages, split by theme.
## Public publishing model
The published site does not expose the entire `docs/` tree as-is. The release builder starts from the navigation manifest in `docs/docs-website/nav.json` and copies the reachable markdown files and screenshots into the final bundle.
That means:
- not every markdown file under `docs/` is guaranteed to be published
- navigation starts from `docs/docs-website/nav.json`
- internal markdown links can pull additional markdown files into the release bundle
## Editing content safely
When editing docs pages:
- prefer keeping file paths stable unless a rename is really necessary
- update `docs/docs-website/nav.json` if a published page is renamed or moved
- verify internal markdown links after edits
- rebuild locally after structural changes
## Screenshots
Guide pages use placeholder-style image paths such as:
```md
![Example](../images/dashboard/dashboard-overview.png)
```
The custom site rewrites those at runtime to:
- `docs/user-guides/screenshots/light/...`
- `docs/user-guides/screenshots/dark/...`
That means the markdown stays theme-agnostic while the site swaps assets based on the selected theme.
## Legacy and reference content
Some content in this imported tree is not part of the main public experience yet. Treat these as secondary unless you intentionally wire them into the public nav:
- plans
- some legacy guide paths
- imported docs format files such as `docs.json`
## Related docs
- maintainer workflow: [../MAINTAINING.md](../MAINTAINING.md)
- custom site shell: [docs-website/README.md](docs-website/README.md)
-186
View File
@@ -1,186 +0,0 @@
# Agent Runtime Guide
Status: User-facing guide
Last updated: 2026-03-26
Audience: Operators setting up and running agents in Paperclip
## 1. What this system does
Agents in Paperclip do not run continuously.
They run in **heartbeats**: short execution windows triggered by a wakeup.
Each heartbeat:
1. Starts the configured agent adapter (for example, Claude CLI or Codex CLI)
2. Gives it the current prompt/context
3. Lets it work until it exits, times out, or is cancelled
4. Stores results (status, token usage, errors, logs)
5. Updates the UI live
## 2. When an agent wakes up
An agent can be woken up in four ways:
- `timer`: scheduled interval (for example every 5 minutes)
- `assignment`: when work is assigned/checked out to that agent
- `on_demand`: manual wakeup (button/API)
- `automation`: system-triggered wakeup for future automations
If an agent is already running, new wakeups are merged (coalesced) instead of launching duplicate runs.
## 3. What to configure per agent
## 3.1 Adapter choice
Built-in adapters:
- `claude_local`: runs your local `claude` CLI
- `codex_local`: runs your local `codex` CLI
- `opencode_local`: runs your local `opencode` CLI
- `cursor`: runs Cursor in background mode
- `pi_local`: runs an embedded Pi agent locally
- `hermes_local`: runs your local `hermes` CLI (`hermes-paperclip-adapter`)
- `openclaw_gateway`: connects to an OpenClaw gateway endpoint
- `process`: generic shell command adapter
- `http`: calls an external HTTP endpoint
External plugin adapters (install via the adapter manager or API):
- `droid_local`: runs your local Factory Droid CLI (`@henkey/droid-paperclip-adapter`)
For local CLI adapters (`claude_local`, `codex_local`, `opencode_local`, `hermes_local`, `droid_local`), Paperclip assumes the CLI is already installed and authenticated on the host machine.
## 3.2 Runtime behavior
In agent runtime settings, configure heartbeat policy:
- `enabled`: allow scheduled heartbeats
- `intervalSec`: timer interval (0 = disabled)
- `wakeOnAssignment`: wake when assigned work
- `wakeOnOnDemand`: allow ping-style on-demand wakeups
- `wakeOnAutomation`: allow system automation wakeups
## 3.3 Working directory and execution limits
For local adapters, set:
- `cwd` (working directory)
- `timeoutSec` (max runtime per heartbeat)
- `graceSec` (time before force-kill after timeout/cancel)
- optional env vars and extra CLI args
- use **Test environment** in agent configuration to run adapter-specific diagnostics before saving
## 3.4 Prompt templates
You can set:
- `promptTemplate`: used for every run (first run and resumed sessions)
Templates support variables like `{{agent.id}}`, `{{agent.name}}`, and run context values.
> **Note:** `bootstrapPromptTemplate` is deprecated and should not be used for new agents. Existing configs that use it will continue to work but should be migrated to the managed instructions bundle system.
## 4. Session resume behavior
Paperclip stores session IDs for resumable adapters.
- Next heartbeat reuses the saved session automatically.
- This gives continuity across heartbeats.
- You can reset a session if context gets stale or confused.
Use session reset when:
- you significantly changed prompt strategy
- the agent is stuck in a bad loop
- you want a clean restart
## 5. Logs, status, and run history
For each heartbeat run you get:
- run status (`queued`, `running`, `succeeded`, `failed`, `timed_out`, `cancelled`)
- error text and stderr/stdout excerpts
- token usage/cost when available from the adapter
- full logs (stored outside core run rows, optimized for large output)
In local/dev setups, full logs are stored on disk under the configured run-log path.
## 6. Live updates in the UI
Paperclip pushes runtime/activity updates to the browser in real time.
You should see live changes for:
- agent status
- heartbeat run status
- task/activity updates caused by agent work
- dashboard/cost/activity panels as relevant
If the connection drops, the UI reconnects automatically.
## 7. Common operating patterns
## 7.1 Simple autonomous loop
1. Enable timer wakeups (for example every 300s)
2. Keep assignment wakeups on
3. Use a focused prompt template
4. Watch run logs and adjust prompt/config over time
## 7.2 Event-driven loop (less constant polling)
1. Disable timer or set a long interval
2. Keep wake-on-assignment enabled
3. Use on-demand wakeups for manual nudges
## 7.3 Safety-first loop
1. Short timeout
2. Conservative prompt
3. Monitor errors + cancel quickly when needed
4. Reset sessions when drift appears
## 8. Troubleshooting
If runs fail repeatedly:
1. Check adapter command availability (e.g. `claude`/`codex`/`opencode`/`hermes` installed and logged in).
2. Verify `cwd` exists and is accessible.
3. Inspect run error + stderr excerpt, then full log.
4. Confirm timeout is not too low.
5. Reset session and retry.
6. Pause agent if it is causing repeated bad updates.
Typical failure causes:
- CLI not installed/authenticated
- bad working directory
- malformed adapter args/env
- prompt too broad or missing constraints
- process timeout
Claude-specific note:
- If `ANTHROPIC_API_KEY` is set in adapter env or host environment, Claude uses API-key auth instead of subscription login. Paperclip surfaces this as a warning in environment tests, not a hard error.
## 9. Security and risk notes
Local CLI adapters run unsandboxed on the host machine.
That means:
- prompt instructions matter
- configured credentials/env vars are sensitive
- working directory permissions matter
Start with least privilege where possible, and avoid exposing secrets in broad reusable prompts unless intentionally required.
## 10. Minimal setup checklist
1. Choose adapter (e.g. `claude_local`, `codex_local`, `opencode_local`, `hermes_local`, `cursor`, or `openclaw_gateway`). External plugins like `droid_local` are also available via the adapter manager.
2. Set `cwd` to the target workspace (for local adapters).
3. Optionally add a prompt template (`promptTemplate`) or use the managed instructions bundle.
4. Configure heartbeat policy (timer and/or assignment wakeups).
5. Trigger a manual wakeup.
6. Confirm run succeeds and session/token usage is recorded.
7. Watch live updates and iterate prompt/config.
-596
View File
@@ -1,596 +0,0 @@
# Agent Companies Specification
Extension of the Agent Skills Specification
Version: `agentcompanies/v1-draft`
## 1. Purpose
An Agent Company package is a filesystem- and GitHub-native format for describing a company, team, agent, project, task, and associated skills using markdown files with YAML frontmatter.
This specification is an extension of the Agent Skills specification, not a replacement for it.
It defines how company-, team-, and agent-level package structure composes around the existing `SKILL.md` model.
This specification is vendor-neutral. It is intended to be usable by any agent-company runtime, not only Paperclip.
The format is designed to:
- be readable and writable by humans
- work directly from a local folder or GitHub repository
- require no central registry
- support attribution and pinned references to upstream files
- extend the existing Agent Skills ecosystem without redefining it
- be useful outside Paperclip
## 2. Core Principles
1. Markdown is canonical.
2. Git repositories are valid package containers.
3. Registries are optional discovery layers, not authorities.
4. `SKILL.md` remains owned by the Agent Skills specification.
5. External references must be pinnable to immutable Git commits.
6. Attribution and license metadata must survive import/export.
7. Slugs and relative paths are the portable identity layer, not database ids.
8. Conventional folder structure should work without verbose wiring.
9. Vendor-specific fidelity belongs in optional extensions, not the base package.
## 3. Package Kinds
A package root is identified by one primary markdown file:
- `COMPANY.md` for a company package
- `TEAM.md` for a team package
- `AGENTS.md` for an agent package
- `PROJECT.md` for a project package
- `TASK.md` for a task package
- `SKILL.md` for a skill package defined by the Agent Skills specification
A GitHub repo may contain one package at root or many packages in subdirectories.
## 4. Reserved Files And Directories
Common conventions:
```text
COMPANY.md
TEAM.md
AGENTS.md
PROJECT.md
TASK.md
SKILL.md
agents/<slug>/AGENTS.md
teams/<slug>/TEAM.md
projects/<slug>/PROJECT.md
projects/<slug>/tasks/<slug>/TASK.md
tasks/<slug>/TASK.md
skills/<slug>/SKILL.md
.paperclip.yaml
HEARTBEAT.md
SOUL.md
TOOLS.md
README.md
assets/
scripts/
references/
```
Rules:
- only markdown files are canonical content docs
- non-markdown directories like `assets/`, `scripts/`, and `references/` are allowed
- package tools may generate optional lock files, but lock files are not required for authoring
## 5. Common Frontmatter
Package docs may support these fields:
```yaml
schema: agentcompanies/v1
kind: company | team | agent | project | task
slug: my-slug
name: Human Readable Name
description: Short description
version: 0.1.0
license: MIT
authors:
- name: Jane Doe
homepage: https://example.com
tags:
- startup
- engineering
metadata: {}
sources: []
```
Notes:
- `schema` is optional and should usually appear only at the package root
- `kind` is optional when file path and file name already make the kind obvious
- `slug` should be URL-safe and stable
- `sources` is for provenance and external references
- `metadata` is for tool-specific extensions
- exporters should omit empty or default-valued fields
## 6. COMPANY.md
`COMPANY.md` is the root entrypoint for a whole company package.
### Required fields
```yaml
name: Lean Dev Shop
description: Small engineering-focused AI company
slug: lean-dev-shop
schema: agentcompanies/v1
```
### Recommended fields
```yaml
version: 1.0.0
license: MIT
authors:
- name: Example Org
goals:
- Build and ship software products
includes:
- https://github.com/example/shared-company-parts/blob/0123456789abcdef0123456789abcdef01234567/teams/engineering/TEAM.md
requirements:
secrets:
- OPENAI_API_KEY
```
### Semantics
- `includes` defines the package graph
- local package contents should be discovered implicitly by folder convention
- `includes` is optional and should be used mainly for external refs or nonstandard locations
- included items may be local or external references
- `COMPANY.md` may include agents directly, teams, projects, tasks, or skills
- a company importer may render `includes` as the tree/checkbox import UI
## 7. TEAM.md
`TEAM.md` defines an org subtree.
### Example
```yaml
name: Engineering
description: Product and platform engineering team
schema: agentcompanies/v1
slug: engineering
manager: ../cto/AGENTS.md
includes:
- ../platform-lead/AGENTS.md
- ../frontend-lead/AGENTS.md
- ../../skills/review/SKILL.md
tags:
- team
- engineering
```
### Semantics
- a team package is a reusable subtree, not necessarily a runtime database table
- `manager` identifies the root agent of the subtree
- `includes` may contain child agents, child teams, or shared skills
- a team package can be imported into an existing company and attached under a target manager
## 8. AGENTS.md
`AGENTS.md` defines an agent.
### Example
```yaml
name: CEO
title: Chief Executive Officer
reportsTo: null
skills:
- plan-ceo-review
- review
```
### Semantics
- body content is the canonical default instruction content for the agent
- `docs` points to sibling markdown docs when present
- `skills` references reusable `SKILL.md` packages by skill shortname or slug
- a bare skill entry like `review` should resolve to `skills/review/SKILL.md` by convention
- if a package references external skills, the agent should still refer to the skill by shortname; the skill package itself owns any source refs, pinning, or attribution details
- tools may allow path or URL entries as an escape hatch, but exporters should prefer shortname-based skill references in `AGENTS.md`
- vendor-specific adapter/runtime config should not live in the base package
- local absolute paths, machine-specific cwd values, and secret values must not be exported as canonical package data
### Skill Resolution
The preferred association standard between agents and skills is by skill shortname.
Suggested resolution order for an agent skill entry:
1. a local package skill at `skills/<shortname>/SKILL.md`
2. a referenced or included skill package whose declared slug or shortname matches
3. a tool-managed company skill library entry with the same shortname
Rules:
- exporters should emit shortnames in `AGENTS.md` whenever possible
- importers should not require full file paths for ordinary skill references
- the skill package itself should carry any complexity around external refs, vendoring, mirrors, or pinned upstream content
- this keeps `AGENTS.md` readable and consistent with `skills.sh`-style sharing
## 9. PROJECT.md
`PROJECT.md` defines a lightweight project package.
### Example
```yaml
name: Q2 Launch
description: Ship the Q2 launch plan and supporting assets
owner: cto
```
### Semantics
- a project package groups related starter tasks and supporting markdown
- `owner` should reference an agent slug when there is a clear project owner
- a conventional `tasks/` subfolder should be discovered implicitly
- `includes` may contain `TASK.md`, `SKILL.md`, or supporting docs when explicit wiring is needed
- project packages are intended to seed planned work, not represent runtime task state
## 10. TASK.md
`TASK.md` defines a lightweight starter task.
### Example
```yaml
name: Monday Review
assignee: ceo
project: q2-launch
recurring: true
```
### Semantics
- body content is the canonical markdown task description
- `assignee` should reference an agent slug inside the package
- `project` should reference a project slug when the task belongs to a `PROJECT.md`
- `recurring: true` marks the task as ongoing recurring work instead of a one-time starter task
- tasks are intentionally basic seed work: title, markdown body, assignee, project linkage, and optional `recurring: true`
- tools may also support optional fields like `priority`, `labels`, or `metadata`, but they should not require them in the base package
### Recurring Tasks
- the base package only needs to say whether a task is recurring
- vendors may attach the actual schedule / trigger / runtime fidelity in a vendor extension such as `.paperclip.yaml`
- this keeps `TASK.md` portable while still allowing richer runtime systems to round-trip their own automation details
- legacy packages may still use `schedule.recurrence` during transition, but exporters should prefer `recurring: true`
Example Paperclip extension:
```yaml
routines:
monday-review:
triggers:
- kind: schedule
cronExpression: "0 9 * * 1"
timezone: America/Chicago
```
- vendors should ignore unknown recurring-task extensions they do not understand
- vendors importing legacy `schedule.recurrence` data may translate it into their own runtime trigger model, but new exports should prefer the simpler `recurring: true` base field
## 11. SKILL.md Compatibility
A skill package must remain a valid Agent Skills package.
Rules:
- `SKILL.md` should follow the Agent Skills spec
- Paperclip must not require extra top-level fields for skill validity
- Paperclip-specific extensions must live under `metadata.paperclip` or `metadata.sources`
- a skill directory may include `scripts/`, `references/`, and `assets/` exactly as the Agent Skills ecosystem expects
- tools implementing this spec should treat `skills.sh` compatibility as a first-class goal rather than inventing a parallel skill format
In other words, this spec extends Agent Skills upward into company/team/agent composition. It does not redefine skill package semantics.
### Example compatible extension
```yaml
---
name: review
description: Paranoid code review skill
allowed-tools:
- Read
- Grep
metadata:
paperclip:
tags:
- engineering
- review
sources:
- kind: github-file
repo: vercel-labs/skills
path: review/SKILL.md
commit: 0123456789abcdef0123456789abcdef01234567
sha256: 3b7e...9a
attribution: Vercel Labs
usage: referenced
---
```
## 12. Source References
A package may point to upstream content instead of vendoring it.
### Source object
```yaml
sources:
- kind: github-file
repo: owner/repo
path: path/to/file.md
commit: 0123456789abcdef0123456789abcdef01234567
blob: abcdef0123456789abcdef0123456789abcdef01
sha256: 3b7e...9a
url: https://github.com/owner/repo/blob/0123456789abcdef0123456789abcdef01234567/path/to/file.md
rawUrl: https://raw.githubusercontent.com/owner/repo/0123456789abcdef0123456789abcdef01234567/path/to/file.md
attribution: Owner Name
license: MIT
usage: referenced
```
### Supported kinds
- `local-file`
- `local-dir`
- `github-file`
- `github-dir`
- `url`
### Usage modes
- `vendored`: bytes are included in the package
- `referenced`: package points to upstream immutable content
- `mirrored`: bytes are cached locally but upstream attribution remains canonical
### Rules
- `commit` is required for `github-file` and `github-dir` in strict mode
- `sha256` is strongly recommended and should be verified on fetch
- branch-only refs may be allowed in development mode but must warn
- exporters should default to `referenced` for third-party content unless redistribution is clearly allowed
## 13. Resolution Rules
Given a package root, an importer resolves in this order:
1. local relative paths
2. local absolute paths if explicitly allowed by the importing tool
3. pinned GitHub refs
4. generic URLs
For pinned GitHub refs:
1. resolve `repo + commit + path`
2. fetch content
3. verify `sha256` if present
4. verify `blob` if present
5. fail closed on mismatch
An importer must surface:
- missing files
- hash mismatches
- missing licenses
- referenced upstream content that requires network fetch
- executable content in skills or scripts
## 14. Import Graph
A package importer should build a graph from:
- `COMPANY.md`
- `TEAM.md`
- `AGENTS.md`
- `PROJECT.md`
- `TASK.md`
- `SKILL.md`
- local and external refs
Suggested import UI behavior:
- render graph as a tree
- checkbox at entity level, not raw file level
- selecting an agent auto-selects required docs and referenced skills
- selecting a team auto-selects its subtree
- selecting a project auto-selects its included tasks
- selecting a recurring task should make it clear that the import target is a routine / automation, not a one-time task
- selecting referenced third-party content shows attribution, license, and fetch policy
## 15. Vendor Extensions
Vendor-specific data should live outside the base package shape.
For Paperclip, the preferred fidelity extension is:
```text
.paperclip.yaml
```
Example uses:
- adapter type and adapter config
- adapter env inputs and defaults
- runtime settings
- permissions
- budgets
- approval policies
- project execution workspace policies
- issue/task Paperclip-only metadata
Rules:
- the base package must remain readable without the extension
- tools that do not understand a vendor extension should ignore it
- Paperclip tools may emit the vendor extension by default as a sidecar while keeping the base markdown clean
Suggested Paperclip shape:
```yaml
schema: paperclip/v1
agents:
claudecoder:
adapter:
type: claude_local
config:
model: claude-opus-4-6
inputs:
env:
ANTHROPIC_API_KEY:
kind: secret
requirement: optional
default: ""
GH_TOKEN:
kind: secret
requirement: optional
CLAUDE_BIN:
kind: plain
requirement: optional
default: claude
routines:
monday-review:
triggers:
- kind: schedule
cronExpression: "0 9 * * 1"
timezone: America/Chicago
```
Additional rules for Paperclip exporters:
- do not duplicate `promptTemplate` when `AGENTS.md` already contains the agent instructions
- do not export provider-specific secret bindings such as `secretId`, `version`, or `type: secret_ref`
- export env inputs as portable declarations with `required` or `optional` semantics and optional defaults
- warn on system-dependent values such as absolute commands and absolute `PATH` overrides
- omit empty and default-valued Paperclip fields when possible
## 16. Export Rules
A compliant exporter should:
- emit markdown roots and relative folder layout
- omit machine-local ids and timestamps
- omit secret values
- omit machine-specific paths
- preserve task descriptions and recurring-task declarations when exporting tasks
- omit empty/default fields
- default to the vendor-neutral base package
- Paperclip exporters should emit `.paperclip.yaml` as a sidecar by default
- preserve attribution and source references
- prefer `referenced` over silent vendoring for third-party content
- preserve `SKILL.md` as-is when exporting compatible skills
## 17. Licensing And Attribution
A compliant tool must:
- preserve `license` and `attribution` metadata when importing and exporting
- distinguish vendored vs referenced content
- not silently inline referenced third-party content during export
- surface missing license metadata as a warning
- surface restrictive or unknown licenses before install/import if content is vendored or mirrored
## 18. Optional Lock File
Authoring does not require a lock file.
Tools may generate an optional lock file such as:
```text
company-package.lock.json
```
Purpose:
- cache resolved refs
- record final hashes
- support reproducible installs
Rules:
- lock files are optional
- lock files are generated artifacts, not canonical authoring input
- the markdown package remains the source of truth
## 19. Paperclip Mapping
Paperclip can map this spec to its runtime model like this:
- base package:
- `COMPANY.md` -> company metadata
- `TEAM.md` -> importable org subtree
- `AGENTS.md` -> agent identity and instructions
- `PROJECT.md` -> starter project definition
- `TASK.md` -> starter issue/task definition, or recurring task template when `recurring: true`
- `SKILL.md` -> imported skill package
- `sources[]` -> provenance and pinned upstream refs
- Paperclip extension:
- `.paperclip.yaml` -> adapter config, runtime config, env input declarations, permissions, budgets, routine triggers, and other Paperclip-specific fidelity
Inline Paperclip-only metadata that must live inside a shared markdown file should use:
- `metadata.paperclip`
That keeps the base format broader than Paperclip.
This specification itself remains vendor-neutral and intended for any agent-company runtime, not only Paperclip.
## 20. Cutover
Paperclip should cut over to this markdown-first package model as the primary portability format.
`paperclip.manifest.json` does not need to be preserved as a compatibility requirement for the future package system.
For Paperclip, this should be treated as a hard cutover in product direction rather than a long-lived dual-format strategy.
## 21. Minimal Example
```text
lean-dev-shop/
├── COMPANY.md
├── agents/
│ ├── ceo/AGENTS.md
│ └── cto/AGENTS.md
├── projects/
│ └── q2-launch/
│ ├── PROJECT.md
│ └── tasks/
│ └── monday-review/
│ └── TASK.md
├── teams/
│ └── engineering/TEAM.md
├── tasks/
│ └── weekly-review/TASK.md
└── skills/
└── review/SKILL.md
Optional:
```text
.paperclip.yaml
```
```
**Recommendation**
This is the direction I would take:
- make this the human-facing spec
- define `SKILL.md` compatibility as non-negotiable
- treat this spec as an extension of Agent Skills, not a parallel format
- make `companies.sh` a discovery layer for repos implementing this spec, not a publishing authority
-1
View File
@@ -1 +0,0 @@
release/
-8
View File
@@ -1,8 +0,0 @@
RewriteEngine On
RewriteBase /docs-website/
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^ index.html [L]
-109
View File
@@ -1,109 +0,0 @@
# Docs Website
`docs/docs-website/` contains the custom static docs application used to publish this repository on GitHub Pages.
## Files
- `index.html`
Single-file docs app shell. It handles routing, markdown loading, search, theme switching, image remapping, table of contents behavior, and navigation.
- `nav.json`
Navigation manifest that defines the published reading structure.
- `build-release.mjs`
Release builder that creates the publishable static bundle.
## Routing
The site uses hash routing for GitHub Pages compatibility.
Examples:
- `/#/installation`
- `/#/api/issues`
This avoids needing server rewrites for deep links.
## How the site loads content
At runtime the app:
1. loads `nav.json`
2. determines the current route
3. maps the route to a markdown file
4. fetches that markdown file from the published bundle
5. renders the page client-side
The site also:
- rewrites screenshot references from `../images/...` to themed screenshot folders
- turns callout-style blockquotes into styled callout blocks
- turns tab comment syntax into interactive tab UIs
- builds a local search index in the browser
## Build process
The release builder:
1. reads `nav.json`
2. collects the referenced markdown files
3. follows linked local markdown references
4. rewrites the nav file for the release bundle
5. copies markdown files and screenshots into the output directory
6. writes `index.html`, `nav.json`, `.htaccess`, `nginx.conf.example`, and `DEPLOY.md`
Typical build command:
```sh
npm run docs:build
```
## When to edit `index.html`
Edit `index.html` only when you need to change site behavior such as:
- routing
- navigation
- theme behavior
- markdown rendering behavior
- screenshot remapping behavior
- search or TOC behavior
Do not edit it for normal content updates.
## When to edit `nav.json`
Edit `nav.json` when:
- you add a new published page
- you remove a published page
- you change the order of the public docs
- you reorganize the main reading paths
## When to edit `build-release.mjs`
Edit the release builder only when:
- the output bundle contents need to change
- base-path handling changes
- publishing rules change
- the set of copied assets changes
## Local verification
After changing the site shell or nav:
```sh
npm run docs:build
npm run docs:serve
```
Then verify:
- the homepage loads
- navigation works
- hash-route deep links work
- screenshots render
- search still finds pages
- internal markdown links still resolve
-147
View File
@@ -1,147 +0,0 @@
{
"$schema": "https://mintlify.com/docs.json",
"name": "Paperclip",
"description": "The control plane for autonomous AI companies",
"theme": "mint",
"colors": {
"primary": "#2563EB",
"light": "#3B82F6",
"dark": "#1D4ED8"
},
"favicon": "/favicon.svg",
"logo": {
"dark": "/images/logo-dark.svg",
"light": "/images/logo-light.svg"
},
"topbarLinks": [
{
"name": "GitHub",
"url": "https://github.com/paperclip-ai/paperclip"
}
],
"navigation": {
"tabs": [
{
"tab": "Get Started",
"groups": [
{
"group": "Introduction",
"pages": [
"start/what-is-paperclip",
"start/quickstart",
"start/core-concepts",
"start/architecture"
]
}
]
},
{
"tab": "Guides",
"groups": [
{
"group": "Board Operator",
"pages": [
"guides/board-operator/dashboard",
"guides/board-operator/creating-a-company",
"guides/board-operator/managing-agents",
"guides/board-operator/org-structure",
"guides/board-operator/managing-tasks",
"guides/board-operator/execution-workspaces-and-runtime-services",
"guides/board-operator/delegation",
"guides/board-operator/approvals",
"guides/board-operator/costs-and-budgets",
"guides/board-operator/activity-log",
"guides/board-operator/importing-and-exporting"
]
},
{
"group": "Agent Developer",
"pages": [
"guides/agent-developer/how-agents-work",
"guides/agent-developer/heartbeat-protocol",
"guides/agent-developer/writing-a-skill",
"guides/agent-developer/task-workflow",
"guides/agent-developer/comments-and-communication",
"guides/agent-developer/handling-approvals",
"guides/agent-developer/cost-reporting"
]
}
]
},
{
"tab": "Deploy",
"groups": [
{
"group": "Deployment",
"pages": [
"deploy/overview",
"deploy/local-development",
"deploy/tailscale-private-access",
"deploy/docker",
"deploy/deployment-modes",
"deploy/database",
"deploy/secrets",
"deploy/storage",
"deploy/environment-variables"
]
}
]
},
{
"tab": "Adapters",
"groups": [
{
"group": "Agent Adapters",
"pages": [
"adapters/overview",
"adapters/claude-local",
"adapters/codex-local",
"adapters/process",
"adapters/http",
"adapters/external-adapters",
"adapters/adapter-ui-parser",
"adapters/creating-an-adapter"
]
}
]
},
{
"tab": "API Reference",
"groups": [
{
"group": "REST API",
"pages": [
"api/overview",
"api/authentication",
"api/companies",
"api/agents",
"api/issues",
"api/approvals",
"api/goals-and-projects",
"api/costs",
"api/secrets",
"api/activity",
"api/dashboard"
]
}
]
},
{
"tab": "CLI",
"groups": [
{
"group": "CLI Reference",
"pages": [
"cli/overview",
"cli/setup-commands",
"cli/control-plane-commands"
]
}
]
}
]
},
"footerSocials": {
"github": "https://github.com/paperclip-ai/paperclip"
}
}
-4
View File
@@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -4 32 32" fill="none" stroke-linecap="round" stroke-linejoin="round">
<rect x="-4" y="-4" width="32" height="32" rx="6" fill="#2563EB"/>
<path stroke="#ffffff" stroke-width="2" d="m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551"/>
</svg>

Before

Width:  |  Height:  |  Size: 367 B

-193
View File
@@ -1,193 +0,0 @@
# Feedback Voting — Local Data Guide
When you rate an agent's response with **Helpful** (thumbs up) or **Needs work** (thumbs down), Paperclip saves your vote locally alongside your running instance. This guide covers what gets stored, how to access it, and how to export it.
## How voting works
1. Click **Helpful** or **Needs work** on any agent comment or document revision.
2. If you click **Needs work**, an optional text prompt appears: _"What could have been better?"_ You can type a reason or dismiss it.
3. A consent dialog asks whether to keep the vote local or share it. Your choice is remembered for future votes.
### What gets stored
Each vote creates two local records:
| Record | What it contains |
|--------|-----------------|
| **Vote** | Your vote (up/down), optional reason text, sharing preference, consent version, timestamp |
| **Trace bundle** | Full context snapshot: the voted-on comment/revision text, issue title, agent info, your vote, and reason — everything needed to understand the feedback in isolation |
All data lives in your local Paperclip database. Nothing leaves your machine unless you explicitly choose to share.
When a vote is marked for sharing, Paperclip immediately tries to upload the trace bundle through the Telemetry Backend. The upload is compressed in transit so full trace bundles stay under gateway size limits. If that immediate push fails, the trace is left in a retriable failed state for later flush attempts. The app server never uploads raw feedback trace bundles directly to object storage.
## Viewing your votes
### Quick report (terminal)
```bash
pnpm paperclipai feedback report
```
Shows a color-coded summary: vote counts, per-trace details with reasons, and export statuses.
```bash
# Installed CLI
paperclipai feedback report
# Point to a different server or company
pnpm paperclipai feedback report --api-base http://127.0.0.1:3000 --company-id <company-id>
# Include raw payload dumps in the report
pnpm paperclipai feedback report --payloads
```
### API endpoints
All endpoints require board-user access (automatic in local dev).
**List votes for an issue:**
```bash
curl http://127.0.0.1:3102/api/issues/<issueId>/feedback-votes
```
**List trace bundles for an issue (with full payloads):**
```bash
curl 'http://127.0.0.1:3102/api/issues/<issueId>/feedback-traces?includePayload=true'
```
**List all traces company-wide:**
```bash
curl 'http://127.0.0.1:3102/api/companies/<companyId>/feedback-traces?includePayload=true'
```
**Get a single trace envelope record:**
```bash
curl http://127.0.0.1:3102/api/feedback-traces/<traceId>
```
**Get the full export bundle for a trace:**
```bash
curl http://127.0.0.1:3102/api/feedback-traces/<traceId>/bundle
```
#### Filtering
The trace endpoints accept query parameters:
| Parameter | Values | Description |
|-----------|--------|-------------|
| `vote` | `up`, `down` | Filter by vote direction |
| `status` | `local_only`, `pending`, `sent`, `failed` | Filter by export status |
| `targetType` | `issue_comment`, `issue_document_revision` | Filter by what was voted on |
| `sharedOnly` | `true` | Only show votes the user chose to share |
| `includePayload` | `true` | Include the full context snapshot |
| `from` / `to` | ISO date | Date range filter |
## Exporting your data
### Export to files + zip
```bash
pnpm paperclipai feedback export
```
Creates a timestamped directory with:
```
feedback-export-20260331T120000Z/
index.json # manifest with summary stats
votes/
PAP-123-a1b2c3d4.json # vote metadata (one per vote)
traces/
PAP-123-e5f6g7h8.json # Paperclip feedback envelope (one per trace)
full-traces/
PAP-123-e5f6g7h8/
bundle.json # full export manifest for the trace
...raw adapter files # codex / claude / opencode session artifacts when available
feedback-export-20260331T120000Z.zip
```
Exports are full by default. `traces/` keeps the Paperclip envelope, while `full-traces/` contains the richer per-trace bundle plus any recoverable adapter-native files.
```bash
# Custom server and output directory
pnpm paperclipai feedback export --api-base http://127.0.0.1:3000 --company-id <company-id> --out ./my-export
```
### Reading an exported trace
Open any file in `traces/` to see:
```json
{
"id": "trace-uuid",
"vote": "down",
"issueIdentifier": "PAP-123",
"issueTitle": "Fix login timeout",
"targetType": "issue_comment",
"targetSummary": {
"label": "Comment",
"excerpt": "The first 80 chars of the comment that was voted on..."
},
"payloadSnapshot": {
"vote": {
"value": "down",
"reason": "Did not address the root cause"
},
"target": {
"body": "Full text of the agent comment..."
},
"issue": {
"identifier": "PAP-123",
"title": "Fix login timeout"
}
}
}
```
Open `full-traces/<issue>-<trace>/bundle.json` to see the expanded export metadata, including capture notes, adapter type, integrity metadata, and the inventory of raw files written alongside it.
Each entry in `bundle.json.files[]` includes the actual captured file payload under `contents`, not just a pathname. For text artifacts this is stored as UTF-8 text; binary artifacts use base64 plus an `encoding` marker.
Built-in local adapters now export their native session artifacts more directly:
- `codex_local`: `adapter/codex/session.jsonl`
- `claude_local`: `adapter/claude/session.jsonl`, plus any `adapter/claude/session/...` sidecar files and `adapter/claude/debug.txt` when present
- `opencode_local`: `adapter/opencode/session.json`, `adapter/opencode/messages/*.json`, and `adapter/opencode/parts/<messageId>/*.json`, with optional `project.json`, `todo.json`, and `session-diff.json`
## Sharing preferences
The first time you vote, a consent dialog asks:
- **Keep local** — vote is stored locally only (`sharedWithLabs: false`)
- **Share this vote** — vote is marked for sharing (`sharedWithLabs: true`)
Your preference is saved per-company. You can change it any time via the feedback settings. Votes marked "keep local" are never queued for export.
## Data lifecycle
| Status | Meaning |
|--------|---------|
| `local_only` | Vote stored locally, not marked for sharing |
| `pending` | Marked for sharing, saved locally, and waiting for the immediate upload attempt |
| `sent` | Successfully transmitted |
| `failed` | Transmission attempted but failed (for example the backend is unreachable or not configured); later flushes retry once a backend is available |
Your local database always retains the full vote and trace data regardless of sharing status.
## Remote sync
Votes you choose to share are sent to the Telemetry Backend immediately from the vote request. The server also keeps a background flush worker so failed traces can retry later. The Telemetry Backend validates the request, then persists the bundle into its configured object storage.
- App server responsibility: build the bundle, POST it to Telemetry Backend, update trace status
- Telemetry Backend responsibility: authenticate the request, validate payload shape, compress/store the bundle, return the final object key
- Retry behavior: failed uploads move to `failed` with an error message in `failureReason`, and the worker retries them on later ticks
- Default endpoint: when no feedback export backend URL is configured, Paperclip falls back to `https://telemetry.paperclip.ing`
- Important nuance: the uploaded object is a snapshot of the full bundle at vote time. If you fetch a local bundle later and the underlying adapter session file has continued to grow, the local regenerated bundle may be larger than the already-uploaded snapshot for that same trace.
Exported objects use a deterministic key pattern so they are easy to inspect:
```text
feedback-traces/<companyId>/YYYY/MM/DD/<exportId-or-traceId>.json
```
@@ -1,57 +0,0 @@
---
title: Comments and Communication
summary: How agents communicate via issues
---
Comments on issues are the primary communication channel between agents. Every status update, question, finding, and handoff happens through comments.
## Posting Comments
```
POST /api/issues/{issueId}/comments
{ "body": "## Update\n\nCompleted JWT signing.\n\n- Added RS256 support\n- Tests passing\n- Still need refresh token logic" }
```
You can also add a comment when updating an issue:
```
PATCH /api/issues/{issueId}
{ "status": "done", "comment": "Implemented login endpoint with JWT auth." }
```
## Comment Style
Use concise markdown with:
- A short status line
- Bullets for what changed or what is blocked
- Links to related entities when available
```markdown
## Update
Submitted CTO hire request and linked it for board review.
- Approval: [ca6ba09d](/approvals/ca6ba09d-b558-4a53-a552-e7ef87e54a1b)
- Pending agent: [CTO draft](/agents/66b3c071-6cb8-4424-b833-9d9b6318de0b)
- Source issue: [PC-142](/issues/244c0c2c-8416-43b6-84c9-ec183c074cc1)
```
## @-Mentions
Mention another agent by name using `@AgentName` in a comment to wake them:
```
POST /api/issues/{issueId}/comments
{ "body": "@EngineeringLead I need a review on this implementation." }
```
The name must match the agent's `name` field exactly (case-insensitive). This triggers a heartbeat for the mentioned agent.
@-mentions also work inside the `comment` field of `PATCH /api/issues/{issueId}`.
## @-Mention Rules
- **Don't overuse mentions** — each mention triggers a budget-consuming heartbeat
- **Don't use mentions for assignment** — create/assign a task instead
- **Mention handoff exception** — if an agent is explicitly @-mentioned with a clear directive to take a task, they may self-assign via checkout
@@ -1,52 +0,0 @@
---
title: Cost Reporting
summary: How agents report token costs
---
Agents report their token usage and costs back to Paperclip so the system can track spending and enforce budgets.
## How It Works
Cost reporting happens automatically through adapters. When an agent heartbeat completes, the adapter parses the agent's output to extract:
- **Provider** — which LLM provider was used (e.g. "anthropic", "openai")
- **Model** — which model was used (e.g. "claude-sonnet-4-20250514")
- **Input tokens** — tokens sent to the model
- **Output tokens** — tokens generated by the model
- **Cost** — dollar cost of the invocation (if available from the runtime)
The server records this as a cost event for budget tracking.
## Cost Events API
Cost events can also be reported directly:
```
POST /api/companies/{companyId}/cost-events
{
"agentId": "{agentId}",
"provider": "anthropic",
"model": "claude-sonnet-4-20250514",
"inputTokens": 15000,
"outputTokens": 3000,
"costCents": 12
}
```
## Budget Awareness
Agents should check their budget at the start of each heartbeat:
```
GET /api/agents/me
# Check: spentMonthlyCents vs budgetMonthlyCents
```
If budget utilization is above 80%, focus on critical tasks only. At 100%, the agent is auto-paused.
## Best Practices
- Let the adapter handle cost reporting — don't duplicate it
- Check budget early in the heartbeat to avoid wasted work
- Above 80% utilization, skip low-priority tasks
- If you're running out of budget mid-task, leave a comment and exit gracefully
@@ -1,65 +0,0 @@
---
title: Handling Approvals
summary: Agent-side approval request and response
---
Agents interact with the approval system in two ways: requesting approvals and responding to approval resolutions.
## Requesting a Hire
Managers and CEOs can request to hire new agents:
```
POST /api/companies/{companyId}/agent-hires
{
"name": "Marketing Analyst",
"role": "researcher",
"reportsTo": "{yourAgentId}",
"capabilities": "Market research, competitor analysis",
"budgetMonthlyCents": 5000
}
```
If company policy requires approval, the new agent is created as `pending_approval` and a `hire_agent` approval is created automatically.
Only managers and CEOs should request hires. IC agents should ask their manager.
## CEO Strategy Approval
If you are the CEO, your first strategic plan requires board approval:
```
POST /api/companies/{companyId}/approvals
{
"type": "approve_ceo_strategy",
"requestedByAgentId": "{yourAgentId}",
"payload": { "plan": "Strategic breakdown..." }
}
```
## Responding to Approval Resolutions
When an approval you requested is resolved, you may be woken with:
- `PAPERCLIP_APPROVAL_ID` — the resolved approval
- `PAPERCLIP_APPROVAL_STATUS` — `approved` or `rejected`
- `PAPERCLIP_LINKED_ISSUE_IDS` — comma-separated list of linked issue IDs
Handle it at the start of your heartbeat:
```
GET /api/approvals/{approvalId}
GET /api/approvals/{approvalId}/issues
```
For each linked issue:
- Close it if the approval fully resolves the requested work
- Comment on it explaining what happens next if it remains open
## Checking Approval Status
Poll pending approvals for your company:
```
GET /api/companies/{companyId}/approvals?status=pending
```
@@ -1,107 +0,0 @@
---
title: Heartbeat Protocol
summary: Step-by-step heartbeat procedure for agents
---
Every agent follows the same heartbeat procedure on each wake. This is the core contract between agents and Paperclip.
## The Steps
### Step 1: Identity
Get your agent record:
```
GET /api/agents/me
```
This returns your ID, company, role, chain of command, and budget.
### Step 2: Approval Follow-up
If `PAPERCLIP_APPROVAL_ID` is set, handle the approval first:
```
GET /api/approvals/{approvalId}
GET /api/approvals/{approvalId}/issues
```
Close linked issues if the approval resolves them, or comment on why they remain open.
### Step 3: Get Assignments
```
GET /api/companies/{companyId}/issues?assigneeAgentId={yourId}&status=todo,in_progress,in_review,blocked
```
Results are sorted by priority. This is your inbox.
### Step 4: Pick Work
- Work on `in_progress` tasks first, then `in_review` when you were woken by a comment on it, then `todo`
- Skip `blocked` unless you can unblock it
- If `PAPERCLIP_TASK_ID` is set and assigned to you, prioritize it
- If woken by a comment mention, read that comment thread first
### Step 5: Checkout
Before doing any work, you must checkout the task:
```
POST /api/issues/{issueId}/checkout
Headers: X-Paperclip-Run-Id: {runId}
{ "agentId": "{yourId}", "expectedStatuses": ["todo", "backlog", "blocked", "in_review"] }
```
If already checked out by you, this succeeds. If another agent owns it: `409 Conflict` — stop and pick a different task. **Never retry a 409.**
### Step 6: Understand Context
```
GET /api/issues/{issueId}
GET /api/issues/{issueId}/comments
```
Read ancestors to understand why this task exists. If woken by a specific comment, find it and treat it as the immediate trigger.
### Step 7: Do the Work
Use your tools and capabilities to complete the task.
### Step 8: Update Status
Always include the run ID header on state changes:
```
PATCH /api/issues/{issueId}
Headers: X-Paperclip-Run-Id: {runId}
{ "status": "done", "comment": "What was done and why." }
```
If blocked:
```
PATCH /api/issues/{issueId}
Headers: X-Paperclip-Run-Id: {runId}
{ "status": "blocked", "comment": "What is blocked, why, and who needs to unblock it." }
```
### Step 9: Delegate if Needed
Create subtasks for your reports:
```
POST /api/companies/{companyId}/issues
{ "title": "...", "assigneeAgentId": "...", "parentId": "...", "goalId": "..." }
```
Always set `parentId` and `goalId` on subtasks.
## Critical Rules
- **Always checkout** before working — never PATCH to `in_progress` manually
- **Never retry a 409** — the task belongs to someone else
- **Always comment** on in-progress work before exiting a heartbeat
- **Always set parentId** on subtasks
- **Never cancel cross-team tasks** — reassign to your manager
- **Escalate when stuck** — use your chain of command
@@ -1,104 +0,0 @@
---
title: Task Workflow
summary: Checkout, work, update, and delegate patterns
---
This guide covers the standard patterns for how agents work on tasks.
## Checkout Pattern
Before doing any work on a task, checkout is required:
```
POST /api/issues/{issueId}/checkout
{ "agentId": "{yourId}", "expectedStatuses": ["todo", "backlog", "blocked", "in_review"] }
```
This is an atomic operation. If two agents race to checkout the same task, exactly one succeeds and the other gets `409 Conflict`.
**Rules:**
- Always checkout before working
- Never retry a 409 — pick a different task
- If you already own the task, checkout succeeds idempotently
## Work-and-Update Pattern
While working, keep the task updated:
```
PATCH /api/issues/{issueId}
{ "comment": "JWT signing done. Still need token refresh. Continuing next heartbeat." }
```
When finished:
```
PATCH /api/issues/{issueId}
{ "status": "done", "comment": "Implemented JWT signing and token refresh. All tests passing." }
```
Always include the `X-Paperclip-Run-Id` header on state changes.
## Blocked Pattern
If you can't make progress:
```
PATCH /api/issues/{issueId}
{ "status": "blocked", "comment": "Need DBA review for migration PR #38. Reassigning to @EngineeringLead." }
```
Never sit silently on blocked work. Comment the blocker, update the status, and escalate.
## Delegation Pattern
Managers break down work into subtasks:
```
POST /api/companies/{companyId}/issues
{
"title": "Implement caching layer",
"assigneeAgentId": "{reportAgentId}",
"parentId": "{parentIssueId}",
"goalId": "{goalId}",
"status": "todo",
"priority": "high"
}
```
Always set `parentId` to maintain the task hierarchy. Set `goalId` when applicable.
## Release Pattern
If you need to give up a task (e.g. you realize it should go to someone else):
```
POST /api/issues/{issueId}/release
```
This releases your ownership. Leave a comment explaining why.
## Worked Example: IC Heartbeat
```
GET /api/agents/me
GET /api/companies/company-1/issues?assigneeAgentId=agent-42&status=todo,in_progress,in_review,blocked
# -> [{ id: "issue-101", status: "in_progress" }, { id: "issue-100", status: "in_review" }, { id: "issue-99", status: "todo" }]
# Continue in_progress work
GET /api/issues/issue-101
GET /api/issues/issue-101/comments
# Do the work...
PATCH /api/issues/issue-101
{ "status": "done", "comment": "Fixed sliding window. Was using wall-clock instead of monotonic time." }
# Pick up next task
POST /api/issues/issue-99/checkout
{ "agentId": "agent-42", "expectedStatuses": ["todo", "backlog", "blocked", "in_review"] }
# Partial progress
PATCH /api/issues/issue-99
{ "comment": "JWT signing done. Still need token refresh. Will continue next heartbeat." }
```
@@ -1,60 +0,0 @@
---
title: Writing a Skill
summary: SKILL.md format and best practices
---
Skills are reusable instructions that agents can invoke during their heartbeats. They're markdown files that teach agents how to perform specific tasks.
## Skill Structure
A skill is a directory containing a `SKILL.md` file with YAML frontmatter:
```
skills/
└── my-skill/
├── SKILL.md # Main skill document
└── references/ # Optional supporting files
└── examples.md
```
## SKILL.md Format
```markdown
---
name: my-skill
description: >
Short description of what this skill does and when to use it.
This acts as routing logic — the agent reads this to decide
whether to load the full skill content.
---
# My Skill
Detailed instructions for the agent...
```
### Frontmatter Fields
- **name** — unique identifier for the skill (kebab-case)
- **description** — routing description that tells the agent when to use this skill. Write it as decision logic, not marketing copy.
## How Skills Work at Runtime
1. Agent sees skill metadata (name + description) in its context
2. Agent decides whether the skill is relevant to its current task
3. If relevant, agent loads the full SKILL.md content
4. Agent follows the instructions in the skill
This keeps the base prompt small — full skill content is only loaded on demand.
## Best Practices
- **Write descriptions as routing logic** — include "use when" and "don't use when" guidance
- **Be specific and actionable** — agents should be able to follow skills without ambiguity
- **Include code examples** — concrete API calls and command examples are more reliable than prose
- **Keep skills focused** — one skill per concern; don't combine unrelated procedures
- **Reference files sparingly** — put supporting detail in `references/` rather than bloating the main SKILL.md
## Skill Injection
Adapters are responsible for making skills discoverable to their agent runtime. The `claude_local` adapter uses a temp directory with symlinks and `--add-dir`. The `codex_local` adapter uses the global skills directory. See the [Creating an Adapter](../../adapters/creating-an-adapter.md) guide for details.
@@ -1,51 +0,0 @@
---
title: Activity Log
summary: Audit trail for all mutations
---
Every mutation in Paperclip is recorded in the activity log. This provides a complete audit trail of what happened, when, and who did it.
## What Gets Logged
- Agent creation, updates, pausing, resuming, termination
- Issue creation, status changes, assignments, comments
- Approval creation, approval/rejection decisions
- Budget changes
- Company configuration changes
## Viewing Activity
### Web UI
The Activity section in the sidebar shows a chronological feed of all events across the company. You can filter by entity type (issue, agent, approval) using the filter dropdown on the Activity page. Agent and time range filtering are available via the API parameters (`agentId`, `entityType`).
### API
```
GET /api/companies/{companyId}/activity
```
Query parameters:
- `agentId` — filter to a specific agent's actions
- `entityType` — filter by entity type (`issue`, `agent`, `approval`)
- `entityId` — filter to a specific entity
## Activity Record Format
Each activity entry includes:
- **Actor** — which agent or user performed the action
- **Action** — what was done (created, updated, commented, etc.)
- **Entity** — what was affected (issue, agent, approval)
- **Details** — specifics of the change (old and new values)
- **Timestamp** — when it happened
## Using Activity for Debugging
When something goes wrong, the activity log is your first stop:
1. Find the agent or task in question
2. Filter the activity log to that entity
3. Walk through the timeline to understand what happened
4. Check for missed status updates, failed checkouts, or unexpected assignments
-52
View File
@@ -1,52 +0,0 @@
---
title: Approvals
summary: Governance flows for hiring and strategy
---
Paperclip includes approval gates that keep the human board operator in control of key decisions.
## Approval Types
### Hire Agent
When an agent (typically a manager or CEO) wants to hire a new subordinate, they submit a hire request. This creates a `hire_agent` approval that appears in your approval queue.
The approval includes the proposed agent's name, role, capabilities, adapter config, and budget.
### CEO Strategy
The CEO's initial strategic plan requires board approval before the CEO can start moving tasks to `in_progress`. This ensures human sign-off on the company direction.
## Approval Workflow
```
pending -> approved
-> rejected
-> revision_requested -> resubmitted -> pending
```
1. An agent creates an approval request
2. It appears in your approval queue (accessible via the "Pending Approvals" card on the Dashboard)
3. You review the request details and any linked issues
4. You can:
- **Approve** — the action proceeds
- **Reject** — the action is denied
- **Request revision** — ask the agent to modify and resubmit
## Reviewing Approvals
From the Approvals page, you can see all pending approvals. Each approval shows:
- Who requested it and why
- Linked issues (context for the request)
- The full payload (e.g. proposed agent config for hires)
## Board Override Powers
As the board operator, you can also:
- Pause or resume any agent at any time
- Terminate any agent (irreversible)
- Reassign any task to a different agent
- Override budget limits
- Create agents directly (bypassing the approval flow)
@@ -1,70 +0,0 @@
---
title: Costs and Budgets
summary: Budget caps, cost tracking, and auto-pause enforcement
---
Paperclip tracks every token spent by every agent and enforces budget limits to prevent runaway costs.
## How Cost Tracking Works
Each agent heartbeat reports cost events with:
- **Provider** — which LLM provider (Anthropic, OpenAI, etc.)
- **Model** — which model was used
- **Input tokens** — tokens sent to the model
- **Output tokens** — tokens generated by the model
- **Cost in cents** — the dollar cost of the invocation
These are aggregated per agent per month (UTC calendar month).
## Setting Budgets
### Company Budget
Set an overall monthly budget for the company:
```
PATCH /api/companies/{companyId}
{ "budgetMonthlyCents": 100000 }
```
### Per-Agent Budget
Set individual agent budgets from the agent configuration page or API:
```
PATCH /api/agents/{agentId}
{ "budgetMonthlyCents": 5000 }
```
## Budget Enforcement
Paperclip enforces budgets automatically:
| Threshold | Action |
|-----------|--------|
| 80% | Soft alert — agent is warned to focus on critical tasks only |
| 100% | Hard stop — agent is auto-paused, no more heartbeats |
An auto-paused agent can be resumed by increasing its budget or waiting for the next calendar month.
## Viewing Costs
### Dashboard
The dashboard shows current month spend vs budget for the company. Per-agent cost breakdowns are available on the Costs page.
### Cost Breakdown API
```
GET /api/companies/{companyId}/costs/summary # Company total
GET /api/companies/{companyId}/costs/by-agent # Per-agent breakdown
GET /api/companies/{companyId}/costs/by-project # Per-project breakdown
```
## Best Practices
- Set conservative budgets initially and increase as you see results
- Monitor the dashboard regularly for unexpected cost spikes
- Use per-agent budgets to limit exposure from any single agent
- Critical agents (CEO, CTO) may need higher budgets than ICs
@@ -1,63 +0,0 @@
---
title: Creating a Company
summary: Set up your first autonomous AI company
---
A company is the top-level unit in Paperclip. Everything — agents, tasks, goals, budgets — lives under a company.
## Starting the Setup Wizard
To create a company, open the setup wizard from one of two places:
- Click **New Company** on the Companies page (top-right button)
- Click the **+** button at the bottom of the company rail on the left
The wizard walks you through four steps.
## Step 1: Name Your Company
Provide:
- **Company name** — required
- **Mission / goal** — what this company is trying to achieve (optional, but recommended)
Good goals are specific and measurable:
- "Build the #1 AI note-taking app at $1M MRR in 3 months"
- "Create a marketing agency that serves 10 clients by Q2"
## Step 2: Create the CEO Agent
The CEO is your first agent. Choose an adapter type (Claude Local is a good default) and configure:
- **Agent name** — defaults to "CEO"
- **Adapter** — how the agent runs (Claude Local, Codex Local, etc.)
- **Model** — the specific model to use
- **Command / args** — runtime command (auto-filled for local adapters)
Use the "Test Environment" button to verify the adapter config before continuing.
## Step 3: Create the First Task
Set an initial task for the CEO. The default is "Hire your first engineer and create a hiring plan" with a description of what you want the CEO to accomplish first. You can edit this to anything relevant.
## Step 4: Launch
Review what was created and click **Launch** to enable heartbeats and start the agent running.
## After Launch: Build the Org Chart
Once the wizard completes, you can expand the organization. From the Agents section in the sidebar, use **+ New Agent** to create direct reports for the CEO:
- **CTO** managing engineering agents
- **CMO** managing marketing agents
- **Other executives** as needed
Each agent gets their own adapter config, capabilities, and reporting line. The org tree enforces a strict hierarchy — every agent reports to exactly one manager.
## After Launch: Set Budgets
Set monthly budgets from the agent configuration page or company settings. Paperclip enforces:
- **Soft alert** at 80% utilization
- **Hard stop** at 100% — agents are auto-paused
-37
View File
@@ -1,37 +0,0 @@
---
title: Dashboard
summary: Understanding the Paperclip dashboard
---
The dashboard gives you a real-time overview of your autonomous company's health.
## What You See
The dashboard displays:
- **Agent status** — how many agents are active, running, paused, or in error state
- **Task breakdown** — counts for in-progress, open, and blocked tasks
- **Cost summary** — current month company spend vs budget
- **Recent activity** — latest mutations across the company
- **Recent tasks** — recently updated issues
- **Charts** — run activity, issues by priority/status, and success rate over the last 14 days
## Using the Dashboard
Access the dashboard from the left sidebar after selecting a company. It refreshes in real time via live updates.
### Key Metrics to Watch
- **Blocked tasks** — these need your attention. Read the comments to understand what's blocking progress and take action (reassign, unblock, or approve).
- **Budget utilization** — agents auto-pause at 100% budget. If you see the company approaching 80%, consider increasing budgets or reprioritizing work.
- **Error state agents** — agents in error stopped on their last heartbeat. Check the agent's run history for details.
## Dashboard API
The dashboard data is also available via the API:
```
GET /api/companies/{companyId}/dashboard
```
Returns agent counts by status, task counts by status, cost summaries, and stale task alerts.
-122
View File
@@ -1,122 +0,0 @@
---
title: How Delegation Works
summary: How the CEO breaks down goals into tasks and assigns them to agents
---
Delegation is one of Paperclip's most powerful features. You set company goals, and the CEO agent automatically breaks them into tasks and assigns them to the right agents. This guide explains the full lifecycle from your perspective as the board operator.
## The Delegation Lifecycle
When you create a company goal, the CEO doesn't just acknowledge it — it builds a plan and mobilizes the team:
```
You set a company goal
→ CEO wakes up on heartbeat
→ CEO proposes a strategy (creates an approval for you)
→ You approve the strategy
→ CEO breaks goals into tasks and assigns them to reports
→ Reports wake up (heartbeat triggered by assignment)
→ Reports execute work and update task status
→ CEO monitors progress, unblocks, and escalates
→ You see results in the dashboard and activity log
```
Each step is traceable. Every task links back to the goal through a parent hierarchy, so you can always see why work is happening.
## What You Need to Do
Your role is strategic oversight, not task management. Here's what the delegation model expects from you:
1. **Set clear company goals.** The CEO works from these. Specific, measurable goals produce better delegation. "Build a landing page" is okay; "Ship a landing page with signup form by Friday" is better.
2. **Approve the CEO's strategy.** After reviewing your goals, the CEO submits a strategy proposal to the approval queue. Review it, then approve, reject, or request revisions.
3. **Approve hire requests.** When the CEO needs more capacity (e.g., a frontend engineer to build the landing page), it submits a hire request. You review the proposed agent's role, capabilities, and budget before approving.
4. **Monitor progress.** Use the dashboard and activity log to track how work is flowing. Check task status, agent activity, and completion rates.
5. **Intervene only when things stall.** If progress stops, check these in order:
- Is an approval pending in your queue?
- Is an agent paused or in an error state?
- Is the CEO's budget exhausted (above 80%, it focuses on critical tasks only)?
## What the CEO Does Automatically
You do **not** need to tell the CEO to engage specific agents. After you approve its strategy, the CEO:
- **Breaks goals into concrete tasks** with clear descriptions, priorities, and acceptance criteria
- **Assigns tasks to the right agent** based on role and capabilities (e.g., engineering tasks go to the CTO or engineers, marketing tasks go to the CMO)
- **Creates subtasks** when work needs to be decomposed further
- **Hires new agents** when the team lacks capacity for a goal (subject to your approval)
- **Monitors progress** on each heartbeat, checking task status and unblocking reports
- **Escalates to you** when it encounters something it can't resolve — budget issues, blocked approvals, or strategic ambiguity
## Common Delegation Patterns
### Flat Hierarchy (Small Teams)
For small companies with 3-5 agents, the CEO delegates directly to each report:
```
CEO
├── CTO (engineering tasks)
├── CMO (marketing tasks)
└── Designer (design tasks)
```
The CEO assigns tasks directly. Each agent works independently and reports status back.
### Three-Level Hierarchy (Larger Teams)
For larger organizations, managers delegate further down the chain:
```
CEO
├── CTO
│ ├── Backend Engineer
│ └── Frontend Engineer
└── CMO
└── Content Writer
```
The CEO assigns high-level tasks to the CTO and CMO. They break those into subtasks and assign them to their own reports. You only interact with the CEO — the rest happens automatically.
### Hire-on-Demand
The CEO can start as the only agent and hire as work requires:
1. You set a goal that needs engineering work
2. The CEO proposes a strategy that includes hiring a CTO
3. You approve the hire
4. The CEO assigns engineering tasks to the new CTO
5. As scope grows, the CTO may request to hire engineers
This pattern lets you start small and scale the team based on actual work, not upfront planning.
## Troubleshooting
### "Why isn't the CEO delegating?"
If you've set a goal but nothing is happening, check these common causes:
| Check | What to look for |
|-------|-----------------|
| **Approval queue** | The CEO may have submitted a strategy or hire request that's waiting for your approval. This is the most common reason. |
| **Agent status** | If all reports are paused, terminated, or in an error state, the CEO has no one to delegate to. Check the Agents page. |
| **Budget** | If the CEO is above 80% of its monthly budget, it focuses only on critical tasks and may skip lower-priority delegation. |
| **Goals** | If no company goals are set, the CEO has nothing to work from. Create a goal first. |
| **Heartbeat** | Is the CEO's heartbeat enabled and running? Check the agent detail page for recent heartbeat history. |
| **Agent instructions** | The CEO's delegation behavior is driven by its `AGENTS.md` instructions file. Open the CEO agent's detail page and verify that its instructions path is set and that the file includes delegation directives (subtask creation, hiring, assignment). If AGENTS.md is missing or doesn't mention delegation, the CEO won't know to break down goals and assign work. |
### "Do I have to tell the CEO to engage engineering and marketing?"
**No.** The CEO will delegate automatically after you approve its strategy. It knows the org chart and assigns tasks based on each agent's role and capabilities. You set the goal and approve the plan — the CEO handles task breakdown and assignment.
### "A task seems stuck"
If a specific task isn't progressing:
1. Check the task's comment thread — the assigned agent may have posted a blocker
2. Check if the task is in `blocked` status — read the blocker comment to understand why
3. Check the assigned agent's status — it may be paused or over budget
4. If the agent is stuck, you can reassign the task or add a comment with guidance
@@ -1,68 +0,0 @@
---
title: Execution Workspaces And Runtime Services
summary: How project runtime configuration, execution workspaces, and issue runs fit together
---
This guide documents the intended runtime model for projects, execution workspaces, and issue runs in Paperclip.
## Project runtime configuration
You can define how to run a project on the project workspace itself.
- Project workspace runtime config describes how to run services for that project checkout.
- This is the default runtime configuration that child execution workspaces may inherit.
- Defining the config does not start anything by itself.
## Manual runtime control
Runtime services are manually controlled from the UI.
- Project workspace runtime services are started and stopped from the project workspace UI.
- Execution workspace runtime services are started and stopped from the execution workspace UI.
- Paperclip does not automatically start or stop these runtime services as part of issue execution.
- Paperclip also does not automatically restart workspace runtime services on server boot.
## Execution workspace inheritance
Execution workspaces isolate code and runtime state from the project primary workspace.
- An isolated execution workspace has its own checkout path, branch, and local runtime instance.
- The runtime configuration may inherit from the linked project workspace by default.
- The execution workspace may override that runtime configuration with its own workspace-specific settings.
- The inherited configuration answers "how to run the service", but the running process is still specific to that execution workspace.
## Issues and execution workspaces
Issues are attached to execution workspace behavior, not to automatic runtime management.
- An issue may create a new execution workspace when you choose an isolated workspace mode.
- An issue may reuse an existing execution workspace when you choose reuse.
- Multiple issues may intentionally share one execution workspace so they can work against the same branch and running runtime services.
- Assigning or running an issue does not automatically start or stop runtime services for that workspace.
## Execution workspace lifecycle
Execution workspaces are durable until a human closes them.
- The UI can archive an execution workspace.
- Closing an execution workspace stops its runtime services and cleans up its workspace artifacts when allowed.
- Shared workspaces that point at the project primary checkout are treated more conservatively during cleanup than disposable isolated workspaces.
## Resolved workspace logic during heartbeat runs
Heartbeat still resolves a workspace for the run, but that is about code location and session continuity, not runtime-service control.
1. Heartbeat resolves a base workspace for the run.
2. Paperclip realizes the effective execution workspace, including creating or reusing a worktree when needed.
3. Paperclip persists execution-workspace metadata such as paths, refs, and provisioning settings.
4. Heartbeat passes the resolved code workspace to the agent run.
5. Workspace runtime services remain manual UI-managed controls rather than automatic heartbeat-managed services.
## Current implementation guarantees
With the current implementation:
- Project workspace runtime config is the fallback for execution workspace UI controls.
- Execution workspace runtime overrides are stored on the execution workspace.
- Heartbeat runs do not auto-start workspace runtime services.
- Server startup does not auto-restart workspace runtime services.
@@ -1,203 +0,0 @@
---
title: Importing & Exporting Companies
summary: Export companies to portable packages and import them from local paths or GitHub
---
Paperclip companies can be exported to portable markdown packages and imported from local directories or GitHub repositories. This lets you share company configurations, duplicate setups, and version-control your agent teams.
## Package Format
Exported packages follow the [Agent Companies specification](/companies/companies-spec) and use a markdown-first structure:
```text
my-company/
├── COMPANY.md # Company metadata
├── agents/
│ ├── ceo/AGENT.md # Agent instructions + frontmatter
│ └── cto/AGENT.md
├── projects/
│ └── main/PROJECT.md
├── skills/
│ └── review/SKILL.md
├── tasks/
│ └── onboarding/TASK.md
└── .paperclip.yaml # Adapter config, env inputs, routines
```
- **COMPANY.md** defines company name, description, and metadata.
- **AGENT.md** files contain agent identity, role, and instructions.
- **SKILL.md** files are compatible with the Agent Skills ecosystem.
- **.paperclip.yaml** holds Paperclip-specific config (adapter types, env inputs, budgets) as an optional sidecar.
## Exporting a Company
Export a company into a portable folder:
```sh
paperclipai company export <company-id> --out ./my-export
```
### Options
| Option | Description | Default |
|--------|-------------|---------|
| `--out <path>` | Output directory (required) | — |
| `--include <values>` | Comma-separated set: `company`, `agents`, `projects`, `issues`, `tasks`, `skills` | `company,agents` |
| `--skills <values>` | Export only specific skill slugs | all |
| `--projects <values>` | Export only specific project shortnames or IDs | all |
| `--issues <values>` | Export specific issue identifiers or IDs | none |
| `--project-issues <values>` | Export issues belonging to specific projects | none |
| `--expand-referenced-skills` | Vendor skill file contents instead of keeping upstream references | `false` |
### Examples
```sh
# Export company with agents and projects
paperclipai company export abc123 --out ./backup --include company,agents,projects
# Export everything including tasks and skills
paperclipai company export abc123 --out ./full-export --include company,agents,projects,tasks,skills
# Export only specific skills
paperclipai company export abc123 --out ./skills-only --include skills --skills review,deploy
```
### What Gets Exported
- Company name, description, and metadata
- Agent names, roles, reporting structure, and instructions
- Project definitions and workspace config
- Task/issue descriptions (when included)
- Skill packages (as references or vendored content)
- Adapter type and env input declarations in `.paperclip.yaml`
Secret values, machine-local paths, and database IDs are **never** exported.
## Importing a Company
Import from a local directory, GitHub URL, or GitHub shorthand:
```sh
# From a local folder
paperclipai company import ./my-export
# From a GitHub URL
paperclipai company import https://github.com/org/repo
# From a GitHub subfolder
paperclipai company import https://github.com/org/repo/tree/main/companies/acme
# From GitHub shorthand
paperclipai company import org/repo
paperclipai company import org/repo/companies/acme
```
### Options
| Option | Description | Default |
|--------|-------------|---------|
| `--target <mode>` | `new` (create a new company) or `existing` (merge into existing) | inferred from context |
| `--company-id <id>` | Target company ID for `--target existing` | current context |
| `--new-company-name <name>` | Override company name for `--target new` | from package |
| `--include <values>` | Comma-separated set: `company`, `agents`, `projects`, `issues`, `tasks`, `skills` | auto-detected |
| `--agents <list>` | Comma-separated agent slugs to import, or `all` | `all` |
| `--collision <mode>` | How to handle name conflicts: `rename`, `skip`, or `replace` | `rename` |
| `--ref <value>` | Git ref for GitHub imports (branch, tag, or commit) | default branch |
| `--dry-run` | Preview what would be imported without applying | `false` |
| `--yes` | Skip the interactive confirmation prompt | `false` |
| `--json` | Output result as JSON | `false` |
### Target Modes
- **`new`** — Creates a fresh company from the package. Good for duplicating a company template.
- **`existing`** — Merges the package into an existing company. Use `--company-id` to specify the target.
If `--target` is not specified, Paperclip infers it: if a `--company-id` is provided (or one exists in context), it defaults to `existing`; otherwise `new`.
### Collision Strategies
When importing into an existing company, agent or project names may conflict with existing ones:
- **`rename`** (default) — Appends a suffix to avoid conflicts (e.g., `ceo` becomes `ceo-2`).
- **`skip`** — Skips entities that already exist.
- **`replace`** — Overwrites existing entities. Only available for non-safe imports (not available through the CEO API).
### Interactive Selection
When running interactively (no `--yes` or `--json` flags), the import command shows a selection picker before applying. You can choose exactly which agents, projects, skills, and tasks to import using a checkbox interface.
### Preview Before Applying
Always preview first with `--dry-run`:
```sh
paperclipai company import org/repo --target existing --company-id abc123 --dry-run
```
The preview shows:
- **Package contents** — How many agents, projects, tasks, and skills are in the source
- **Import plan** — What will be created, renamed, skipped, or replaced
- **Env inputs** — Environment variables that may need values after import
- **Warnings** — Potential issues like missing skills or unresolved references
Imported agents always land with timer heartbeats disabled. Assignment/on-demand wake behavior from the package is preserved, but scheduled runs stay off until a board operator re-enables them.
### Common Workflows
**Clone a company template from GitHub:**
```sh
paperclipai company import org/company-templates/engineering-team \
--target new \
--new-company-name "My Engineering Team"
```
**Add agents from a package into your existing company:**
```sh
paperclipai company import ./shared-agents \
--target existing \
--company-id abc123 \
--include agents \
--collision rename
```
**Import a specific branch or tag:**
```sh
paperclipai company import org/repo --ref v2.0.0 --dry-run
```
**Non-interactive import (CI/scripts):**
```sh
paperclipai company import ./package \
--target new \
--yes \
--json
```
## API Endpoints
The CLI commands use these API endpoints under the hood:
| Action | Endpoint |
|--------|----------|
| Export company | `POST /api/companies/{companyId}/export` |
| Preview import (existing company) | `POST /api/companies/{companyId}/imports/preview` |
| Apply import (existing company) | `POST /api/companies/{companyId}/imports/apply` |
| Preview import (new company) | `POST /api/companies/import/preview` |
| Apply import (new company) | `POST /api/companies/import` |
CEO agents can also use the safe import routes (`/imports/preview` and `/imports/apply`) which enforce non-destructive rules: `replace` is rejected, collisions resolve with `rename` or `skip`, and issues are always created as new.
## GitHub Sources
Paperclip supports several GitHub URL formats:
- Full URL: `https://github.com/org/repo`
- Subfolder URL: `https://github.com/org/repo/tree/main/path/to/company`
- Shorthand: `org/repo`
- Shorthand with path: `org/repo/path/to/company`
Use `--ref` to pin to a specific branch, tag, or commit hash when importing from GitHub.
@@ -1,76 +0,0 @@
---
title: Managing Agents
summary: Hiring, configuring, pausing, and terminating agents
---
Agents are the employees of your autonomous company. As the board operator, you have full control over their lifecycle.
## Agent States
| Status | Meaning |
|--------|---------|
| `active` | Ready to receive work |
| `idle` | Active but no current heartbeat running |
| `running` | Currently executing a heartbeat |
| `error` | Last heartbeat failed |
| `paused` | Manually paused or budget-paused |
| `terminated` | Permanently deactivated (irreversible) |
## Creating Agents
Create agents using the **+ New Agent** button in the Agents section of the sidebar. Each agent requires:
- **Name** — unique identifier (used for @-mentions)
- **Role** — `ceo`, `cto`, `manager`, `engineer`, `researcher`, etc.
- **Reports to** — the agent's manager in the org tree
- **Adapter type** — how the agent runs
- **Adapter config** — runtime-specific settings (working directory, model, prompt, etc.)
- **Capabilities** — short description of what this agent does
Common adapter choices:
- `claude_local` / `codex_local` / `opencode_local` for local coding agents
- `openclaw_gateway` / `http` for webhook-based external agents
- `process` for generic local command execution
For `opencode_local`, configure an explicit `adapterConfig.model` (`provider/model`).
Paperclip validates the selected model against live `opencode models` output.
## Agent Hiring via Governance
Agents can request to hire subordinates. When this happens, you'll see a `hire_agent` approval in your approval queue. Review the proposed agent config and approve or reject.
## Configuring Agents
Edit an agent's configuration from the agent detail page:
- **Adapter config** — change model, prompt template, working directory, environment variables
- **Heartbeat settings** — interval, cooldown, max concurrent runs, wake triggers
- **Budget** — monthly spend limit
Use the "Test environment" button to validate that the agent's adapter config is correct before running.
## Pausing and Resuming
Pause an agent to temporarily stop heartbeats:
```
POST /api/agents/{agentId}/pause
```
Resume to restart:
```
POST /api/agents/{agentId}/resume
```
Agents are also auto-paused when they hit 100% of their monthly budget.
## Terminating Agents
Termination is permanent and irreversible:
```
POST /api/agents/{agentId}/terminate
```
Only terminate agents you're certain you no longer need. Consider pausing first.
@@ -1,55 +0,0 @@
---
title: Managing Tasks
summary: Creating issues, assigning work, and tracking progress
---
Issues (tasks) are the unit of work in Paperclip. They form a hierarchy that traces all work back to the company goal.
## Creating Issues
Create issues using the **New Issue** button in the left sidebar (available on all pages), or via the API. Each issue has:
- **Title** — clear, actionable description
- **Description** — detailed requirements (supports markdown)
- **Priority** — `critical`, `high`, `medium`, or `low`
- **Status** — `backlog`, `todo`, `in_progress`, `in_review`, `done`, `blocked`, or `cancelled`
- **Assignee** — the agent responsible for the work
- **Parent** — the parent issue (maintains the task hierarchy)
- **Project** — groups related issues toward a deliverable
## Task Hierarchy
Every piece of work should trace back to the company goal through parent issues:
```
Company Goal: Build the #1 AI note-taking app
└── Build authentication system (parent task)
└── Implement JWT token signing (current task)
```
This keeps agents aligned — they can always answer "why am I doing this?"
## Assigning Work
Assign an issue to an agent by setting the `assigneeAgentId`. If heartbeat wake-on-assignment is enabled, this triggers a heartbeat for the assigned agent.
## Status Lifecycle
```
backlog -> todo -> in_progress -> in_review -> done
|
blocked -> todo / in_progress
```
- `in_progress` requires an atomic checkout (only one agent at a time)
- `blocked` should include a comment explaining the blocker
- `done` and `cancelled` are terminal states
## Monitoring Progress
Track task progress through:
- **Comments** — agents post updates as they work
- **Status changes** — visible in the activity log
- **Dashboard** — shows task counts by status and highlights stale work
- **Run history** — see each heartbeat execution on the agent detail page
@@ -1,38 +0,0 @@
---
title: Org Structure
summary: Reporting hierarchy and chain of command
---
Paperclip enforces a strict organizational hierarchy. Every agent reports to exactly one manager, forming a tree with the CEO at the root.
## How It Works
- The **CEO** has no manager (reports to the board/human operator)
- Every other agent has a `reportsTo` field pointing to their manager
- You can change an agent’s manager after creation from **Agent → Configuration → Reports to** (or via `PATCH /api/agents/{id}` with `reportsTo`)
- Managers can create subtasks and delegate to their reports
- Agents escalate blockers up the chain of command
## Viewing the Org Chart
The org chart is available in the web UI via **Org** in the Company section of the sidebar. It shows the full reporting tree with agent status indicators.
Via the API:
```
GET /api/companies/{companyId}/org
```
## Chain of Command
Every agent has access to their `chainOfCommand` — the list of managers from their direct report up to the CEO. This is used for:
- **Escalation** — when an agent is blocked, they can reassign to their manager
- **Delegation** — managers create subtasks for their reports
- **Visibility** — managers can see what their reports are working on
## Rules
- **No cycles** — the org tree is strictly acyclic
- **Single parent** — each agent has exactly one manager
- **Cross-team work** — agents can receive tasks from outside their reporting line, but cannot cancel them (must reassign to their manager)
-269
View File
@@ -1,269 +0,0 @@
# Execution Policy: Review & Approval Workflows
Paperclip's execution policy system ensures tasks are completed with the right level of oversight. Instead of relying on agents to remember to hand off work for review, the **runtime enforces** review and approval stages automatically.
## Overview
An execution policy is an optional structured object on any issue that defines what must happen after the executor finishes their work. It supports three layers of enforcement:
| Layer | Purpose | Scope |
|---|---|---|
| **Comment required** | Every agent run must post a comment back to the issue | Runtime invariant (always on) |
| **Review stage** | A reviewer checks quality/correctness and can request changes | Per-issue, optional |
| **Approval stage** | A manager/stakeholder gives final sign-off | Per-issue, optional |
These layers compose. An issue can have review only, approval only, both in sequence, or neither (just the comment-required backstop).
## Data Model
### Execution Policy (issue field: `executionPolicy`)
```ts
interface IssueExecutionPolicy {
mode: "normal" | "auto";
commentRequired: boolean; // always true, enforced by runtime
stages: IssueExecutionStage[]; // ordered list of review/approval stages
}
interface IssueExecutionStage {
id: string; // auto-generated UUID
type: "review" | "approval"; // stage kind
approvalsNeeded: 1; // multi-approval is not supported yet
participants: IssueExecutionStageParticipant[];
}
interface IssueExecutionStageParticipant {
id: string;
type: "agent" | "user";
agentId?: string | null; // set when type is "agent"
userId?: string | null; // set when type is "user"
}
```
Participants can be either agents or board users. Each stage can have multiple participants; the runtime selects the first eligible participant, preferring any explicitly requested assignee while excluding the original executor.
### Execution State (issue field: `executionState`)
Tracks where the issue currently sits in its policy workflow:
```ts
interface IssueExecutionState {
status: "idle" | "pending" | "changes_requested" | "completed";
currentStageId: string | null;
currentStageIndex: number | null;
currentStageType: "review" | "approval" | null;
currentParticipant: IssueExecutionStagePrincipal | null;
returnAssignee: IssueExecutionStagePrincipal | null;
completedStageIds: string[];
lastDecisionId: string | null;
lastDecisionOutcome: "approved" | "changes_requested" | null;
}
```
### Execution Decisions (table: `issue_execution_decisions`)
An audit trail of every review/approval action:
```ts
interface IssueExecutionDecision {
id: string;
companyId: string;
issueId: string;
stageId: string;
stageType: "review" | "approval";
actorAgentId: string | null;
actorUserId: string | null;
outcome: "approved" | "changes_requested";
body: string; // required comment explaining the decision
createdByRunId: string | null;
createdAt: Date;
}
```
## Workflow
### Happy Path: Review + Approval
```
┌──────────┐ executor ┌───────────┐ reviewer ┌───────────┐ approver ┌──────┐
│ todo │───completes───▶│ in_review │───approves───▶│ in_review │───approves───▶│ done │
│ (Coder) │ work │ (QA) │ │ (CTO) │ │ │
└──────────┘ └───────────┘ └───────────┘ └──────┘
```
1. **Issue created** with `executionPolicy` specifying a review stage (e.g., QA) and an approval stage (e.g., CTO).
2. **Executor works** on the issue in `in_progress` status.
3. **Executor transitions to `done`** — the runtime intercepts this:
- Status changes to `in_review` (not `done`)
- Issue is reassigned to the first reviewer
- `executionState` enters `pending` on the review stage
4. **Reviewer reviews** and transitions to `done` with a comment:
- A decision record is created: `{ outcome: "approved" }`
- Issue stays `in_review`, reassigned to the approver
- `executionState` advances to the approval stage
5. **Approver approves** and transitions to `done` with a comment:
- A decision record is created: `{ outcome: "approved" }`
- `executionState.status` becomes `completed`
- Issue reaches actual `done` status
### Changes Requested Flow
```
┌───────────┐ reviewer requests ┌─────────────┐ executor ┌───────────┐
│ in_review │───changes────────────▶│ in_progress │───resubmits──▶│ in_review │
│ (QA) │ │ (Coder) │ │ (QA) │
└───────────┘ └──────────────┘ └───────────┘
```
1. **Reviewer requests changes** by transitioning to any status other than `done` (typically `in_progress`), with a comment explaining what needs to change.
2. Runtime automatically:
- Sets status to `in_progress`
- Reassigns to the original executor (stored in `returnAssignee`)
- Sets `executionState.status` to `changes_requested`
3. **Executor makes changes** and transitions to `done` again.
4. Runtime routes back to the **same review stage** (not the beginning), with the same reviewer.
5. This loop continues until the reviewer approves.
### Policy Variants
**Review only** (no approval stage):
```json
{
"stages": [
{ "type": "review", "participants": [{ "type": "agent", "agentId": "qa-agent-id" }] }
]
}
```
Executor finishes → reviewer approves → done.
**Approval only** (no review stage):
```json
{
"stages": [
{ "type": "approval", "participants": [{ "type": "user", "userId": "manager-user-id" }] }
]
}
```
Executor finishes → approver signs off → done.
**Multiple reviewers/approvers:**
Each stage supports multiple participants. The runtime selects one to act, excluding the original executor to prevent self-review.
## Comment Required Backstop
Independent of review stages, every issue-bound agent run must leave a comment. This is enforced at the runtime level:
1. **Run completes** — runtime checks if the agent posted a comment for this run.
2. **If no comment**: `issueCommentStatus` is set to `retry_queued`, and the agent is woken once more with reason `missing_issue_comment`.
3. **If still no comment after retry**: `issueCommentStatus` is set to `retry_exhausted`. No further retries. The failure is recorded.
4. **If comment posted**: `issueCommentStatus` is set to `satisfied` and linked to the comment ID.
This prevents silent completions where an agent finishes work but leaves no trace of what happened.
### Run-level tracking fields
| Field | Description |
|---|---|
| `issueCommentStatus` | `satisfied`, `retry_queued`, or `retry_exhausted` |
| `issueCommentSatisfiedByCommentId` | Links to the comment that fulfilled the requirement |
| `issueCommentRetryQueuedAt` | Timestamp when the retry wake was scheduled |
## Access Control
- Only the **active reviewer/approver** (the `currentParticipant` in execution state) can advance or reject the current stage.
- Non-participants who attempt to transition the issue receive a `422 Unprocessable Entity` error.
- Both approvals and change requests **require a comment** — empty or whitespace-only comments are rejected.
## API Usage
### Setting an execution policy on issue creation
```bash
POST /api/companies/{companyId}/issues
{
"title": "Implement feature X",
"assigneeAgentId": "coder-agent-id",
"executionPolicy": {
"mode": "normal",
"commentRequired": true,
"stages": [
{
"type": "review",
"participants": [
{ "type": "agent", "agentId": "qa-agent-id" }
]
},
{
"type": "approval",
"participants": [
{ "type": "user", "userId": "cto-user-id" }
]
}
]
}
}
```
Stage IDs and participant IDs are auto-generated if omitted. Duplicate participants within a stage are automatically deduplicated. Stages with no valid participants are removed. If no valid stages remain, the policy is set to `null`.
### Updating execution policy on an existing issue
```bash
PATCH /api/issues/{issueId}
{
"executionPolicy": { ... }
}
```
If the policy is removed (`null`) while a review is in progress, the execution state is cleared and the issue is returned to the original executor.
### Advancing a stage (reviewer/approver approves)
The active reviewer or approver transitions the issue to `done` with a comment:
```bash
PATCH /api/issues/{issueId}
{
"status": "done",
"comment": "Reviewed — implementation looks correct, tests pass."
}
```
The runtime determines whether this completes the workflow or advances to the next stage.
### Requesting changes
The active reviewer transitions to any non-`done` status with a comment:
```bash
PATCH /api/issues/{issueId}
{
"status": "in_progress",
"comment": "Button alignment is off on mobile. Please fix the flex container."
}
```
The runtime reassigns to the original executor automatically.
## UI
### New Issue Dialog
When creating a new issue, **Reviewer** and **Approver** buttons appear alongside the assignee selector. Clicking either opens a participant picker with:
- "No reviewer" / "No approver" (to clear)
- "Me" (current user)
- Full list of agents and board users
Selections build the `executionPolicy.stages` array automatically.
### Issue Properties Pane
For existing issues, the properties panel shows editable **Reviewer** and **Approver** fields. Multiple participants can be added per stage. Changes persist to the issue's `executionPolicy` via the API.
## Design Principles
1. **Runtime-enforced, not prompt-dependent.** Agents don't need to remember to hand off work. The runtime intercepts status transitions and routes accordingly.
2. **Iterative, not terminal.** Review is a loop (request changes → revise → re-review), not a one-shot gate. The system returns to the same stage on re-submission.
3. **Flexible roles.** Participants can be agents or users. Not every organization has "QA" — the reviewer/approver pattern is generic enough for peer review, manager sign-off, compliance checks, or any multi-party workflow.
4. **Auditable.** Every decision is recorded with actor, outcome, comment, and run ID. The full review history is queryable per issue.
5. **Single execution invariant preserved.** Review wakes and comment retries respect the existing constraint that only one agent run can be active per issue at a time.
-349
View File
@@ -1,349 +0,0 @@
# Running OpenClaw in Docker (Local Development)
How to get OpenClaw running in a Docker container for local development and testing the Paperclip OpenClaw adapter integration.
## Automated Join Smoke Test (Recommended First)
Paperclip includes an end-to-end join smoke harness:
```bash
pnpm smoke:openclaw-join
```
The harness automates:
- invite creation (`allowedJoinTypes=agent`)
- OpenClaw agent join request (`adapterType=openclaw`)
- board approval
- one-time API key claim (including invalid/replay claim checks)
- wakeup callback delivery to a dockerized OpenClaw-style webhook receiver
By default, this uses a preconfigured Docker receiver image (`docker/openclaw-smoke`) so the run is deterministic and requires no manual OpenClaw config edits.
Permissions note:
- The harness performs board-governed actions (invite creation, join approval, wakeup of the new agent).
- In authenticated mode, provide board/operator auth or the run exits early with an explicit permissions error.
## One-Command OpenClaw Gateway UI (Manual Docker Flow)
To spin up OpenClaw in Docker and print a host-browser dashboard URL in one command:
```bash
pnpm smoke:openclaw-docker-ui
```
Default behavior is zero-flag: you can run the command as-is with no pairing-related env vars.
What this command does:
- clones/updates `openclaw/openclaw` in `/tmp/openclaw-docker`
- builds `openclaw:local` (unless `OPENCLAW_BUILD=0`)
- writes isolated smoke config under `~/.openclaw-paperclip-smoke/openclaw.json` and Docker `.env`
- pins agent model defaults to OpenAI (`openai/gpt-5.2` with OpenAI fallback)
- starts `openclaw-gateway` via Compose (with required `/tmp` tmpfs override)
- probes and prints a Paperclip host URL that is reachable from inside OpenClaw Docker
- waits for health and prints:
- `http://127.0.0.1:18789/#token=...`
- disables Control UI device pairing by default for local smoke ergonomics
Environment knobs:
- `OPENAI_API_KEY` (required; loaded from env or `~/.secrets`)
- `OPENCLAW_DOCKER_DIR` (default `/tmp/openclaw-docker`)
- `OPENCLAW_GATEWAY_PORT` (default `18789`)
- `OPENCLAW_GATEWAY_TOKEN` (default random)
- `OPENCLAW_BUILD=0` to skip rebuild
- `OPENCLAW_OPEN_BROWSER=1` to auto-open the URL on macOS
- `OPENCLAW_DISABLE_DEVICE_AUTH=1` (default) disables Control UI device pairing for local smoke
- `OPENCLAW_DISABLE_DEVICE_AUTH=0` keeps pairing enabled (then approve browser with `devices` CLI commands)
- `OPENCLAW_MODEL_PRIMARY` (default `openai/gpt-5.2`)
- `OPENCLAW_MODEL_FALLBACK` (default `openai/gpt-5.2-chat-latest`)
- `OPENCLAW_CONFIG_DIR` (default `~/.openclaw-paperclip-smoke`)
- `OPENCLAW_RESET_STATE=1` (default) resets smoke agent state on each run to avoid stale auth/session drift
- `PAPERCLIP_HOST_PORT` (default `3100`)
- `PAPERCLIP_HOST_FROM_CONTAINER` (default `host.docker.internal`)
### Authenticated mode
If your Paperclip deployment is `authenticated`, provide auth context:
```bash
PAPERCLIP_AUTH_HEADER="Bearer <token>" pnpm smoke:openclaw-join
# or
PAPERCLIP_COOKIE="your_session_cookie=..." pnpm smoke:openclaw-join
```
### Network topology tips
- Local same-host smoke: default callback uses `http://127.0.0.1:<port>/webhook`.
- Inside OpenClaw Docker, `127.0.0.1` points to the container itself, not your host Paperclip server.
- For invite/onboarding URLs consumed by OpenClaw in Docker, use the script-printed Paperclip URL (typically `http://host.docker.internal:3100`).
- If Paperclip rejects the container-visible host with a hostname error, allow it from host:
```bash
pnpm paperclipai allowed-hostname host.docker.internal
```
Then restart Paperclip and rerun the smoke script.
- Docker/remote OpenClaw: prefer a reachable hostname (Docker host alias, Tailscale hostname, or public domain).
- Authenticated/private mode: ensure hostnames are in the allowed list when required:
```bash
pnpm paperclipai allowed-hostname <host>
```
## Prerequisites
- **Docker Desktop v29+** (with Docker Sandbox support)
- **2 GB+ RAM** available for the Docker image build
- **API keys** in `~/.secrets` (at minimum `OPENAI_API_KEY`)
## Option A: Docker Sandbox (Recommended)
Docker Sandbox provides better isolation (microVM-based) and simpler setup than Docker Compose. Requires Docker Desktop v29+ / Docker Sandbox v0.12+.
```bash
# 1. Clone the OpenClaw repo and build the image
git clone https://github.com/openclaw/openclaw.git /tmp/openclaw-docker
cd /tmp/openclaw-docker
docker build -t openclaw:local -f Dockerfile .
# 2. Create the sandbox using the built image
docker sandbox create --name openclaw -t openclaw:local shell ~/.openclaw/workspace
# 3. Allow network access to OpenAI API
docker sandbox network proxy openclaw \
--allow-host api.openai.com \
--allow-host localhost
# 4. Write the config inside the sandbox
docker sandbox exec openclaw sh -c '
mkdir -p /home/node/.openclaw/workspace /home/node/.openclaw/identity /home/node/.openclaw/credentials
cat > /home/node/.openclaw/openclaw.json << INNEREOF
{
"gateway": {
"mode": "local",
"port": 18789,
"bind": "loopback",
"auth": {
"mode": "token",
"token": "sandbox-dev-token-12345"
},
"controlUi": { "enabled": true }
},
"agents": {
"defaults": {
"model": {
"primary": "openai/gpt-5.2",
"fallbacks": ["openai/gpt-5.2-chat-latest"]
},
"workspace": "/home/node/.openclaw/workspace"
}
}
}
INNEREOF
chmod 600 /home/node/.openclaw/openclaw.json
'
# 5. Start the gateway (pass your API key from ~/.secrets)
source ~/.secrets
docker sandbox exec -d \
-e OPENAI_API_KEY="$OPENAI_API_KEY" \
-w /app openclaw \
node dist/index.js gateway --bind loopback --port 18789
# 6. Wait ~15 seconds, then verify
sleep 15
docker sandbox exec openclaw curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:18789/
# Should print: 200
# 7. Check status
docker sandbox exec -e OPENAI_API_KEY="$OPENAI_API_KEY" -w /app openclaw \
node dist/index.js status
```
### Sandbox Management
```bash
# List sandboxes
docker sandbox ls
# Shell into the sandbox
docker sandbox exec -it openclaw bash
# Stop the sandbox (preserves state)
docker sandbox stop openclaw
# Remove the sandbox
docker sandbox rm openclaw
# Check sandbox version
docker sandbox version
```
## Option B: Docker Compose (Fallback)
Use this if Docker Sandbox is not available (Docker Desktop < v29).
```bash
# 1. Clone the OpenClaw repo
git clone https://github.com/openclaw/openclaw.git /tmp/openclaw-docker
cd /tmp/openclaw-docker
# 2. Build the Docker image (~5-10 min on first run)
docker build -t openclaw:local -f Dockerfile .
# 3. Create config directories
mkdir -p ~/.openclaw/workspace ~/.openclaw/identity ~/.openclaw/credentials
chmod 700 ~/.openclaw ~/.openclaw/credentials
# 4. Generate a gateway token
export OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)
echo "Your gateway token: $OPENCLAW_GATEWAY_TOKEN"
# 5. Create the config file
cat > ~/.openclaw/openclaw.json << EOF
{
"gateway": {
"mode": "local",
"port": 18789,
"bind": "lan",
"auth": {
"mode": "token",
"token": "$OPENCLAW_GATEWAY_TOKEN"
},
"controlUi": {
"enabled": true,
"allowedOrigins": ["http://127.0.0.1:18789"]
}
},
"env": {
"OPENAI_API_KEY": "\${OPENAI_API_KEY}"
},
"agents": {
"defaults": {
"model": {
"primary": "openai/gpt-5.2",
"fallbacks": ["openai/gpt-5.2-chat-latest"]
},
"workspace": "/home/node/.openclaw/workspace"
}
}
}
EOF
chmod 600 ~/.openclaw/openclaw.json
# 6. Create the .env file (load API keys from ~/.secrets)
source ~/.secrets
cat > .env << EOF
OPENCLAW_CONFIG_DIR=$HOME/.openclaw
OPENCLAW_WORKSPACE_DIR=$HOME/.openclaw/workspace
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_BRIDGE_PORT=18790
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_GATEWAY_TOKEN=$OPENCLAW_GATEWAY_TOKEN
OPENCLAW_IMAGE=openclaw:local
OPENAI_API_KEY=$OPENAI_API_KEY
OPENCLAW_EXTRA_MOUNTS=
OPENCLAW_HOME_VOLUME=
OPENCLAW_DOCKER_APT_PACKAGES=
EOF
# 7. Add tmpfs to docker-compose.yml (required — see Known Issues)
# Add to BOTH openclaw-gateway and openclaw-cli services:
# tmpfs:
# - /tmp:exec,size=512M
# 8. Start the gateway
docker compose up -d openclaw-gateway
# 9. Wait ~15 seconds for startup, then get the dashboard URL
sleep 15
docker compose run --rm openclaw-cli dashboard --no-open
```
The dashboard URL will look like: `http://127.0.0.1:18789/#token=<your-token>`
### Docker Compose Management
```bash
cd /tmp/openclaw-docker
# Stop
docker compose down
# Start again (no rebuild needed)
docker compose up -d openclaw-gateway
# View logs
docker compose logs -f openclaw-gateway
# Check status
docker compose run --rm openclaw-cli status
# Get dashboard URL
docker compose run --rm openclaw-cli dashboard --no-open
```
## Known Issues and Fixes
### "no space left on device" when starting containers
Docker Desktop's virtual disk may be full.
```bash
docker system df # check usage
docker system prune -f # remove stopped containers, unused networks
docker image prune -f # remove dangling images
```
### "Unable to create fallback OpenClaw temp dir: /tmp/openclaw-1000" (Compose only)
The container can't write to `/tmp`. Add a `tmpfs` mount to `docker-compose.yml` for **both** services:
```yaml
services:
openclaw-gateway:
tmpfs:
- /tmp:exec,size=512M
openclaw-cli:
tmpfs:
- /tmp:exec,size=512M
```
This issue does not affect the Docker Sandbox approach.
### Node version mismatch in community template images
Some community-built sandbox templates (e.g. `olegselajev241/openclaw-dmr:latest`) ship Node 20, but OpenClaw requires Node >=22.12.0. Use our locally built `openclaw:local` image as the sandbox template instead, which includes Node 22.
### Gateway takes ~15 seconds to respond after start
The Node.js gateway needs time to initialize. Wait 15 seconds before hitting `http://127.0.0.1:18789/`.
### CLAUDE_AI_SESSION_KEY warnings (Compose only)
These Docker Compose warnings are harmless and can be ignored:
```
level=warning msg="The \"CLAUDE_AI_SESSION_KEY\" variable is not set. Defaulting to a blank string."
```
## Configuration
Config file: `~/.openclaw/openclaw.json` (JSON5 format)
Key settings:
- `gateway.auth.token` — the auth token for the web UI and API
- `agents.defaults.model.primary` — the AI model (use `openai/gpt-5.2` or newer)
- `env.OPENAI_API_KEY` — references the `OPENAI_API_KEY` env var (Compose approach)
API keys are stored in `~/.secrets` and passed into containers via env vars.
## Reference
- [OpenClaw Docker docs](https://docs.openclaw.ai/install/docker)
- [OpenClaw Configuration Reference](https://docs.openclaw.ai/gateway/configuration-reference)
- [Docker blog: Run OpenClaw Securely in Docker Sandboxes](https://www.docker.com/blog/run-openclaw-securely-in-docker-sandboxes/)
- [Docker Sandbox docs](https://docs.docker.com/ai/sandboxes)
- [OpenAI Models](https://platform.openai.com/docs/models) — current models: gpt-5.2, gpt-5.2-chat-latest, gpt-5.2-pro
-6
View File
@@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="140" height="32" viewBox="0 0 140 32" fill="none">
<g stroke-linecap="round" stroke-linejoin="round">
<path stroke="#e4e4e7" stroke-width="2" d="m18 4-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551"/>
</g>
<text x="32" y="22" font-family="system-ui, -apple-system, sans-serif" font-size="18" font-weight="600" fill="#e4e4e7">Paperclip</text>
</svg>

Before

Width:  |  Height:  |  Size: 474 B

-6
View File
@@ -1,6 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="140" height="32" viewBox="0 0 140 32" fill="none">
<g stroke-linecap="round" stroke-linejoin="round">
<path stroke="#18181b" stroke-width="2" d="m18 4-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551"/>
</g>
<text x="32" y="22" font-family="system-ui, -apple-system, sans-serif" font-size="18" font-weight="600" fill="#18181b">Paperclip</text>
</svg>

Before

Width:  |  Height:  |  Size: 474 B

@@ -1,569 +0,0 @@
# Issue Documents Plan
Status: Draft
Owner: Backend + UI + Agent Protocol
Date: 2026-03-13
Primary issue: `PAP-448`
## Summary
Add first-class **documents** to Paperclip as editable, revisioned, company-scoped text artifacts that can be linked to issues.
The first required convention is a document with key `plan`.
This solves the immediate workflow problem in `PAP-448`:
- plans should stop living inside issue descriptions as `<plan>` blocks
- agents and board users should be able to create/update issue documents directly
- `GET /api/issues/:id` should include the full `plan` document and expose the other available documents
- issue detail should render documents under the description
This should be built as the **text-document slice** of the broader artifact system, not as a replacement for attachments/assets.
## Recommended Product Shape
### Documents vs attachments vs artifacts
- **Documents**: editable text content with stable keys and revision history.
- **Attachments**: uploaded/generated opaque files backed by storage (`assets` + `issue_attachments`).
- **Artifacts**: later umbrella/read-model that can unify documents, attachments, previews, and workspace files.
Recommendation:
- implement **issue documents now**
- keep existing attachments as-is
- defer full artifact unification until there is a second real consumer beyond issue documents + attachments
This keeps `PAP-448` focused while still fitting the larger artifact direction.
## Goals
1. Give issues first-class keyed documents, starting with `plan`.
2. Make documents editable by board users and same-company agents with issue access.
3. Preserve change history with append-only revisions.
4. Make the `plan` document automatically available in the normal issue fetch used by agents/heartbeats.
5. Replace the current `<plan>`-in-description convention in skills/docs.
6. Keep the design compatible with a future artifact/deliverables layer.
## Non-Goals
- full collaborative doc editing
- binary-file version history
- browser IDE or workspace editor
- full artifact-system implementation in the same change
- generalized polymorphic relations for every entity type on day one
## Product Decisions
### 1. Keyed issue documents
Each issue can have multiple documents. Each document relation has a stable key:
- `plan`
- `design`
- `notes`
- `report`
- custom keys later
Key rules:
- unique per issue, case-insensitive
- normalized to lowercase slug form
- machine-oriented and stable
- title is separate and user-facing
The `plan` key is conventional and reserved by Paperclip workflow/docs.
### 2. Text-first v1
V1 documents should be text-first, not arbitrary blobs.
Recommended supported formats:
- `markdown`
- `plain_text`
- `json`
- `html`
Recommendation:
- optimize UI for `markdown`
- allow raw editing for the others
- keep PDFs/images/CSVs/etc as attachments/artifacts, not editable documents
### 3. Revision model
Every document update creates a new immutable revision.
The current document row stores the latest snapshot for fast reads.
### 4. Concurrency model
Do not use silent last-write-wins.
Updates should include `baseRevisionId`:
- create: no base revision required
- update: `baseRevisionId` must match current latest revision
- mismatch: return `409 Conflict`
This is important because both board users and agents may edit the same document.
### 5. Issue fetch behavior
`GET /api/issues/:id` should include:
- full `planDocument` when a `plan` document exists
- `documentSummaries` for all linked documents
It should not inline every document body by default.
This keeps issue fetches useful for agents without making every issue payload unbounded.
### 6. Legacy `<plan>` compatibility
If an issue has no `plan` document but its description contains a legacy `<plan>` block:
- expose that as a legacy read-only fallback in API/UI
- mark it as legacy/synthetic
- prefer a real `plan` document when both exist
Recommendation:
- do not auto-rewrite old issue descriptions in the first rollout
- provide an explicit import/migrate path later
## Proposed Data Model
Recommendation: make documents first-class, but keep issue linkage explicit via a join table.
This preserves foreign keys today and gives a clean path to future `project_documents` or `company_documents` tables later.
## Tables
### `documents`
Canonical text document record.
Suggested columns:
- `id`
- `company_id`
- `title`
- `format`
- `latest_body`
- `latest_revision_id`
- `latest_revision_number`
- `created_by_agent_id`
- `created_by_user_id`
- `updated_by_agent_id`
- `updated_by_user_id`
- `created_at`
- `updated_at`
### `document_revisions`
Append-only history.
Suggested columns:
- `id`
- `company_id`
- `document_id`
- `revision_number`
- `body`
- `change_summary`
- `created_by_agent_id`
- `created_by_user_id`
- `created_at`
Constraints:
- unique `(document_id, revision_number)`
### `issue_documents`
Issue relation + workflow key.
Suggested columns:
- `id`
- `company_id`
- `issue_id`
- `document_id`
- `key`
- `created_at`
- `updated_at`
Constraints:
- unique `(company_id, issue_id, key)`
- unique `(document_id)` to keep one issue relation per document in v1
## Why not use `assets` for this?
Because `assets` solves blob storage, not:
- stable keyed semantics like `plan`
- inline text editing
- revision history
- optimistic concurrency
- cheap inclusion in `GET /issues/:id`
Documents and attachments should remain separate primitives, then meet later in a deliverables/artifact read-model.
## Shared Types and API Contract
## New shared types
Add:
- `DocumentFormat`
- `IssueDocument`
- `IssueDocumentSummary`
- `DocumentRevision`
Recommended `IssueDocument` shape:
```ts
type DocumentFormat = "markdown" | "plain_text" | "json" | "html";
interface IssueDocument {
id: string;
companyId: string;
issueId: string;
key: string;
title: string | null;
format: DocumentFormat;
body: string;
latestRevisionId: string;
latestRevisionNumber: number;
createdByAgentId: string | null;
createdByUserId: string | null;
updatedByAgentId: string | null;
updatedByUserId: string | null;
createdAt: Date;
updatedAt: Date;
}
```
Recommended `IssueDocumentSummary` shape:
```ts
interface IssueDocumentSummary {
id: string;
key: string;
title: string | null;
format: DocumentFormat;
latestRevisionId: string;
latestRevisionNumber: number;
updatedAt: Date;
}
```
## Issue type enrichment
Extend `Issue` with:
```ts
interface Issue {
...
planDocument?: IssueDocument | null;
documentSummaries?: IssueDocumentSummary[];
legacyPlanDocument?: {
key: "plan";
body: string;
source: "issue_description";
} | null;
}
```
This directly satisfies the `PAP-448` requirement for heartbeat/API issue fetches.
## API endpoints
Recommended endpoints:
- `GET /api/issues/:issueId/documents`
- `GET /api/issues/:issueId/documents/:key`
- `PUT /api/issues/:issueId/documents/:key`
- `GET /api/issues/:issueId/documents/:key/revisions`
- `DELETE /api/issues/:issueId/documents/:key` optionally board-only in v1
Recommended `PUT` body:
```ts
{
title?: string | null;
format: "markdown" | "plain_text" | "json" | "html";
body: string;
changeSummary?: string | null;
baseRevisionId?: string | null;
}
```
Behavior:
- missing document + no `baseRevisionId`: create
- existing document + matching `baseRevisionId`: update
- existing document + stale `baseRevisionId`: `409`
## Authorization and invariants
- all document records are company-scoped
- issue relation must belong to same company
- board access follows existing issue access rules
- agent access follows existing same-company issue access rules
- every mutation writes activity log entries
Recommended delete rule for v1:
- board can delete documents
- agents can create/update, but not delete
That keeps automated systems from removing canonical docs too easily.
## UI Plan
## Issue detail
Add a new **Documents** section directly under the issue description.
Recommended behavior:
- show `plan` first when present
- show other documents below it
- render a gist-like header:
- key
- title
- last updated metadata
- revision number
- support inline edit
- support create new document by key
- support revision history drawer or sheet
Recommended presentation order:
1. Description
2. Documents
3. Attachments
4. Comments / activity / sub-issues
This matches the request that documents live under the description while still leaving attachments available.
## Editing UX
Recommendation:
- use markdown preview + raw edit toggle for markdown docs
- use raw textarea editor for non-markdown docs in v1
- show explicit save conflicts on `409`
- show a clear empty state: "No documents yet"
## Legacy plan rendering
If there is no stored `plan` document but legacy `<plan>` exists:
- show it in the Documents section
- mark it `Legacy plan from description`
- offer create/import in a later pass
## Agent Protocol and Skills
Update the Paperclip agent workflow so planning no longer edits the issue description.
Required changes:
- update `skills/paperclip/SKILL.md`
- replace the `<plan>` instructions with document creation/update instructions
- document the new endpoints in `docs/api/issues.md`
- update any internal planning docs that still teach inline `<plan>` blocks
New rule:
- when asked to make a plan for an issue, create or update the issue document with key `plan`
- leave a comment that the plan document was created/updated
- do not mark the issue done
## Relationship to the Artifact Plan
This work should explicitly feed the broader artifact/deliverables direction.
Recommendation:
- keep documents as their own primitive in this change
- add `document` to any future `ArtifactKind`
- later build a deliverables read-model that aggregates:
- issue documents
- issue attachments
- preview URLs
- workspace-file references
The artifact proposal currently has no explicit `document` kind. It should.
Recommended future shape:
```ts
type ArtifactKind =
| "document"
| "attachment"
| "workspace_file"
| "preview"
| "report_link";
```
## Implementation Phases
## Phase 1: Shared contract and schema
Files:
- `packages/db/src/schema/documents.ts`
- `packages/db/src/schema/document_revisions.ts`
- `packages/db/src/schema/issue_documents.ts`
- `packages/db/src/schema/index.ts`
- `packages/db/src/migrations/*`
- `packages/shared/src/types/issue.ts`
- `packages/shared/src/validators/issue.ts` or new document validator file
- `packages/shared/src/index.ts`
Acceptance:
- schema enforces one key per issue
- revisions are append-only
- shared types expose plan/document fields on issue fetch
## Phase 2: Server services and routes
Files:
- `server/src/services/issues.ts` or `server/src/services/documents.ts`
- `server/src/routes/issues.ts`
- `server/src/services/activity.ts` callsites
Behavior:
- list/get/upsert/delete documents
- revision listing
- `GET /issues/:id` returns `planDocument` + `documentSummaries`
- company boundary checks match issue routes
Acceptance:
- agents and board can fetch/update same-company issue documents
- stale edits return `409`
- activity timeline shows document changes
## Phase 3: UI issue documents surface
Files:
- `ui/src/api/issues.ts`
- `ui/src/lib/queryKeys.ts`
- `ui/src/pages/IssueDetail.tsx`
- new reusable document UI component if needed
Behavior:
- render plan + documents under description
- create/update by key
- open revision history
- show conflicts/errors clearly
Acceptance:
- board can create a `plan` doc from issue detail
- updated plan appears immediately
- issue detail no longer depends on description-embedded `<plan>`
## Phase 4: Skills/docs migration
Files:
- `skills/paperclip/SKILL.md`
- `docs/api/issues.md`
- `doc/SPEC-implementation.md`
- relevant plan/docs that mention `<plan>`
Acceptance:
- planning guidance references issue documents, not inline issue description tags
- API docs describe the new document endpoints and issue payload additions
## Phase 5: Legacy compatibility and follow-up
Behavior:
- read legacy `<plan>` blocks as fallback
- optionally add explicit import/migration command later
Follow-up, not required for first merge:
- deliverables/artifact read-model
- project/company documents
- comment-linked documents
- diff view between revisions
## Test Plan
### Server
- document create/read/update/delete lifecycle
- revision numbering
- `baseRevisionId` conflict handling
- company boundary enforcement
- agent vs board authorization
- issue fetch includes `planDocument` and document summaries
- legacy `<plan>` fallback behavior
- activity log mutation coverage
### UI
- issue detail shows plan document
- create/update flows invalidate queries correctly
- conflict and validation errors are surfaced
- legacy plan fallback renders correctly
### Verification
Run before implementation is declared complete:
```sh
pnpm -r typecheck
pnpm test:run
pnpm build
```
## Open Questions
1. Should v1 documents be markdown-only, with `json/html/plain_text` deferred?
Recommendation: allow all four in API, optimize UI for markdown only.
2. Should agents be allowed to create arbitrary keys, or only conventional keys?
Recommendation: allow arbitrary keys with normalized validation; reserve `plan` as special behavior only.
3. Should delete exist in v1?
Recommendation: yes, but board-only.
4. Should legacy `<plan>` blocks ever be auto-migrated?
Recommendation: no automatic mutation in the first rollout.
5. Should documents appear inside a future Deliverables section or remain a top-level Issue section?
Recommendation: keep a dedicated Documents section now; later also expose them in Deliverables if an aggregated artifact view is added.
## Final Recommendation
Ship **issue documents** as a focused, text-first primitive now.
Do not try to solve full artifact unification in the same implementation.
Use:
- first-class document tables
- issue-level keyed linkage
- append-only revisions
- `planDocument` embedded in normal issue fetches
- legacy `<plan>` fallback
- skill/docs migration away from description-embedded plans
This addresses the real planning workflow problem immediately and leaves the artifact system room to grow cleanly afterward.
File diff suppressed because it is too large. Load diff
-286
View File
@@ -1,286 +0,0 @@
# Agent Configuration & Activity UI
## Context
Agents are the employees of a Paperclip company. Each agent has an adapter type (`claude_local`, `codex_local`, `process`, `http`) that determines how it runs, a position in the org chart (who it reports to), a heartbeat policy (how/when it wakes up), and a budget. The UI at `/agents` needs to support creating and configuring agents, viewing their org hierarchy, and inspecting what they've been doing -- their run history, live logs, and accumulated costs.
This spec covers three surfaces:
1. **Agent Creation Dialog** -- the "New Agent" flow
2. **Agent Detail Page** -- configuration, activity, and logs
3. **Agents List Page** -- improvements to the existing list
---
## 1. Agent Creation Dialog
Follows the existing `NewIssueDialog` / `NewProjectDialog` pattern: a `Dialog` component with expand/minimize toggle, company badge breadcrumb, and Cmd+Enter submit.
### Fields
**Identity (always visible):**
| Field | Control | Required | Default | Notes |
|-------|---------|----------|---------|-------|
| Name | Text input (large, auto-focused) | Yes | -- | e.g. "Alice", "Build Bot" |
| Title | Text input (subtitle style) | No | -- | e.g. "VP of Engineering" |
| Role | Chip popover (select) | No | `general` | Values from `AGENT_ROLES`: ceo, cto, cmo, cfo, engineer, designer, pm, qa, devops, researcher, general |
| Reports To | Chip popover (agent select) | No | -- | Dropdown of existing agents in the company. If this is the first agent, auto-set role to `ceo` and gray out Reports To. Otherwise required unless role is `ceo`. |
| Capabilities | Text input | No | -- | Free-text description of what this agent can do |
**Adapter (collapsible section, default open):**
| Field | Control | Default | Notes |
|-------|---------|---------|-------|
| Adapter Type | Chip popover (select) | `claude_local` | `claude_local`, `codex_local`, `process`, `http` |
| Test environment | Button | -- | Runs adapter-specific diagnostics and returns pass/warn/fail checks for current unsaved config |
| CWD | Text input | -- | Working directory for local adapters |
| Prompt Template | Textarea | -- | Supports `{{ agent.id }}`, `{{ agent.name }}` etc. |
| Model | Text input | -- | Optional model override |
**Adapter-specific fields (shown/hidden based on adapter type):**
*claude_local:*
| Field | Control | Default |
|-------|---------|---------|
| Max Turns Per Run | Number input | 80 |
| Skip Permissions | Toggle | true |
*codex_local:*
| Field | Control | Default |
|-------|---------|---------|
| Search | Toggle | false |
| Bypass Sandbox | Toggle | true |
*process:*
| Field | Control | Default |
|-------|---------|---------|
| Command | Text input | -- |
| Args | Text input (comma-separated) | -- |
*http:*
| Field | Control | Default |
|-------|---------|---------|
| URL | Text input | -- |
| Method | Select | POST |
| Headers | Key-value pairs | -- |
**Runtime (collapsible section, default collapsed):**
| Field | Control | Default |
|-------|---------|---------|
| Context Mode | Chip popover | `thin` |
| Monthly Budget (cents) | Number input | 0 |
| Timeout (sec) | Number input | 900 |
| Grace Period (sec) | Number input | 15 |
| Extra Args | Text input | -- |
| Env Vars | Key-value pair editor | -- |
**Heartbeat Policy (collapsible section, default collapsed):**
| Field | Control | Default |
|-------|---------|---------|
| Enabled | Toggle | true |
| Interval (sec) | Number input | 300 |
| Wake on Assignment | Toggle | true |
| Wake on On-Demand | Toggle | true |
| Wake on Automation | Toggle | true |
| Cooldown (sec) | Number input | 10 |
### Behavior
- On submit, calls `agentsApi.create(companyId, data)` where `data` packs identity fields at the top level and adapter-specific fields into `adapterConfig` and heartbeat/runtime into `runtimeConfig`.
- After creation, navigate to the new agent's detail page.
- If the company has zero agents, pre-fill role as `ceo` and disable Reports To.
- The adapter config section updates its visible fields when adapter type changes, preserving any shared field values (cwd, promptTemplate, etc.).
---
## 2. Agent Detail Page
Restructure the existing tabbed layout. Keep the header (name, role, title, status badge, action buttons) and add richer tabs.
### Header
```
[StatusBadge] Agent Name [Invoke] [Pause/Resume] [...]
Role / Title
```
The `[...]` overflow menu contains: Terminate, Reset Session, Create API Key.
### Tabs
#### Overview Tab
Two-column layout: left column is a summary card, right column is the org position.
**Summary card:**
- Adapter type + model (if set)
- Heartbeat interval (e.g. "every 5 min") or "Disabled"
- Last heartbeat time (relative, e.g. "3 min ago")
- Session status: "Active (session abc123...)" or "No session"
- Current month spend / budget with progress bar
**Org position card:**
- Reports to: clickable agent name (links to their detail page)
- Direct reports: list of agents who report to this agent (clickable)
#### Configuration Tab
Editable form with the same sections as the creation dialog (Adapter, Runtime, Heartbeat Policy) but pre-populated with current values. Uses inline editing -- click a value to edit, press Enter or blur to save via `agentsApi.update()`.
Sections:
- **Identity**: name, title, role, reports to, capabilities
- **Adapter Config**: all adapter-specific fields for the current adapter type
- **Heartbeat Policy**: enable/disable, interval, wake-on triggers, cooldown
- **Runtime**: context mode, budget, timeout, grace, env vars, extra args
Each section is a collapsible card. Save happens per-field (PATCH on blur/enter), not a single form submit. Validation errors show inline.
#### Runs Tab
This is the primary activity/history view. Shows a paginated list of heartbeat runs, most recent first.
**Run list item:**
```
[StatusIcon] #run-id-short source: timer 2 min ago 1.2k tokens $0.03
"Reviewed 3 PRs and filed 2 issues"
```
Fields per row:
- Status icon (green check = succeeded, red X = failed, yellow spinner = running, gray clock = queued, orange timeout = timed_out, slash = cancelled)
- Run ID (short, first 8 chars)
- Invocation source chip (timer, assignment, on_demand, automation)
- Relative timestamp
- Token usage summary (total input + output)
- Cost
- Result summary (first line of result or error)
**Clicking a run** opens a run detail inline (accordion expand) or a slide-over panel showing:
- Full status timeline (queued -> running -> outcome) with timestamps
- Session before/after
- Token breakdown: input, output, cached input
- Cost breakdown
- Error message and error code (if failed)
- Exit code and signal (if applicable)
**Log viewer** within the run detail:
- Streams `heartbeat_run_events` for the run, ordered by `seq`
- Each event rendered as a log line with timestamp, level (color-coded), and message
- Events of type `stdout`/`stderr` shown in monospace
- System events shown with distinct styling
- For running runs, auto-scrolls and appends live via WebSocket events (`heartbeat.run.event`, `heartbeat.run.log`)
- "View full log" link fetches from `heartbeatsApi.log(runId)` and shows in a scrollable monospace container
- Truncation: show last 200 events by default, "Load more" button to fetch earlier events
#### Issues Tab
Keep as-is: list of issues assigned to this agent with status, clickable to navigate to issue detail.
#### Costs Tab
Expand the existing costs tab:
- **Cumulative totals** from `agent_runtime_state`: total input tokens, total output tokens, total cached tokens, total cost
- **Monthly budget** progress bar (current month spend vs budget)
- **Per-run cost table**: date, run ID, tokens in/out/cached, cost -- sortable by date or cost
- **Chart** (stretch): simple bar chart of daily spend over last 30 days
### Properties Panel (Right Sidebar)
The existing `AgentProperties` panel continues to show the quick-glance info. Add:
- Session ID (truncated, with copy button)
- Last error (if any, in red)
- Link to "View Configuration" (scrolls to / switches to Configuration tab)
---
## 3. Agents List Page
### Current state
Shows a flat list of agents with status badge, name, role, title, and budget bar.
### Improvements
**Add "New Agent" button** in the header (Plus icon + "New Agent"), opens the creation dialog.
**Add view toggle**: List view (current) and Org Chart view.
**Org Chart view:**
- Tree layout showing reporting hierarchy
- Each node shows: agent name, role, status badge
- CEO at the top, direct reports below, etc.
- Uses the `agentsApi.org(companyId)` endpoint which already returns `OrgNode[]`
- Clicking a node navigates to agent detail
**List view improvements:**
- Add adapter type as a small chip/tag on each row
- Add "last active" relative timestamp
- Add running indicator (animated dot) if agent currently has a running heartbeat
**Filtering:**
- Tab filters: All, Active, Paused, Error (similar to Issues page pattern)
---
## 4. Component Inventory
New components needed:
| Component | Purpose |
|-----------|---------|
| `NewAgentDialog` | Agent creation form dialog |
| `AgentConfigForm` | Shared form sections for create + edit (adapter, heartbeat, runtime) |
| `AdapterConfigFields` | Conditional fields based on adapter type |
| `HeartbeatPolicyFields` | Heartbeat configuration fields |
| `EnvVarEditor` | Key-value pair editor for environment variables |
| `RunListItem` | Single run row in the runs list |
| `RunDetail` | Expanded run detail with log viewer |
| `LogViewer` | Streaming log viewer with auto-scroll |
| `OrgChart` | Tree visualization of agent hierarchy |
| `AgentSelect` | Reusable agent picker (for Reports To, etc.) |
Reused existing components:
- `StatusBadge`, `EntityRow`, `EmptyState`, `PropertyRow`
- shadcn: `Dialog`, `Tabs`, `Button`, `Popover`, `Command`, `Separator`, `Toggle`
---
## 5. API Surface
All endpoints already exist. No new server work needed for V1.
| Action | Endpoint | Used by |
|--------|----------|---------|
| List agents | `GET /companies/:id/agents` | List page |
| Get org tree | `GET /companies/:id/org` | Org chart view |
| Create agent | `POST /companies/:id/agents` | Creation dialog |
| Update agent | `PATCH /agents/:id` | Configuration tab |
| Pause/Resume/Terminate | `POST /agents/:id/{action}` | Header actions |
| Reset session | `POST /agents/:id/runtime-state/reset-session` | Overflow menu |
| Create API key | `POST /agents/:id/keys` | Overflow menu |
| Get runtime state | `GET /agents/:id/runtime-state` | Overview tab, properties panel |
| Invoke/Wakeup | `POST /agents/:id/heartbeat/invoke` | Header invoke button |
| List runs | `GET /companies/:id/heartbeat-runs?agentId=X` | Runs tab |
| Cancel run | `POST /heartbeat-runs/:id/cancel` | Run detail |
| Run events | `GET /heartbeat-runs/:id/events` | Log viewer |
| Run log | `GET /heartbeat-runs/:id/log` | Full log view |
---
## 6. Implementation Order
1. **New Agent Dialog** -- unblocks agent creation from the UI
2. **Agents List improvements** -- add New Agent button, tab filters, adapter chip, running indicator
3. **Agent Detail: Configuration tab** -- editable adapter/heartbeat/runtime config
4. **Agent Detail: Runs tab** -- run history list with status, tokens, cost
5. **Agent Detail: Run Detail + Log Viewer** -- expandable run detail with streaming logs
6. **Agent Detail: Overview tab** -- summary card, org position
7. **Agent Detail: Costs tab** -- expanded cost breakdown
8. **Org Chart view** -- tree visualization on list page
9. **Properties panel updates** -- session ID, last error
Steps 1-5 are the core. Steps 6-9 are polish.
-526
View File
@@ -1,526 +0,0 @@
# ClipHub: Marketplace for Paperclip Team Configurations
> Supersession note: this marketplace plan predates the markdown-first company package direction. For the current package-format and import/export rollout plan, see `doc/plans/2026-03-13-company-import-export-v2.md` and `docs/companies/companies-spec.md`.
> The "app store" for whole-company AI teams — pre-built Paperclip configurations, agent blueprints, skills, and governance templates that ship real work from day one.
## 1. Vision & Positioning
**ClipHub** sells **entire team configurations** — org charts, agent roles, inter-agent workflows, governance rules, and project templates — for Paperclip-managed companies.
| Dimension | ClipHub |
|---|---|
| Unit of sale | Team blueprint (multi-agent org) |
| Buyer | Founder / team lead spinning up an AI company |
| Install target | Paperclip company (agents, projects, governance) |
| Value prop | "Skip org design — get a shipping team in minutes" |
| Price range | $0–$499 per blueprint (+ individual add-ons) |
---
## 2. Product Taxonomy
### 2.1 Team Blueprints (primary product)
A complete Paperclip company configuration:
- **Org chart**: Agents with roles, titles, reporting chains, capabilities
- **Agent configs**: Adapter type, model, prompt templates, instructions paths
- **Governance rules**: Approval flows, budget limits, escalation chains
- **Project templates**: Pre-configured projects with workspace settings
- **Skills & instructions**: AGENTS.md / skill files bundled per agent
**Examples:**
- "SaaS Startup Team" — CEO, CTO, Engineer, CMO, Designer ($199)
- "Content Agency" — Editor-in-Chief, 3 Writers, SEO Analyst, Social Manager ($149)
- "Dev Shop" — CTO, 2 Engineers, QA, DevOps ($99)
- "Solo Founder + Crew" — CEO agent + 3 ICs across eng/marketing/ops ($79)
### 2.2 Agent Blueprints (individual agents within a team context)
Single-agent configurations designed to plug into a Paperclip org:
- Role definition, prompt template, adapter config
- Reporting chain expectations (who they report to)
- Skill bundles included
- Governance defaults (budget, permissions)
**Examples:**
- "Staff Engineer" — ships production code, manages PRs ($29)
- "Growth Marketer" — content pipeline, SEO, social ($39)
- "DevOps Agent" — CI/CD, deployment, monitoring ($29)
### 2.3 Skills (modular capabilities)
Portable skill files that any Paperclip agent can use:
- Markdown skill files with instructions
- Tool configurations and shell scripts
- Compatible with Paperclip's skill loading system
**Examples:**
- "Git PR Workflow" — standardized PR creation and review (Free)
- "Deployment Pipeline" — Cloudflare/Vercel deploy skill ($9)
- "Customer Support Triage" — ticket classification and routing ($19)
### 2.4 Governance Templates
Pre-built approval flows and policies:
- Budget thresholds and approval chains
- Cross-team delegation rules
- Escalation procedures
- Billing code structures
**Examples:**
- "Startup Governance" — lightweight, CEO approves > $50 (Free)
- "Enterprise Governance" — multi-tier approval, audit trail ($49)
---
## 3. Data Schemas
### 3.1 Listing
```typescript
interface Listing {
id: string;
slug: string; // URL-friendly identifier
type: 'team_blueprint' | 'agent_blueprint' | 'skill' | 'governance_template';
title: string;
tagline: string; // Short pitch (≤120 chars)
description: string; // Markdown, full details
// Pricing
price: number; // Cents (0 = free)
currency: 'usd';
// Creator
creatorId: string;
creatorName: string;
creatorAvatar: string | null;
// Categorization
categories: string[]; // e.g. ['saas', 'engineering', 'marketing']
tags: string[]; // e.g. ['claude', 'startup', '5-agent']
agentCount: number | null; // For team blueprints
// Content
previewImages: string[]; // Screenshots / org chart visuals
readmeMarkdown: string; // Full README shown on detail page
includedFiles: string[]; // List of files in the bundle
// Compatibility
compatibleAdapters: string[]; // ['claude_local', 'codex_local', ...]
requiredModels: string[]; // ['claude-opus-4-6', 'claude-sonnet-4-6']
paperclipVersionMin: string; // Minimum Paperclip version
// Social proof
installCount: number;
rating: number | null; // 1.0–5.0
reviewCount: number;
// Metadata
version: string; // Semver
publishedAt: string;
updatedAt: string;
status: 'draft' | 'published' | 'archived';
}
```
### 3.2 Team Blueprint Bundle
```typescript
interface TeamBlueprint {
listingId: string;
// Org structure
agents: AgentBlueprint[];
reportingChain: { agentSlug: string; reportsTo: string | null }[];
// Governance
governance: {
approvalRules: ApprovalRule[];
budgetDefaults: { role: string; monthlyCents: number }[];
escalationChain: string[]; // Agent slugs in escalation order
};
// Projects
projects: ProjectTemplate[];
// Company-level config
companyDefaults: {
name: string;
defaultModel: string;
defaultAdapter: string;
};
}
interface AgentBlueprint {
slug: string; // e.g. 'cto', 'engineer-1'
name: string;
role: string;
title: string;
icon: string;
capabilities: string;
promptTemplate: string;
adapterType: string;
adapterConfig: Record<string, any>;
instructionsPath: string | null; // Path to AGENTS.md or similar
skills: SkillBundle[];
budgetMonthlyCents: number;
permissions: {
canCreateAgents: boolean;
canApproveHires: boolean;
};
}
interface ProjectTemplate {
name: string;
description: string;
workspace: {
cwd: string | null;
repoUrl: string | null;
} | null;
}
interface ApprovalRule {
trigger: string; // e.g. 'hire_agent', 'budget_exceed'
threshold: number | null;
approverRole: string;
}
```
### 3.3 Creator / Seller
```typescript
interface Creator {
id: string;
userId: string; // Auth provider ID
displayName: string;
bio: string;
avatarUrl: string | null;
website: string | null;
listings: string[]; // Listing IDs
totalInstalls: number;
totalRevenue: number; // Cents earned
joinedAt: string;
verified: boolean;
payoutMethod: 'stripe_connect';
stripeAccountId: string | null;
}
```
### 3.4 Purchase / Install
```typescript
interface Purchase {
id: string;
listingId: string;
buyerUserId: string;
buyerCompanyId: string | null; // Target Paperclip company
pricePaidCents: number;
paymentIntentId: string | null; // Stripe
installedAt: string | null; // When deployed to company
status: 'pending' | 'completed' | 'refunded';
createdAt: string;
}
```
### 3.5 Review
```typescript
interface Review {
id: string;
listingId: string;
authorUserId: string;
authorDisplayName: string;
rating: number; // 1–5
title: string;
body: string; // Markdown
verifiedPurchase: boolean;
createdAt: string;
updatedAt: string;
}
```
---
## 4. Pages & Routes
### 4.1 Public Pages
| Route | Page | Description |
|---|---|---|
| `/` | Homepage | Hero, featured blueprints, popular skills, how it works |
| `/browse` | Marketplace browse | Filterable grid of all listings |
| `/browse?type=team_blueprint` | Team blueprints | Filtered to team configs |
| `/browse?type=agent_blueprint` | Agent blueprints | Single-agent configs |
| `/browse?type=skill` | Skills | Skill listings |
| `/browse?type=governance_template` | Governance | Policy templates |
| `/listings/:slug` | Listing detail | Full product page |
| `/creators/:slug` | Creator profile | Bio, all listings, stats |
| `/about` | About ClipHub | Mission, how it works |
| `/pricing` | Pricing & fees | Creator revenue share, buyer info |
### 4.2 Authenticated Pages
| Route | Page | Description |
|---|---|---|
| `/dashboard` | Buyer dashboard | Purchased items, installed blueprints |
| `/dashboard/purchases` | Purchase history | All transactions |
| `/dashboard/installs` | Installations | Deployed blueprints with status |
| `/creator` | Creator dashboard | Listing management, analytics |
| `/creator/listings/new` | Create listing | Multi-step listing wizard |
| `/creator/listings/:id/edit` | Edit listing | Modify existing listing |
| `/creator/analytics` | Analytics | Revenue, installs, views |
| `/creator/payouts` | Payouts | Stripe Connect payout history |
### 4.3 API Routes
| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/api/listings` | Browse listings (filters: type, category, price range, sort) |
| `GET` | `/api/listings/:slug` | Get listing detail |
| `POST` | `/api/listings` | Create listing (creator auth) |
| `PATCH` | `/api/listings/:id` | Update listing |
| `DELETE` | `/api/listings/:id` | Archive listing |
| `POST` | `/api/listings/:id/purchase` | Purchase listing (Stripe checkout) |
| `POST` | `/api/listings/:id/install` | Install to Paperclip company |
| `GET` | `/api/listings/:id/reviews` | Get reviews |
| `POST` | `/api/listings/:id/reviews` | Submit review |
| `GET` | `/api/creators/:slug` | Creator profile |
| `GET` | `/api/creators/me` | Current creator profile |
| `POST` | `/api/creators` | Register as creator |
| `GET` | `/api/purchases` | Buyer's purchase history |
| `GET` | `/api/analytics` | Creator analytics |
---
## 5. User Flows
### 5.1 Buyer: Browse → Purchase → Install
```
Homepage → Browse marketplace → Filter by type/category
→ Click listing → Read details, reviews, preview org chart
→ Click "Buy" → Stripe checkout (or free install)
→ Post-purchase: "Install to Company" button
→ Select target Paperclip company (or create new)
→ ClipHub API calls Paperclip API to:
1. Create agents with configs from blueprint
2. Set up reporting chains
3. Create projects with workspace configs
4. Apply governance rules
5. Deploy skill files to agent instruction paths
→ Redirect to Paperclip dashboard with new team running
```
### 5.2 Creator: Build → Publish → Earn
```
Sign up as creator → Connect Stripe
→ "New Listing" wizard:
Step 1: Type (team/agent/skill/governance)
Step 2: Basic info (title, tagline, description, categories)
Step 3: Upload bundle (JSON config + skill files + README)
Step 4: Preview & org chart visualization
Step 5: Pricing ($0–$499)
Step 6: Publish
→ Live on marketplace immediately
→ Track installs, revenue, reviews on creator dashboard
```
### 5.3 Creator: Export from Paperclip → Publish
```
Running Paperclip company → "Export as Blueprint" (CLI or UI)
→ Paperclip exports:
- Agent configs (sanitized — no secrets)
- Org chart / reporting chains
- Governance rules
- Project templates
- Skill files
→ Upload to ClipHub as new listing
→ Edit details, set price, publish
```
---
## 6. UI Design Direction
### 6.1 Visual Language
- **Color palette**: Dark ink primary, warm sand backgrounds, accent color for CTAs (Paperclip brand blue/purple)
- **Typography**: Clean sans-serif, strong hierarchy, monospace for technical details
- **Cards**: Rounded corners, subtle shadows, clear pricing badges
- **Org chart visuals**: Interactive tree/graph showing agent relationships in team blueprints
### 6.2 Key Design Elements
| Element | ClipHub |
|---|---|
| Product card | Org chart mini-preview + agent count badge |
| Detail page | Interactive org chart + per-agent breakdown |
| Install flow | One-click deploy to Paperclip company |
| Social proof | "X companies running this blueprint" |
| Preview | Live demo sandbox (stretch goal) |
### 6.3 Listing Card Design
```
┌─────────────────────────────────────┐
│ [Org Chart Mini-Preview] │
│ ┌─CEO─┐ │
│ ├─CTO─┤ │
│ └─ENG──┘ │
│ │
│ SaaS Startup Team │
│ "Ship your MVP with a 5-agent │
│ engineering + marketing team" │
│ │
│ 👥 5 agents ⬇ 234 installs │
│ ★ 4.7 (12 reviews) │
│ │
│ By @masinov $199 [Buy] │
└─────────────────────────────────────┘
```
### 6.4 Detail Page Sections
1. **Hero**: Title, tagline, price, install button, creator info
2. **Org Chart**: Interactive visualization of agent hierarchy
3. **Agent Breakdown**: Expandable cards for each agent — role, capabilities, model, skills
4. **Governance**: Approval flows, budget structure, escalation chain
5. **Included Projects**: Project templates with workspace configs
6. **README**: Full markdown documentation
7. **Reviews**: Star ratings + written reviews
8. **Related Blueprints**: Cross-sell similar team configs
9. **Creator Profile**: Mini bio, other listings
---
## 7. Installation Mechanics
### 7.1 Install API Flow
When a buyer clicks "Install to Company":
```
POST /api/listings/:id/install
{
"targetCompanyId": "uuid", // Existing Paperclip company
"overrides": { // Optional customization
"agentModel": "claude-sonnet-4-6", // Override default model
"budgetScale": 0.5, // Scale budgets
"skipProjects": false
}
}
```
The install handler:
1. Validates buyer owns the purchase
2. Validates target company access
3. For each agent in blueprint:
- `POST /api/companies/:id/agents` (if `paperclip-create-agent` supports it, or via approval flow)
- Sets adapter config, prompt template, instructions path
4. Sets reporting chains
5. Creates projects and workspaces
6. Applies governance rules
7. Deploys skill files to configured paths
8. Returns summary of created resources
### 7.2 Conflict Resolution
- **Agent name collision**: Append `-2`, `-3` suffix
- **Project name collision**: Prompt buyer to rename or skip
- **Adapter mismatch**: Warn if blueprint requires adapter not available locally
- **Model availability**: Warn if required model not configured
---
## 8. Revenue Model
| Fee | Amount | Notes |
|---|---|---|
| Creator revenue share | 90% of sale price | Minus Stripe processing (~2.9% + $0.30) |
| Platform fee | 10% of sale price | ClipHub's cut |
| Free listings | $0 | No fees for free listings |
| Stripe Connect | Standard rates | Handled by Stripe |
---
## 9. Technical Architecture
### 9.1 Stack
- **Frontend**: Next.js (React), Tailwind CSS, same UI framework as Paperclip
- **Backend**: Node.js API (or extend Paperclip server)
- **Database**: Postgres (can share Paperclip's DB or separate)
- **Payments**: Stripe Connect (marketplace mode)
- **Storage**: S3/R2 for listing bundles and images
- **Auth**: Shared with Paperclip auth (or OAuth2)
### 9.2 Integration with Paperclip
ClipHub can be:
- **Option A**: A separate app that calls Paperclip's API to install blueprints
- **Option B**: A built-in section of the Paperclip UI (`/marketplace` route)
Option B is simpler for MVP — adds routes to the existing Paperclip UI and API.
### 9.3 Bundle Format
Listing bundles are ZIP/tar archives containing:
```
blueprint/
├── manifest.json # Listing metadata + agent configs
├── README.md # Documentation
├── org-chart.json # Agent hierarchy
├── governance.json # Approval rules, budgets
├── agents/
│ ├── ceo/
│ │ ├── prompt.md # Prompt template
│ │ ├── AGENTS.md # Instructions
│ │ └── skills/ # Skill files
│ ├── cto/
│ │ ├── prompt.md
│ │ ├── AGENTS.md
│ │ └── skills/
│ └── engineer/
│ ├── prompt.md
│ ├── AGENTS.md
│ └── skills/
└── projects/
└── default/
└── workspace.json # Project workspace config
```
---
## 10. MVP Scope
### Phase 1: Foundation
- [ ] Listing schema and CRUD API
- [ ] Browse page with filters (type, category, price)
- [ ] Listing detail page with org chart visualization
- [ ] Creator registration and listing creation wizard
- [ ] Free installs only (no payments yet)
- [ ] Install flow: blueprint → Paperclip company
### Phase 2: Payments & Social
- [ ] Stripe Connect integration
- [ ] Purchase flow
- [ ] Review system
- [ ] Creator analytics dashboard
- [ ] "Export from Paperclip" CLI command
### Phase 3: Growth
- [ ] Search with relevance ranking
- [ ] Featured/trending listings
- [ ] Creator verification program
- [ ] Blueprint versioning and update notifications
- [ ] Live demo sandbox
- [ ] API for programmatic publishing
-98
View File
@@ -1,98 +0,0 @@
---
title: Architecture
summary: Stack overview, request flow, and adapter model
---
Paperclip is a monorepo with four main layers.
## Stack Overview
```
┌─────────────────────────────────────┐
│ React UI (Vite) │
│ Dashboard, org management, tasks │
├─────────────────────────────────────┤
│ Express.js REST API (Node.js) │
│ Routes, services, auth, adapters │
├─────────────────────────────────────┤
│ PostgreSQL (Drizzle ORM) │
│ Schema, migrations, embedded mode │
├─────────────────────────────────────┤
│ Adapters │
│ Claude Local, Codex Local, │
│ Process, HTTP │
└─────────────────────────────────────┘
```
## Technology Stack
| Layer | Technology |
|-------|-----------|
| Frontend | React 19, Vite 6, React Router 7, Radix UI, Tailwind CSS 4, TanStack Query |
| Backend | Node.js 20+, Express.js 5, TypeScript |
| Database | PostgreSQL 17 (or embedded PGlite), Drizzle ORM |
| Auth | Better Auth (sessions + API keys) |
| Adapters | Claude Code CLI, Codex CLI, shell process, HTTP webhook |
| Package manager | pnpm 9 with workspaces |
## Repository Structure
```
paperclip/
├── ui/ # React frontend
│ ├── src/pages/ # Route pages
│ ├── src/components/ # React components
│ ├── src/api/ # API client
│ └── src/context/ # React context providers
│
├── server/ # Express.js API
│ ├── src/routes/ # REST endpoints
│ ├── src/services/ # Business logic
│ ├── src/adapters/ # Agent execution adapters
│ └── src/middleware/ # Auth, logging
│
├── packages/
│ ├── db/ # Drizzle schema + migrations
│ ├── shared/ # API types, constants, validators
│ ├── adapter-utils/ # Adapter interfaces and helpers
│ └── adapters/
│ ├── claude-local/ # Claude Code adapter
│ └── codex-local/ # OpenAI Codex adapter
│
├── skills/ # Agent skills
│ └── paperclip/ # Core Paperclip skill (heartbeat protocol)
│
├── cli/ # CLI client
│ └── src/ # Setup and control-plane commands
│
└── doc/ # Internal documentation
```
## Request Flow
When a heartbeat fires:
1. **Trigger** — Scheduler, manual invoke, or event (assignment, mention) triggers a heartbeat
2. **Adapter invocation** — Server calls the configured adapter's `execute()` function
3. **Agent process** — Adapter spawns the agent (e.g. Claude Code CLI) with Paperclip env vars and a prompt
4. **Agent work** — The agent calls Paperclip's REST API to check assignments, checkout tasks, do work, and update status
5. **Result capture** — Adapter captures stdout, parses usage/cost data, extracts session state
6. **Run record** — Server records the run result, costs, and any session state for next heartbeat
## Adapter Model
Adapters are the bridge between Paperclip and agent runtimes. Each adapter is a package with three modules:
- **Server module** — `execute()` function that spawns/calls the agent, plus environment diagnostics
- **UI module** — stdout parser for the run viewer, config form fields for agent creation
- **CLI module** — terminal formatter for `paperclipai run --watch`
Built-in adapters: `claude_local`, `codex_local`, `process`, `http`. You can create custom adapters for any runtime.
## Key Design Decisions
- **Control plane, not execution plane** — Paperclip orchestrates agents; it doesn't run them
- **Company-scoped** — all entities belong to exactly one company; strict data boundaries
- **Single-assignee tasks** — atomic checkout prevents concurrent work on the same task
- **Adapter-agnostic** — any runtime that can call an HTTP API works as an agent
- **Embedded by default** — zero-config local mode with embedded PostgreSQL
-86
View File
@@ -1,86 +0,0 @@
---
title: Core Concepts
summary: Companies, agents, issues, delegation, heartbeats, and governance
---
Paperclip organizes autonomous AI work around six key concepts.
## Company
A company is the top-level unit of organization. Each company has:
- A **goal** — the reason it exists (e.g. "Build the #1 AI note-taking app at $1M MRR")
- **Employees** — every employee is an AI agent
- **Org structure** — who reports to whom
- **Budget** — monthly spend limits in cents
- **Task hierarchy** — all work traces back to the company goal
One Paperclip instance can run multiple companies.
## Agents
Every employee is an AI agent. Each agent has:
- **Adapter type + config** — how the agent runs (Claude Code, Codex, shell process, HTTP webhook)
- **Role and reporting** — title, who they report to, who reports to them
- **Capabilities** — a short description of what the agent does
- **Budget** — per-agent monthly spend limit
- **Status** — active, idle, running, error, paused, or terminated
Agents are organized in a strict tree hierarchy. Every agent reports to exactly one manager (except the CEO). This chain of command is used for escalation and delegation.
## Issues (Tasks)
Issues are the unit of work. Every issue has:
- A title, description, status, and priority
- An assignee (one agent at a time)
- A parent issue (creating a traceable hierarchy back to the company goal)
- A project and optional goal association
### Status Lifecycle
```
backlog -> todo -> in_progress -> in_review -> done
|
blocked
```
Terminal states: `done`, `cancelled`.
The transition to `in_progress` requires an **atomic checkout** — only one agent can own a task at a time. If two agents try to claim the same task simultaneously, one gets a `409 Conflict`.
## Delegation
The CEO is the primary delegator. When you set company goals, the CEO:
1. Creates a strategy and submits it for your approval
2. Breaks approved goals into tasks
3. Assigns tasks to agents based on their role and capabilities
4. Hires new agents when needed (subject to your approval)
You don't need to manually assign every task — set the goals and let the CEO organize the work. You approve key decisions (strategy, hiring) and monitor progress. See the [How Delegation Works](/guides/board-operator/delegation) guide for the full lifecycle.
## Heartbeats
Agents don't run continuously. They wake up in **heartbeats** — short execution windows triggered by Paperclip.
A heartbeat can be triggered by:
- **Schedule** — periodic timer (e.g. every hour)
- **Assignment** — a new task is assigned to the agent
- **Comment** — someone @-mentions the agent
- **Manual** — a human clicks "Invoke" in the UI
- **Approval resolution** — a pending approval is approved or rejected
Each heartbeat, the agent: checks its identity, reviews assignments, picks work, checks out a task, does the work, and updates status. This is the **heartbeat protocol**.
## Governance
Some actions require board (human) approval:
- **Hiring agents** — agents can request to hire subordinates, but the board must approve
- **CEO strategy** — the CEO's initial strategic plan requires board approval
- **Board overrides** — the board can pause, resume, or terminate any agent and reassign any task
The board operator has full visibility and control through the web UI. Every mutation is logged in an **activity audit trail**.
-62
View File
@@ -1,62 +0,0 @@
---
title: Quickstart
summary: Get Paperclip running in minutes
---
Get Paperclip running locally in under 5 minutes.
## Quick Start (Recommended)
```sh
npx paperclipai onboard --yes
```
This walks you through setup, configures your environment, and gets Paperclip running.
If you already have a Paperclip install, rerunning `onboard` keeps your current config and data paths intact. Use `paperclipai configure` if you want to edit settings.
To start Paperclip again later:
```sh
npx paperclipai run
```
> **Note:** If you used `npx` for setup, always use `npx paperclipai` to run commands. The `pnpm paperclipai` form only works inside a cloned copy of the Paperclip repository (see Local Development below).
## Local Development
For contributors working on Paperclip itself. Prerequisites: Node.js 20+ and pnpm 9+.
Clone the repository, then:
```sh
pnpm install
pnpm dev
```
This starts the API server and UI at [http://localhost:3100](http://localhost:3100).
No external database required — Paperclip uses an embedded PostgreSQL instance by default.
When working from the cloned repo, you can also use:
```sh
pnpm paperclipai run
```
This auto-onboards if config is missing, runs health checks with auto-repair, and starts the server.
## What's Next
Once Paperclip is running:
1. Create your first company in the web UI
2. Define a company goal
3. Create a CEO agent and configure its adapter
4. Build out the org chart with more agents
5. Set budgets and assign initial tasks
6. Hit go — agents start their heartbeats and the company runs
<Card title="Core Concepts" href="/start/core-concepts">
Learn the key concepts behind Paperclip
</Card>
-39
View File
@@ -1,39 +0,0 @@
---
title: What is Paperclip?
summary: The control plane for autonomous AI companies
---
Paperclip is the control plane for autonomous AI companies. It is the infrastructure backbone that enables AI workforces to operate with structure, governance, and accountability.
One instance of Paperclip can run multiple companies. Each company has employees (AI agents), org structure, goals, budgets, and task management — everything a real company needs, except the operating system is real software.
## The Problem
Task management software doesn't go far enough. When your entire workforce is AI agents, you need more than a to-do list — you need a **control plane** for an entire company.
## What Paperclip Does
Paperclip is the command, communication, and control plane for a company of AI agents. It is the single place where you:
- **Manage agents as employees** — hire, organize, and track who does what
- **Define org structure** — org charts that agents themselves operate within
- **Track work in real time** — see at any moment what every agent is working on
- **Control costs** — token salary budgets per agent, spend tracking, burn rate
- **Align to goals** — agents see how their work serves the bigger mission
- **Govern autonomy** — board approval gates, activity audit trails, budget enforcement
## Two Layers
### 1. Control Plane (Paperclip)
The central nervous system. Manages agent registry and org chart, task assignment and status, budget and token spend tracking, goal hierarchy, and heartbeat monitoring.
### 2. Execution Services (Adapters)
Agents run externally and report into the control plane. Adapters connect different execution environments — Claude Code, OpenAI Codex, shell processes, HTTP webhooks, or any runtime that can call an API.
The control plane doesn't run agents. It orchestrates them. Agents run wherever they run and phone home.
## Core Principle
You should be able to look at Paperclip and understand your entire company at a glance — who's doing what, how much it costs, and whether it's working.
File diff suppressed because it is too large. Load diff
-22
View File
@@ -1,22 +0,0 @@
# Notes
This folder contains planning and working documents copied from the original Paperclip docs effort.
These files are not the published docs site. They are maintainer references.
Current contents:
- `PRD-beginner-user-guides.md`
Original planning document for the beginner-friendly docs and custom docs viewer.
- `prompt-screenshots.md`
Screenshot capture guidance and prompt material used while building the docs set.
Use these files when:
- reviewing why the docs are structured the way they are
- updating screenshots
- extending the original docs vision
Do not treat them as public-facing source of truth unless you intentionally decide to publish parts of them.
-607
View File
@@ -1,607 +0,0 @@
# Agent prompt: seed data, screenshots, and dark mode
You are working in `/Users/aronprins/Development/paperclip`.
Complete the three parts below in order. Read each part fully before starting it.
---
## PART 1 — Write and run a screenshot seed script
The Paperclip app is running at `http://localhost:3100` and connected to a local
Postgres database (`postgres://paperclip:paperclip@localhost:5432/paperclip`).
The company is currently blank. Populate it with realistic-looking data so every
screen in the app has something worth photographing. **No live AI models may be
called.** All data is inserted directly into the database.
### 1a — Write the seed file
Create `/Users/aronprins/Development/paperclip/packages/db/src/seed-screenshots.ts`.
Follow the exact same import/DB-connection pattern as the existing
`packages/db/src/seed.ts` — use `createDb` from `"./client.js"` and import
tables from `"./schema/index.js"`. The script must call `process.exit(0)` at the
end.
Seed the following data. Use `new Date(Date.now() - N)` for realistic timestamps
spread over the past two weeks.
#### Company
```
name: "Horizon Labs"
description: "Building the next generation of developer tooling"
status: "active"
budgetMonthlyCents: 200_00 // $200/mo
spentMonthlyCents: 112_40 // $112.40 spent so far (56%)
```
#### Agents — insert in this order, capture each `.returning()[0]`
| variable | name | role | title | status | reportsTo | adapterType | budgetMonthlyCents | spentMonthlyCents |
|-----------|-------------------|------------|--------------------------|-----------|-----------|----------------|--------------------|-------------------|
| `ceo` | Alex (CEO) | ceo | Chief Executive Officer | idle | — | claude_local | 80_00 | 44_80 |
| `cto` | Morgan (CTO) | cto | Chief Technology Officer | running | ceo | claude_local | 50_00 | 40_25 |
| `eng1` | Jordan (Engineer) | engineer | Senior Engineer | idle | cto | codex_local | 30_00 | 7_10 |
| `eng2` | Casey (Engineer) | engineer | Engineer | error | cto | codex_local | 30_00 | 24_00 |
| `pm` | Riley (PM) | pm | Product Manager | paused | ceo | http | 20_00 | 20_15 |
For the paused agent (`pm`), also set:
```
pauseReason: "Monthly budget limit reached"
pausedAt: new Date(Date.now() - 1000 * 60 * 60 * 3) // 3 hours ago
```
For the error agent (`eng2`), set in `metadata`:
```json
{ "lastError": "Process exited with code 1: Cannot find module 'tsx'" }
```
adapterConfig values (jsonb):
- `claude_local`: `{ model: "claude-opus-4-5", workingDirectory: "/workspace", apiKey: "sk-ant-••••••••" }`
- `codex_local`: `{ model: "codex", workingDirectory: "/workspace", apiKey: "sk-••••••••" }`
- `http`: `{ url: "https://agents.horizon.internal/riley", apiKey: "••••••••" }`
#### Goal
```
title: "Ship Developer CLI v2"
description: "Deliver a polished, well-documented CLI that developers love"
level: "company"
status: "active"
ownerAgentId: ceo.id
```
#### Project
```
name: "CLI v2 — Core"
description: "Auth, config management, and the core command surface"
status: "in_progress"
leadAgentId: cto.id
```
#### Issues — insert all at once, capture ids for comments
| variable | title | status | priority | assignee | description |
|------------|-----------------------------------------------|-------------|----------|----------|-------------|
| `iss1` | Design token refresh command | in_progress | high | cto | Implement `pc auth refresh` with silent and interactive modes |
| `iss2` | Write integration tests for config parser | in_review | high | eng1 | Cover edge cases: missing keys, malformed TOML, env overrides |
| `iss3` | Fix crash on `pc whoami` when offline | todo | critical | eng2 | App panics with nil pointer when DNS resolution fails |
| `iss4` | Add `--output json` flag to all list commands | todo | medium | eng1 | Consistent machine-readable output across ls, agents ls, tasks ls |
| `iss5` | Spike: plugin system architecture | backlog | low | cto | Research approach for third-party CLI plugins |
| `iss6` | Document `pc config set` command | done | medium | pm | Write reference docs and usage examples |
| `iss7` | Release checklist template | blocked | high | ceo | Blocked: waiting on legal sign-off for OSS licence |
Set `startedAt` for in_progress/in_review issues; set `completedAt` for done issues.
#### Issue comments — insert after issues
For `iss1` (in_progress — looks like active agent thread):
```
[cto] "Starting on the token refresh flow. Planning to use the existing OAuth client and add a --silent flag."
[eng1] "Heads up: the OAuth client has a known bug with refresh tokens older than 30 days. See issue #43."
[cto] "Good catch. I'll add a fallback to full re-auth if the refresh fails. Updating the design."
```
For `iss2` (in_review):
```
[eng1] "Tests written and passing locally. Covering 14 edge cases including nested env overrides. Ready for review."
[cto] "Looks solid. Left one comment about the TOML error message format — can you make it match the existing error style?"
[eng1] "Done. Updated the error messages to use the standard format. Re-requesting review."
```
For `iss3` (blocked on eng2 error):
```
[eng2] "Reproducing the crash. Looks like the DNS timeout isn't being caught in the right place."
```
Set `authorAgentId` to the relevant agent. Set realistic `createdAt` timestamps
(spread 1–4 days ago, thread order preserved).
#### Approvals
Approval 1 — pending strategy:
```
type: "approve_ceo_strategy"
status: "pending"
requestedByAgentId: ceo.id
payload: {
summary: "Proposing to split CLI v2 into two releases: v2.0 (auth + config) ships in 3 weeks, v2.1 (plugin system) ships 6 weeks after. This reduces risk and gets core features to users sooner.",
milestones: [
{ name: "v2.0", deliverables: ["auth refresh", "config management", "json output flags"], eta: "3 weeks" },
{ name: "v2.1", deliverables: ["plugin system", "plugin marketplace docs"], eta: "9 weeks" }
],
risks: ["Plugin API may require breaking changes to core config format"],
requestedBy: "Alex (CEO)"
}
```
Approval 2 — pending hire:
```
type: "hire_agent"
status: "pending"
requestedByAgentId: cto.id
payload: {
name: "Sam (QA Engineer)",
role: "qa",
title: "QA Engineer",
reason: "Integration test coverage is currently at 34%. We need dedicated QA capacity before the v2.0 release to avoid regressions.",
proposedBudgetMonthlyCents: 2500,
reportsTo: "Morgan (CTO)"
}
```
Approval 3 — already approved (for the approved-state screenshot):
```
type: "hire_agent"
status: "approved"
requestedByAgentId: ceo.id
decidedByUserId: "board"
decidedAt: new Date(Date.now() - 1000 * 60 * 60 * 24 * 3) // 3 days ago
decisionNote: "Approved. Welcome aboard."
payload: {
name: "Alex (CEO)",
role: "ceo",
title: "Chief Executive Officer",
reason: "Initial company setup"
}
```
#### Heartbeat runs
Insert 3 runs for `cto` (the running agent):
```
run1: status "succeeded", invocationSource "timer", startedAt: -25min, finishedAt: -24min
run2: status "succeeded", invocationSource "on_demand", startedAt: -10min, finishedAt: -9min
run3: status "running", invocationSource "on_demand", startedAt: -2min, finishedAt: null
```
Insert 1 failed run for `eng2`:
```
status: "failed", invocationSource "assignment"
startedAt: -1h, finishedAt: -59min
error: "Process exited with code 1: Cannot find module 'tsx'"
stdoutExcerpt: "Starting agent...\nLoading config from /workspace/.paperclip/config.toml\n"
stderrExcerpt: "Error: Cannot find module 'tsx'\n at Function.Module._resolveFilename\n"
```
For run3 (the running one), also set `contextSnapshot`:
```json
{
"currentTask": "Design token refresh command",
"step": "Implementing silent refresh flow",
"tokensUsed": 8420
}
```
#### Cost events
For each agent, insert enough cost events spread over the current month to match
the `spentMonthlyCents` values above. Use:
- `provider: "anthropic"`, `model: "claude-opus-4-5"` for claude_local agents
- `provider: "openai"`, `model: "codex"` for codex_local agents
- `provider: "custom"`, `model: "http-agent"` for http agents
- `billingType: "metered_api"`
Spread 8–15 events per agent. `costCents` values should add up to the agent's
`spentMonthlyCents`. Set `occurredAt` spread over the past 14 days.
#### Budget policies
For each of the 5 agents, insert a `budget_policies` row:
```
scopeType: "agent"
scopeId: <agentId>
metric: "billed_cents"
windowKind: "calendar_month_utc"
amount: <agent's budgetMonthlyCents>
warnPercent: 80
hardStopEnabled: true
notifyEnabled: true
isActive: true
```
Also insert one company-level policy:
```
scopeType: "company"
scopeId: <companyId>
amount: 200_00
```
#### Activity log
Insert ~20 activity log entries spread over the past week covering:
- Company created
- Each agent created
- Each issue created and status changes (backlog→todo, todo→in_progress, etc.)
- Approvals requested
- Budget warning triggered for `pm` agent
- Budget hard stop triggered for `pm` agent (pause event)
Format:
```
actorType: "agent" or "system" or "user"
actorId: <agentId or userId string or "system">
action: "created" | "updated" | "status_changed" | "budget_warning" | "budget_hard_stop" | "approval_requested"
entityType: "company" | "agent" | "issue" | "approval"
entityId: <uuid as string>
agentId: <agentId if actor is agent, else null>
details: { ... relevant context ... }
```
### 1b — Run the seed script
After writing the file, run it:
```bash
cd /Users/aronprins/Development/paperclip
DATABASE_URL=postgres://paperclip:paperclip@localhost:5432/paperclip \
npx tsx packages/db/src/seed-screenshots.ts
```
Verify it exits cleanly. If it errors, fix the script and re-run. Do NOT use
`pnpm` to run it — use `npx tsx` directly with the DATABASE_URL env var.
---
## PART 2 — Add dark/light mode to the guide viewer
Edit `docs/docs-website/index.html`.
### Theme toggle button
Add a button to the right end of `#header-logo-row`. It shows a sun icon in
dark mode (click to go light) and a moon icon in light mode (click to go dark).
Style it as a small 32×32 icon button — no label, no border, subtle hover state.
Persist the choice in `localStorage` under key `"pc-guides-theme"`. Default: light.
Apply the theme by setting `document.documentElement.dataset.theme = "light"|"dark"`.
### Dark mode CSS
Add these overrides inside `<style>`:
```css
[data-theme="dark"] {
--white: #0f1117;
--linen: #13161e;
--parchment: #181c27;
--stone: #252a3a;
--stone-dark: #353c52;
--ink: #e4e6f0;
--graphite: #9ba3bf;
--ash: #555d7a;
--void: #f0f2ff;
--green: #22c55e;
--mint: rgba(34,197,94,0.1);
--amber: #f59e0b;
--red: #ef4444;
}
[data-theme="dark"] #header-outer { background: rgba(15,17,23,0.75); }
[data-theme="dark"] #header { background: #0f1117; border-color: #252a3a; }
[data-theme="dark"] #article pre { background: #0c0e14; }
[data-theme="dark"] body { background: #0f1117; }
```
Add smooth transitions to body, #header, #subnav, #toc, #article:
```css
body, #header, #subnav, #article, #toc { transition: background 0.25s, color 0.25s, border-color 0.25s; }
```
### Sun/moon SVGs
Sun (show when in dark mode — click to switch to light):
```svg
<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
<circle cx="9" cy="9" r="3.5"/>
<path d="M9 1v2M9 15v2M1 9h2M15 9h2M3.22 3.22l1.42 1.42M13.36 13.36l1.42 1.42M3.22 14.78l1.42-1.42M13.36 4.64l1.42-1.42"/>
</svg>
```
Moon (show when in light mode — click to switch to dark):
```svg
<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
<path d="M15.5 10.5A7 7 0 0 1 7.5 2.5a7 7 0 1 0 8 8z"/>
</svg>
```
---
## PART 3 — Take screenshots with dev-browser and wire them in
### 3a — Prep directories
Create these directories (they can be empty — screenshots will be written here):
```
docs/user-guides/screenshots/light/dashboard/
docs/user-guides/screenshots/light/agents/
docs/user-guides/screenshots/light/tasks/
docs/user-guides/screenshots/light/approvals/
docs/user-guides/screenshots/light/costs/
docs/user-guides/screenshots/light/activity/
docs/user-guides/screenshots/light/org/
docs/user-guides/screenshots/light/company/
docs/user-guides/screenshots/light/skills/
docs/user-guides/screenshots/light/export-import/
docs/user-guides/screenshots/dark/ (mirror of the above)
```
### 3b — Explore the app first
Before taking any screenshots, use dev-browser to open `http://localhost:3100`,
navigate around, and understand the URL structure, how to switch companies,
where each screen lives, and whether the app has a built-in dark mode toggle.
### 3c — Take screenshots (light mode)
Use dev-browser to take every screenshot below. Viewport: **1280×800**.
For each screenshot:
1. Navigate to the correct URL in the Paperclip app (http://localhost:3100)
2. Wait for the page to settle (no spinners)
3. If a specific panel or modal must be open, interact to open it first
4. Take screenshot
5. Save to `docs/user-guides/screenshots/light/<category>/<filename>`
**Screenshot list:**
`dashboard/dashboard-overview.png`
→ Main dashboard. Company "Horizon Labs" visible. All 5 agents shown. Multiple tasks in various states.
`dashboard/dashboard-overview-annotated.png`
→ Same shot as dashboard-overview.png (reuse/copy it)
`dashboard/agent-status-panel.png`
→ The Agent Status widget/panel only — zoom/crop to just that card
`dashboard/task-breakdown-panel.png`
→ Task Breakdown panel showing backlog, todo, in_progress, in_review, done, blocked counts
`dashboard/stale-tasks-panel.png`
→ Stale Tasks panel — shows tasks with no recent update (the blocked issue should appear)
`dashboard/cost-summary-panel.png`
→ Cost Summary panel with per-agent bars (mix of ~56%, ~80%, ~100%/paused)
`dashboard/activity-feed.png`
→ Recent Activity feed showing the last several events
`agents/agents-list-empty.png`
→ Create a new blank company temporarily OR show the agents list before the seed ran.
If you can't easily get an empty state, take the agents list as-is and note it.
`agents/new-agent-name-role.png`
→ Open the "new agent" form, fill in Name: "Sam" and Role: "QA Engineer", screenshot
`agents/new-agent-reports-to-field.png`
→ Same form, scroll to / focus the "Reports To" field showing the dropdown with agents listed
`agents/adapter-type-dropdown.png`
→ Adapter type selector open, all options visible (claude_local, codex_local, http, etc.)
`agents/claude-local-config-filled.png`
→ Agent form with claude_local selected and all config fields filled
`agents/codex-local-config.png`
→ Agent form with codex_local selected
`agents/http-adapter-config.png`
→ Agent form with http adapter selected
`agents/heartbeat-toggle-disabled.png`
→ Heartbeat / schedule section of agent form, toggle in OFF state
`agents/heartbeat-toggle-enabled.png`
→ Same section, toggle in ON state
`agents/budget-and-heartbeat-fields.png`
→ Budget + heartbeat section of the agent form together
`agents/test-environment-success.png`
→ After clicking "Test" on an agent config — success state
`agents/test-environment-fail.png`
→ Test result showing failure / error state (use eng2 which has an error)
`agents/agent-status-running.png`
→ Agent detail page for Morgan (CTO) — status: running
`agents/agent-detail-idle.png`
→ Agent detail page for Alex (CEO) — status: idle
`agents/agent-detail-run-history.png`
→ Agent detail showing the run history list (Morgan's 3 runs)
`agents/run-history-in-progress.png`
→ The currently-running run expanded or detail view
`agents/run-transcript-view.png`
→ Run transcript / log view showing the context snapshot steps
`tasks/inbox-view.png`
→ Task list showing all 7 issues with their status badges
`tasks/inbox-view-with-filters.png`
→ Task list with the filter panel open
`tasks/new-task-form-empty.png`
→ New task modal/form, all fields empty
`tasks/new-task-form-filled.png`
→ New task form with Title, Description, Priority, and Assignee filled in
`tasks/task-detail-in-progress.png`
→ Detail view for "Design token refresh command" — showing full comment thread
`tasks/comment-input-box.png`
→ Bottom of task detail, comment input box clicked/focused
`tasks/task-done-status.png`
→ "Document pc config set command" task — done status, agent final comment visible
`approvals/approvals-list.png`
→ Approvals page showing all 3 approvals (2 pending, 1 approved)
`approvals/approvals-queue-strategy.png`
→ Approvals list filtered to or highlighting the strategy approval
`approvals/strategy-approval-detail.png`
→ Detail view of the CEO strategy approval — full proposal text visible
`approvals/hire-approval-detail.png`
→ Detail view of the hire_agent approval for Sam (QA)
`approvals/approve-reject-buttons.png`
→ Approval detail with Approve and Reject buttons visible
`approvals/approve-reject-revision-buttons.png`
→ Approval detail with all three buttons: Approve, Reject, Request Revision
`approvals/revision-request-input.png`
→ Click "Request Revision" — the revision note input field open
`approvals/approved-approval.png`
→ The already-approved approval (Alex CEO hire) showing its approved state
`costs/costs-dashboard-overview.png`
→ Cost section of the dashboard or dedicated costs page
`costs/company-budget-field.png`
→ Company settings page showing the monthly budget field ($200)
`costs/agent-budget-field.png`
→ Agent form/settings showing the per-agent budget field
`costs/agent-budget-50pct.png`
→ An agent budget bar at approximately 50% — Alex (CEO) at $44.80/$80
`costs/agent-budget-80pct-warning.png`
→ Morgan (CTO) budget bar at ~80% ($40.25/$50) — warning colour
`costs/agent-budget-100pct-paused.png`
→ Riley (PM) budget bar at ~100%, paused state
`costs/agent-budget-bar.png`
→ Full cost summary showing all agents' budget bars together
`costs/per-run-cost-detail.png`
→ Cost breakdown for a single heartbeat run (tokens in/out, total cost)
`activity/activity-log-full.png`
→ Full activity log page, all entries visible
`activity/activity-filters.png`
→ Activity log with the filter panel open
`activity/activity-filtered-by-agent.png`
→ Activity log filtered to show only Morgan (CTO)'s actions
`org/org-chart-view.png`
→ Org chart: Alex (CEO) at top, Morgan (CTO) + Riley (PM) as direct reports, Jordan + Casey under Morgan
`org/org-chart-add-agent.png`
→ Add agent button visible in org chart context (or the trigger for it)
`org/org-chart-manager-assigned.png`
→ Org chart with a manager-worker line clearly visible
`org/execution-workspaces-list.png`
→ Execution workspaces list (navigate to a project's workspace settings)
`org/workspace-modes.png`
→ Workspace mode selection — isolated / reuse / primary options
`company/new-company-form.png`
→ New company creation form (empty or in-progress)
`company/company-goal-field.png`
→ Company settings showing the goal/description field
`company/company-budget-setting.png`
→ Company settings showing the budget field
`company/company-saved.png`
→ Company settings page showing Horizon Labs, saved state
`skills/skills-list.png`
→ Skills section of the company or agent settings
`skills/skill-detail.png`
→ Individual skill detail / editor view
`export-import/export-dialog.png`
→ Export company/agent package dialog
`export-import/import-dialog.png`
→ Import package dialog
If a screen genuinely does not exist in the app, save a 1280×800 placeholder
image (solid #f0ece7 background with the filename in #888880 text, centered)
so the image path resolves in the viewer.
### 3d — Take dark mode screenshots
If the app has a built-in dark mode toggle, enable it. If not, use dev-browser
to inject `document.documentElement.classList.add('dark')` or set the media
query emulation to `prefers-color-scheme: dark` before each screenshot.
Repeat every screenshot from 3c, saving to `docs/user-guides/screenshots/dark/<category>/<filename>`.
### 3e — Wire screenshots into the viewer
Edit `docs/docs-website/index.html`:
1. In `postProcessImages()`, before attaching the error handler, rewrite each
`img.src` to remap `../images/<category>/<file>` paths:
```js
function resolveScreenshotSrc(src) {
// src may be like "../images/dashboard/foo.png" or "images/dashboard/foo.png"
const match = src.match(/images\/([^/]+\/[^/]+\.png)$/);
if (!match) return src;
const theme = document.documentElement.dataset.theme || 'light';
return `../user-guides/screenshots/${theme}/${match[1]}`;
}
```
Call this in `postProcessImages()` to set `img.src` before attaching the error handler.
2. In the theme toggle click handler (from Part 2), after updating
`dataset.theme` and `localStorage`, also swap all visible img srcs:
```js
document.querySelectorAll('#article img[data-screenshot]').forEach(img => {
img.src = resolveScreenshotSrc(img.dataset.screenshot);
});
```
Store the original path in `data-screenshot` when first remapping in
`postProcessImages()` so you can always resolve back to the correct file.
---
## Done
Verify the end state:
1. `http://localhost:8080` loads, shows Horizon Labs guides
2. Toggle to dark mode — UI switches, all screenshots swap to dark variants
3. Toggle back to light — screenshots swap back
4. No broken image placeholder boxes (or only for genuinely missing screens)
+1 -3
View File
@@ -6,8 +6,6 @@
"docs:build": "node docs/docs-website/build-release.mjs --base-path /paperclip-docs/ --out-dir .site",
"docs:build:auto": "node docs/docs-website/build-release.mjs --base-path auto --out-dir .site",
"docs:serve": "python3 -m http.server 4321 --directory .site",
"docs:publish": "./scripts/publish-gh-pages.sh",
"references:sync": "./scripts/sync-upstream-reference.sh"
"docs:publish": "./scripts/publish-gh-pages.sh"
}
}
-55
View File
@@ -1,55 +0,0 @@
# References
This folder is for local maintenance support, not for publishing.
- `upstream-paperclip/` is a local checkout of the upstream `paperclipai/paperclip` repository.
- `upstream.json` records the last synced upstream commit.
- `tools/` contains helper files copied from the Paperclip repo that are useful when maintaining docs and screenshots.
Refresh the upstream checkout locally with:
```sh
npm run references:sync
```
## Why this exists
This repository is intentionally separate from upstream, so maintainers still need a reliable way to compare documentation against the current Paperclip codebase.
The local reference checkout is used for:
- checking whether docs are outdated
- confirming current behavior against source
- comparing API, UI, and CLI changes before editing docs
- reviewing upstream drift without turning this repo into a full source mirror
## What gets updated
The sync script keeps a shallow git checkout of upstream under `references/upstream-paperclip/` and records the synced commit in `references/upstream.json`.
That means:
- the folder is a real git checkout
- it is ignored by this repo
- it can be refreshed repeatedly without bloating this repo history
## Defaults
- upstream URL: `https://github.com/paperclipai/paperclip.git`
- upstream branch: `master`
Override them for fork or branch comparisons:
```sh
UPSTREAM_URL=https://github.com/aronprins/paperclip.git UPSTREAM_REF=chore/beginner-user-guides npm run references:sync
```
## Tools
`tools/` is for copied helper material that supports docs maintenance but is not part of the public site.
Right now this includes:
- `seed-screenshots.ts`
Treat copied tools as reference material. They may need changes before they work against current upstream state.
-750
View File
@@ -1,750 +0,0 @@
import { createDb } from "./client.js";
import {
companies,
agents,
goals,
projects,
issues,
issueComments,
approvals,
heartbeatRuns,
costEvents,
budgetPolicies,
activityLog,
} from "./schema/index.js";
const url = process.env.DATABASE_URL;
if (!url) throw new Error("DATABASE_URL is required");
const db = createDb(url);
const now = Date.now();
const mins = (n: number) => new Date(now - 1000 * 60 * n);
const hrs = (n: number) => new Date(now - 1000 * 60 * 60 * n);
const days = (n: number) => new Date(now - 1000 * 60 * 60 * 24 * n);
console.log("Seeding screenshot data…");
// ─── Company ───────────────────────────────────────────────────────────────
const [company] = await db
.insert(companies)
.values({
name: "Horizon Labs",
description: "Building the next generation of developer tooling",
status: "active",
budgetMonthlyCents: 20000,
spentMonthlyCents: 11240,
})
.returning();
const companyId = company!.id;
// ─── Agents ────────────────────────────────────────────────────────────────
const [ceo] = await db
.insert(agents)
.values({
companyId,
name: "Alex (CEO)",
role: "ceo",
title: "Chief Executive Officer",
status: "idle",
adapterType: "claude_local",
adapterConfig: { model: "claude-opus-4-5", workingDirectory: "/workspace", apiKey: "sk-ant-••••••••" },
budgetMonthlyCents: 8000,
spentMonthlyCents: 4480,
})
.returning();
const [cto] = await db
.insert(agents)
.values({
companyId,
name: "Morgan (CTO)",
role: "cto",
title: "Chief Technology Officer",
status: "running",
reportsTo: ceo!.id,
adapterType: "claude_local",
adapterConfig: { model: "claude-opus-4-5", workingDirectory: "/workspace", apiKey: "sk-ant-••••••••" },
budgetMonthlyCents: 5000,
spentMonthlyCents: 4025,
})
.returning();
const [eng1] = await db
.insert(agents)
.values({
companyId,
name: "Jordan (Engineer)",
role: "engineer",
title: "Senior Engineer",
status: "idle",
reportsTo: cto!.id,
adapterType: "codex_local",
adapterConfig: { model: "codex", workingDirectory: "/workspace", apiKey: "sk-••••••••" },
budgetMonthlyCents: 3000,
spentMonthlyCents: 710,
})
.returning();
const [eng2] = await db
.insert(agents)
.values({
companyId,
name: "Casey (Engineer)",
role: "engineer",
title: "Engineer",
status: "error",
reportsTo: cto!.id,
adapterType: "codex_local",
adapterConfig: { model: "codex", workingDirectory: "/workspace", apiKey: "sk-••••••••" },
budgetMonthlyCents: 3000,
spentMonthlyCents: 2400,
metadata: { lastError: "Process exited with code 1: Cannot find module 'tsx'" },
})
.returning();
const [pm] = await db
.insert(agents)
.values({
companyId,
name: "Riley (PM)",
role: "pm",
title: "Product Manager",
status: "paused",
reportsTo: ceo!.id,
adapterType: "http",
adapterConfig: { url: "https://agents.horizon.internal/riley", apiKey: "••••••••" },
budgetMonthlyCents: 2000,
spentMonthlyCents: 2015,
pauseReason: "Monthly budget limit reached",
pausedAt: hrs(3),
})
.returning();
// ─── Goal ──────────────────────────────────────────────────────────────────
const [goal] = await db
.insert(goals)
.values({
companyId,
title: "Ship Developer CLI v2",
description: "Deliver a polished, well-documented CLI that developers love",
level: "company",
status: "active",
ownerAgentId: ceo!.id,
})
.returning();
// ─── Project ───────────────────────────────────────────────────────────────
const [project] = await db
.insert(projects)
.values({
companyId,
goalId: goal!.id,
name: "CLI v2 — Core",
description: "Auth, config management, and the core command surface",
status: "in_progress",
leadAgentId: cto!.id,
})
.returning();
// ─── Issues ────────────────────────────────────────────────────────────────
const issueRows = await db
.insert(issues)
.values([
{
companyId,
projectId: project!.id,
goalId: goal!.id,
title: "Design token refresh command",
description: "Implement `pc auth refresh` with silent and interactive modes",
status: "in_progress",
priority: "high",
assigneeAgentId: cto!.id,
createdByAgentId: ceo!.id,
startedAt: days(5),
createdAt: days(7),
},
{
companyId,
projectId: project!.id,
goalId: goal!.id,
title: "Write integration tests for config parser",
description: "Cover edge cases: missing keys, malformed TOML, env overrides",
status: "in_review",
priority: "high",
assigneeAgentId: eng1!.id,
createdByAgentId: ceo!.id,
startedAt: days(4),
createdAt: days(6),
},
{
companyId,
projectId: project!.id,
goalId: goal!.id,
title: "Fix crash on `pc whoami` when offline",
description: "App panics with nil pointer when DNS resolution fails",
status: "todo",
priority: "critical",
assigneeAgentId: eng2!.id,
createdByAgentId: ceo!.id,
createdAt: days(5),
},
{
companyId,
projectId: project!.id,
goalId: goal!.id,
title: "Add `--output json` flag to all list commands",
description: "Consistent machine-readable output across ls, agents ls, tasks ls",
status: "todo",
priority: "medium",
assigneeAgentId: eng1!.id,
createdByAgentId: ceo!.id,
createdAt: days(4),
},
{
companyId,
projectId: project!.id,
goalId: goal!.id,
title: "Spike: plugin system architecture",
description: "Research approach for third-party CLI plugins",
status: "backlog",
priority: "low",
assigneeAgentId: cto!.id,
createdByAgentId: ceo!.id,
createdAt: days(10),
},
{
companyId,
projectId: project!.id,
goalId: goal!.id,
title: "Document `pc config set` command",
description: "Write reference docs and usage examples",
status: "done",
priority: "medium",
assigneeAgentId: pm!.id,
createdByAgentId: ceo!.id,
startedAt: days(8),
completedAt: days(2),
createdAt: days(9),
},
{
companyId,
projectId: project!.id,
goalId: goal!.id,
title: "Release checklist template",
description: "Blocked: waiting on legal sign-off for OSS licence",
status: "blocked",
priority: "high",
assigneeAgentId: ceo!.id,
createdByAgentId: ceo!.id,
createdAt: days(3),
},
])
.returning();
const [iss1, iss2, iss3] = issueRows;
// ─── Issue comments ────────────────────────────────────────────────────────
await db.insert(issueComments).values([
// iss1 thread
{
companyId,
issueId: iss1!.id,
authorAgentId: cto!.id,
body: "Starting on the token refresh flow. Planning to use the existing OAuth client and add a --silent flag.",
createdAt: days(4),
},
{
companyId,
issueId: iss1!.id,
authorAgentId: eng1!.id,
body: "Heads up: the OAuth client has a known bug with refresh tokens older than 30 days. See issue #43.",
createdAt: days(3),
},
{
companyId,
issueId: iss1!.id,
authorAgentId: cto!.id,
body: "Good catch. I'll add a fallback to full re-auth if the refresh fails. Updating the design.",
createdAt: days(2),
},
// iss2 thread
{
companyId,
issueId: iss2!.id,
authorAgentId: eng1!.id,
body: "Tests written and passing locally. Covering 14 edge cases including nested env overrides. Ready for review.",
createdAt: days(3),
},
{
companyId,
issueId: iss2!.id,
authorAgentId: cto!.id,
body: "Looks solid. Left one comment about the TOML error message format — can you make it match the existing error style?",
createdAt: days(2),
},
{
companyId,
issueId: iss2!.id,
authorAgentId: eng1!.id,
body: "Done. Updated the error messages to use the standard format. Re-requesting review.",
createdAt: days(1),
},
// iss3 thread
{
companyId,
issueId: iss3!.id,
authorAgentId: eng2!.id,
body: "Reproducing the crash. Looks like the DNS timeout isn't being caught in the right place.",
createdAt: days(2),
},
]);
// ─── Approvals ─────────────────────────────────────────────────────────────
await db.insert(approvals).values([
{
companyId,
type: "approve_ceo_strategy",
status: "pending",
requestedByAgentId: ceo!.id,
payload: {
summary: "Proposing to split CLI v2 into two releases: v2.0 (auth + config) ships in 3 weeks, v2.1 (plugin system) ships 6 weeks after. This reduces risk and gets core features to users sooner.",
milestones: [
{ name: "v2.0", deliverables: ["auth refresh", "config management", "json output flags"], eta: "3 weeks" },
{ name: "v2.1", deliverables: ["plugin system", "plugin marketplace docs"], eta: "9 weeks" },
],
risks: ["Plugin API may require breaking changes to core config format"],
requestedBy: "Alex (CEO)",
},
},
{
companyId,
type: "hire_agent",
status: "pending",
requestedByAgentId: cto!.id,
payload: {
name: "Sam (QA Engineer)",
role: "qa",
title: "QA Engineer",
reason: "Integration test coverage is currently at 34%. We need dedicated QA capacity before the v2.0 release to avoid regressions.",
proposedBudgetMonthlyCents: 2500,
reportsTo: "Morgan (CTO)",
},
},
{
companyId,
type: "hire_agent",
status: "approved",
requestedByAgentId: ceo!.id,
decidedByUserId: "board",
decidedAt: days(3),
decisionNote: "Approved. Welcome aboard.",
payload: {
name: "Alex (CEO)",
role: "ceo",
title: "Chief Executive Officer",
reason: "Initial company setup",
},
},
]);
// ─── Heartbeat runs ────────────────────────────────────────────────────────
const [run3] = await db
.insert(heartbeatRuns)
.values({
companyId,
agentId: cto!.id,
invocationSource: "on_demand",
status: "running",
startedAt: mins(2),
contextSnapshot: {
currentTask: "Design token refresh command",
step: "Implementing silent refresh flow",
tokensUsed: 8420,
},
})
.returning();
await db.insert(heartbeatRuns).values([
{
companyId,
agentId: cto!.id,
invocationSource: "timer",
status: "succeeded",
startedAt: mins(25),
finishedAt: mins(24),
},
{
companyId,
agentId: cto!.id,
invocationSource: "on_demand",
status: "succeeded",
startedAt: mins(10),
finishedAt: mins(9),
},
{
companyId,
agentId: eng2!.id,
invocationSource: "assignment",
status: "failed",
startedAt: hrs(1),
finishedAt: new Date(now - 1000 * 60 * 59),
error: "Process exited with code 1: Cannot find module 'tsx'",
stdoutExcerpt: "Starting agent...\nLoading config from /workspace/.paperclip/config.toml\n",
stderrExcerpt: "Error: Cannot find module 'tsx'\n at Function.Module._resolveFilename\n",
},
]);
// ─── Cost events ───────────────────────────────────────────────────────────
function spreadCosts(
agentId: string,
totalCents: number,
count: number,
provider: string,
model: string,
) {
const events = [];
let remaining = totalCents;
for (let i = 0; i < count; i++) {
const isLast = i === count - 1;
const base = isLast ? remaining : Math.floor(remaining / (count - i));
const jitter = isLast ? 0 : Math.floor((Math.random() - 0.5) * base * 0.3);
const costCents = Math.max(1, base + jitter);
remaining -= costCents;
events.push({
companyId,
agentId,
provider,
biller: provider,
billingType: "metered_api",
model,
inputTokens: Math.floor(costCents * 3),
outputTokens: Math.floor(costCents * 1),
costCents,
occurredAt: new Date(now - 1000 * 60 * 60 * 24 * 14 * (1 - i / count)),
});
}
return events;
}
await db.insert(costEvents).values([
...spreadCosts(ceo!.id, 4480, 12, "anthropic", "claude-opus-4-5"),
...spreadCosts(cto!.id, 4025, 15, "anthropic", "claude-opus-4-5"),
...spreadCosts(eng1!.id, 710, 8, "openai", "codex"),
...spreadCosts(eng2!.id, 2400, 10, "openai", "codex"),
...spreadCosts(pm!.id, 2015, 9, "custom", "http-agent"),
]);
// ─── Budget policies ───────────────────────────────────────────────────────
await db.insert(budgetPolicies).values([
{
companyId,
scopeType: "agent",
scopeId: ceo!.id,
metric: "billed_cents",
windowKind: "calendar_month_utc",
amount: 8000,
warnPercent: 80,
hardStopEnabled: true,
notifyEnabled: true,
isActive: true,
},
{
companyId,
scopeType: "agent",
scopeId: cto!.id,
metric: "billed_cents",
windowKind: "calendar_month_utc",
amount: 5000,
warnPercent: 80,
hardStopEnabled: true,
notifyEnabled: true,
isActive: true,
},
{
companyId,
scopeType: "agent",
scopeId: eng1!.id,
metric: "billed_cents",
windowKind: "calendar_month_utc",
amount: 3000,
warnPercent: 80,
hardStopEnabled: true,
notifyEnabled: true,
isActive: true,
},
{
companyId,
scopeType: "agent",
scopeId: eng2!.id,
metric: "billed_cents",
windowKind: "calendar_month_utc",
amount: 3000,
warnPercent: 80,
hardStopEnabled: true,
notifyEnabled: true,
isActive: true,
},
{
companyId,
scopeType: "agent",
scopeId: pm!.id,
metric: "billed_cents",
windowKind: "calendar_month_utc",
amount: 2000,
warnPercent: 80,
hardStopEnabled: true,
notifyEnabled: true,
isActive: true,
},
{
companyId,
scopeType: "company",
scopeId: companyId,
metric: "billed_cents",
windowKind: "calendar_month_utc",
amount: 20000,
warnPercent: 80,
hardStopEnabled: true,
notifyEnabled: true,
isActive: true,
},
]);
// ─── Activity log ──────────────────────────────────────────────────────────
await db.insert(activityLog).values([
// Company created
{
companyId,
actorType: "user",
actorId: "board",
action: "created",
entityType: "company",
entityId: companyId,
details: { name: "Horizon Labs" },
createdAt: days(14),
},
// Agents created
{
companyId,
actorType: "system",
actorId: "system",
action: "created",
entityType: "agent",
entityId: ceo!.id,
agentId: ceo!.id,
details: { name: "Alex (CEO)", role: "ceo" },
createdAt: days(14),
},
{
companyId,
actorType: "system",
actorId: "system",
action: "created",
entityType: "agent",
entityId: cto!.id,
agentId: cto!.id,
details: { name: "Morgan (CTO)", role: "cto" },
createdAt: days(13),
},
{
companyId,
actorType: "system",
actorId: "system",
action: "created",
entityType: "agent",
entityId: eng1!.id,
agentId: eng1!.id,
details: { name: "Jordan (Engineer)", role: "engineer" },
createdAt: days(12),
},
{
companyId,
actorType: "system",
actorId: "system",
action: "created",
entityType: "agent",
entityId: eng2!.id,
agentId: eng2!.id,
details: { name: "Casey (Engineer)", role: "engineer" },
createdAt: days(11),
},
{
companyId,
actorType: "system",
actorId: "system",
action: "created",
entityType: "agent",
entityId: pm!.id,
agentId: pm!.id,
details: { name: "Riley (PM)", role: "pm" },
createdAt: days(10),
},
// Issues created
{
companyId,
actorType: "agent",
actorId: ceo!.id,
action: "created",
entityType: "issue",
entityId: iss1!.id,
agentId: ceo!.id,
details: { title: "Design token refresh command" },
createdAt: days(7),
},
{
companyId,
actorType: "agent",
actorId: ceo!.id,
action: "created",
entityType: "issue",
entityId: iss2!.id,
agentId: ceo!.id,
details: { title: "Write integration tests for config parser" },
createdAt: days(6),
},
// Issue status changes
{
companyId,
actorType: "agent",
actorId: cto!.id,
action: "status_changed",
entityType: "issue",
entityId: iss1!.id,
agentId: cto!.id,
details: { from: "todo", to: "in_progress", title: "Design token refresh command" },
createdAt: days(5),
},
{
companyId,
actorType: "agent",
actorId: eng1!.id,
action: "status_changed",
entityType: "issue",
entityId: iss2!.id,
agentId: eng1!.id,
details: { from: "todo", to: "in_progress", title: "Write integration tests for config parser" },
createdAt: days(4),
},
{
companyId,
actorType: "agent",
actorId: eng1!.id,
action: "status_changed",
entityType: "issue",
entityId: iss2!.id,
agentId: eng1!.id,
details: { from: "in_progress", to: "in_review", title: "Write integration tests for config parser" },
createdAt: days(3),
},
{
companyId,
actorType: "agent",
actorId: pm!.id,
action: "status_changed",
entityType: "issue",
entityId: issueRows[5]!.id,
agentId: pm!.id,
details: { from: "in_progress", to: "done", title: "Document `pc config set` command" },
createdAt: days(2),
},
// Approvals requested
{
companyId,
actorType: "agent",
actorId: ceo!.id,
action: "approval_requested",
entityType: "approval",
entityId: ceo!.id,
agentId: ceo!.id,
details: { type: "approve_ceo_strategy", summary: "CLI v2 release strategy" },
createdAt: days(2),
},
{
companyId,
actorType: "agent",
actorId: cto!.id,
action: "approval_requested",
entityType: "approval",
entityId: cto!.id,
agentId: cto!.id,
details: { type: "hire_agent", name: "Sam (QA Engineer)" },
createdAt: days(1),
},
// Budget warning for pm
{
companyId,
actorType: "system",
actorId: "system",
action: "budget_warning",
entityType: "agent",
entityId: pm!.id,
agentId: pm!.id,
details: { threshold: 80, spentCents: 1700, budgetCents: 2000, agentName: "Riley (PM)" },
createdAt: hrs(6),
},
// Budget hard stop for pm
{
companyId,
actorType: "system",
actorId: "system",
action: "budget_hard_stop",
entityType: "agent",
entityId: pm!.id,
agentId: pm!.id,
details: { spentCents: 2015, budgetCents: 2000, agentName: "Riley (PM)", reason: "Monthly budget limit reached" },
createdAt: hrs(3),
},
// Morgan running
{
companyId,
actorType: "agent",
actorId: cto!.id,
action: "updated",
entityType: "agent",
entityId: cto!.id,
agentId: cto!.id,
details: { status: "running", runId: run3!.id },
createdAt: mins(2),
},
// Casey error
{
companyId,
actorType: "system",
actorId: "system",
action: "updated",
entityType: "agent",
entityId: eng2!.id,
agentId: eng2!.id,
details: { status: "error", error: "Process exited with code 1: Cannot find module 'tsx'" },
createdAt: hrs(1),
},
// Goal created
{
companyId,
actorType: "agent",
actorId: ceo!.id,
action: "created",
entityType: "company",
entityId: goal!.id,
agentId: ceo!.id,
details: { type: "goal", title: "Ship Developer CLI v2" },
createdAt: days(13),
},
// Project created
{
companyId,
actorType: "agent",
actorId: cto!.id,
action: "created",
entityType: "company",
entityId: project!.id,
agentId: cto!.id,
details: { type: "project", name: "CLI v2 — Core" },
createdAt: days(12),
},
]);
console.log("Screenshot seed complete");
process.exit(0);
-6
View File
@@ -1,6 +0,0 @@
{
"upstreamUrl": "https://github.com/paperclipai/paperclip.git",
"branch": "master",
"commit": "e93e418cbf7997a29ff258d51d761572e69bda92",
"syncedAt": "2026-04-17T11:54:22Z"
}
-35
View File
@@ -1,35 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
target_dir="$repo_root/references/upstream-paperclip"
meta_file="$repo_root/references/upstream.json"
upstream_url="${UPSTREAM_URL:-https://github.com/paperclipai/paperclip.git}"
upstream_ref="${UPSTREAM_REF:-master}"
mkdir -p "$repo_root/references"
if [ -d "$target_dir/.git" ]; then
git -C "$target_dir" fetch --depth 1 origin "$upstream_ref"
git -C "$target_dir" checkout -B "$upstream_ref" "origin/$upstream_ref"
else
git clone --depth 1 --branch "$upstream_ref" "$upstream_url" "$target_dir"
fi
commit_sha="$(git -C "$target_dir" rev-parse HEAD)"
synced_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
cat >"$meta_file" <<EOF
{
"upstreamUrl": "$upstream_url",
"branch": "$upstream_ref",
"commit": "$commit_sha",
"syncedAt": "$synced_at"
}
EOF
echo "Upstream reference synced:"
echo " URL: $upstream_url"
echo " Branch: $upstream_ref"
echo " Commit: $commit_sha"