From f83a77f41fdeb26a8c53d3b0f7a67a419eb8fc82 Mon Sep 17 00:00:00 2001 From: dotta Date: Thu, 26 Mar 2026 21:34:40 -0500 Subject: [PATCH 1/4] Add cli/README.md with absolute image URLs for npm The root README uses relative doc/assets/ paths which work on GitHub but break on npmjs.com since those files aren't in the published tarball. This adds a cli-specific README with absolute raw.githubusercontent.com URLs so images render on npm. Co-Authored-By: Paperclip --- cli/README.md | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 cli/README.md diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 00000000..c5a6ce13 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,290 @@ +

+ Paperclip — runs your business +

+ +

+ Quickstart · + Docs · + GitHub · + Discord +

+ +

+ MIT License + Stars + Discord +

+ +
+ +
+ +
+ +
+ +## What is Paperclip? + +# Open-source orchestration for zero-human companies + +**If OpenClaw is an _employee_, Paperclip is the _company_** + +Paperclip is a Node.js server and React UI that orchestrates a team of AI agents to run a business. Bring your own agents, assign goals, and track your agents' work and costs from one dashboard. + +It looks like a task manager — but under the hood it has org charts, budgets, governance, goal alignment, and agent coordination. + +**Manage business goals, not pull requests.** + +| | Step | Example | +| ------ | --------------- | ------------------------------------------------------------------ | +| **01** | Define the goal | _"Build the #1 AI note-taking app to $1M MRR."_ | +| **02** | Hire the team | CEO, CTO, engineers, designers, marketers — any bot, any provider. | +| **03** | Approve and run | Review strategy. Set budgets. Hit go. Monitor from the dashboard. | + +
+ +> **COMING SOON: Clipmart** — Download and run entire companies with one click. Browse pre-built company templates — full org structures, agent configs, and skills — and import them into your Paperclip instance in seconds. + +
+ +
+ + + + + + + + + + +
Works
with
OpenClaw
OpenClaw
Claude
Claude Code
Codex
Codex
Cursor
Cursor
Bash
Bash
HTTP
HTTP
+ +If it can receive a heartbeat, it's hired. + +
+ +
+ +## Paperclip is right for you if + +- ✅ You want to build **autonomous AI companies** +- ✅ You **coordinate many different agents** (OpenClaw, Codex, Claude, Cursor) toward a common goal +- ✅ You have **20 simultaneous Claude Code terminals** open and lose track of what everyone is doing +- ✅ You want agents running **autonomously 24/7**, but still want to audit work and chime in when needed +- ✅ You want to **monitor costs** and enforce budgets +- ✅ You want a process for managing agents that **feels like using a task manager** +- ✅ You want to manage your autonomous businesses **from your phone** + +
+ +## Features + + + + + + + + + + + + + + + + + +
+

🔌 Bring Your Own Agent

+Any agent, any runtime, one org chart. If it can receive a heartbeat, it's hired. +
+

🎯 Goal Alignment

+Every task traces back to the company mission. Agents know what to do and why. +
+

💓 Heartbeats

+Agents wake on a schedule, check work, and act. Delegation flows up and down the org chart. +
+

💰 Cost Control

+Monthly budgets per agent. When they hit the limit, they stop. No runaway costs. +
+

🏢 Multi-Company

+One deployment, many companies. Complete data isolation. One control plane for your portfolio. +
+

🎫 Ticket System

+Every conversation traced. Every decision explained. Full tool-call tracing and immutable audit log. +
+

🛡️ Governance

+You're the board. Approve hires, override strategy, pause or terminate any agent — at any time. +
+

📊 Org Chart

+Hierarchies, roles, reporting lines. Your agents have a boss, a title, and a job description. +
+

📱 Mobile Ready

+Monitor and manage your autonomous businesses from anywhere. +
+ +
+ +## Problems Paperclip solves + +| Without Paperclip | With Paperclip | +| ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| ❌ You have 20 Claude Code tabs open and can't track which one does what. On reboot you lose everything. | ✅ Tasks are ticket-based, conversations are threaded, sessions persist across reboots. | +| ❌ You manually gather context from several places to remind your bot what you're actually doing. | ✅ Context flows from the task up through the project and company goals — your agent always knows what to do and why. | +| ❌ Folders of agent configs are disorganized and you're re-inventing task management, communication, and coordination between agents. | ✅ Paperclip gives you org charts, ticketing, delegation, and governance out of the box — so you run a company, not a pile of scripts. | +| ❌ Runaway loops waste hundreds of dollars of tokens and max your quota before you even know what happened. | ✅ Cost tracking surfaces token budgets and throttles agents when they're out. Management prioritizes with budgets. | +| ❌ You have recurring jobs (customer support, social, reports) and have to remember to manually kick them off. | ✅ Heartbeats handle regular work on a schedule. Management supervises. | +| ❌ You have an idea, you have to find your repo, fire up Claude Code, keep a tab open, and babysit it. | ✅ Add a task in Paperclip. Your coding agent works on it until it's done. Management reviews their work. | + +
+ +## Why Paperclip is special + +Paperclip handles the hard orchestration details correctly. + +| | | +| --------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| **Atomic execution.** | Task checkout and budget enforcement are atomic, so no double-work and no runaway spend. | +| **Persistent agent state.** | Agents resume the same task context across heartbeats instead of restarting from scratch. | +| **Runtime skill injection.** | Agents can learn Paperclip workflows and project context at runtime, without retraining. | +| **Governance with rollback.** | Approval gates are enforced, config changes are revisioned, and bad changes can be rolled back safely. | +| **Goal-aware execution.** | Tasks carry full goal ancestry so agents consistently see the "why," not just a title. | +| **Portable company templates.** | Export/import orgs, agents, and skills with secret scrubbing and collision handling. | +| **True multi-company isolation.** | Every entity is company-scoped, so one deployment can run many companies with separate data and audit trails. | + +
+ +## What Paperclip is not + +| | | +| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| **Not a chatbot.** | Agents have jobs, not chat windows. | +| **Not an agent framework.** | We don't tell you how to build agents. We tell you how to run a company made of them. | +| **Not a workflow builder.** | No drag-and-drop pipelines. Paperclip models companies — with org charts, goals, budgets, and governance. | +| **Not a prompt manager.** | Agents bring their own prompts, models, and runtimes. Paperclip manages the organization they work in. | +| **Not a single-agent tool.** | This is for teams. If you have one agent, you probably don't need Paperclip. If you have twenty — you definitely do. | +| **Not a code review tool.** | Paperclip orchestrates work, not pull requests. Bring your own review process. | + +
+ +## Quickstart + +Open source. Self-hosted. No Paperclip account required. + +```bash +npx paperclipai onboard --yes +``` + +Or manually: + +```bash +git clone https://github.com/paperclipai/paperclip.git +cd paperclip +pnpm install +pnpm dev +``` + +This starts the API server at `http://localhost:3100`. An embedded PostgreSQL database is created automatically — no setup required. + +> **Requirements:** Node.js 20+, pnpm 9.15+ + +
+ +## FAQ + +**What does a typical setup look like?** +Locally, a single Node.js process manages an embedded Postgres and local file storage. For production, point it at your own Postgres and deploy however you like. Configure projects, agents, and goals — the agents take care of the rest. + +If you're a solo-entreprenuer you can use Tailscale to access Paperclip on the go. Then later you can deploy to e.g. Vercel when you need it. + +**Can I run multiple companies?** +Yes. A single deployment can run an unlimited number of companies with complete data isolation. + +**How is Paperclip different from agents like OpenClaw or Claude Code?** +Paperclip _uses_ those agents. It orchestrates them into a company — with org charts, budgets, goals, governance, and accountability. + +**Why should I use Paperclip instead of just pointing my OpenClaw to Asana or Trello?** +Agent orchestration has subtleties in how you coordinate who has work checked out, how to maintain sessions, monitoring costs, establishing governance - Paperclip does this for you. + +(Bring-your-own-ticket-system is on the Roadmap) + +**Do agents run continuously?** +By default, agents run on scheduled heartbeats and event-based triggers (task assignment, @-mentions). You can also hook in continuous agents like OpenClaw. You bring your agent and Paperclip coordinates. + +
+ +## Development + +```bash +pnpm dev # Full dev (API + UI, watch mode) +pnpm dev:once # Full dev without file watching +pnpm dev:server # Server only +pnpm build # Build all +pnpm typecheck # Type checking +pnpm test:run # Run tests +pnpm db:generate # Generate DB migration +pnpm db:migrate # Apply migrations +``` + +See [doc/DEVELOPING.md](https://github.com/paperclipai/paperclip/blob/master/doc/DEVELOPING.md) for the full development guide. + +
+ +## Roadmap + +- ✅ Plugin system (e.g. add a knowledge base, custom tracing, queues, etc) +- ✅ Get OpenClaw / claw-style agent employees +- ✅ companies.sh - import and export entire organizations +- ✅ Easy AGENTS.md configurations +- ✅ Skills Manager +- ✅ Scheduled Routines +- ✅ Better Budgeting +- ⚪ Artifacts & Deployments +- ⚪ CEO Chat +- ⚪ MAXIMIZER MODE +- ⚪ Multiple Human Users +- ⚪ Cloud / Sandbox agents (e.g. Cursor / e2b agents) +- ⚪ Cloud deployments +- ⚪ Desktop App + +
+ +## Community & Plugins + +Find Plugins and more at [awesome-paperclip](https://github.com/gsxdsm/awesome-paperclip) + +## Contributing + +We welcome contributions. See the [contributing guide](https://github.com/paperclipai/paperclip/blob/master/CONTRIBUTING.md) for details. + +
+ +## Community + +- [Discord](https://discord.gg/m4HZY7xNG3) — Join the community +- [GitHub Issues](https://github.com/paperclipai/paperclip/issues) — bugs and feature requests +- [GitHub Discussions](https://github.com/paperclipai/paperclip/discussions) — ideas and RFC + +
+ +## License + +MIT © 2026 Paperclip + +## Star History + +[![Star History Chart](https://api.star-history.com/image?repos=paperclipai/paperclip&type=date&legend=top-left)](https://www.star-history.com/?repos=paperclipai%2Fpaperclip&type=date&legend=top-left) + +
+ +--- + +

+ +

+ +

+ Open source under MIT. Built for people who want to run companies, not babysit agents. +

From 54b05d6d68f1a2b768e91196b1d696bab8aae02a Mon Sep 17 00:00:00 2001 From: dotta Date: Sat, 28 Mar 2026 21:44:15 -0500 Subject: [PATCH 2/4] Make onboarding reruns preserve existing config Co-Authored-By: Paperclip --- README.md | 2 + cli/README.md | 2 + cli/src/__tests__/onboard.test.ts | 105 ++++++++++++++++++++++++++++++ cli/src/commands/onboard.ts | 75 ++++++++++++++++++++- docs/cli/setup-commands.md | 4 ++ docs/start/quickstart.md | 2 + 6 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 cli/src/__tests__/onboard.test.ts diff --git a/README.md b/README.md index f7ade1b3..42f24cd1 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,8 @@ Open source. Self-hosted. No Paperclip account required. npx paperclipai onboard --yes ``` +If you already have Paperclip configured, rerunning `onboard` keeps the existing config in place. Use `paperclipai configure` to edit settings. + Or manually: ```bash diff --git a/cli/README.md b/cli/README.md index c5a6ce13..08f36ad4 100644 --- a/cli/README.md +++ b/cli/README.md @@ -177,6 +177,8 @@ Open source. Self-hosted. No Paperclip account required. npx paperclipai onboard --yes ``` +If you already have Paperclip configured, rerunning `onboard` keeps the existing config in place. Use `paperclipai configure` to edit settings. + Or manually: ```bash diff --git a/cli/src/__tests__/onboard.test.ts b/cli/src/__tests__/onboard.test.ts new file mode 100644 index 00000000..a5ffe44a --- /dev/null +++ b/cli/src/__tests__/onboard.test.ts @@ -0,0 +1,105 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { onboard } from "../commands/onboard.js"; +import type { PaperclipConfig } from "../config/schema.js"; + +const ORIGINAL_ENV = { ...process.env }; + +function createExistingConfigFixture() { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "paperclip-onboard-")); + const runtimeRoot = path.join(root, "runtime"); + const configPath = path.join(root, ".paperclip", "config.json"); + const config: PaperclipConfig = { + $meta: { + version: 1, + updatedAt: "2026-03-29T00:00:00.000Z", + source: "configure", + }, + database: { + mode: "embedded-postgres", + embeddedPostgresDataDir: path.join(runtimeRoot, "db"), + embeddedPostgresPort: 54329, + backup: { + enabled: true, + intervalMinutes: 60, + retentionDays: 30, + dir: path.join(runtimeRoot, "backups"), + }, + }, + logging: { + mode: "file", + logDir: path.join(runtimeRoot, "logs"), + }, + server: { + deploymentMode: "local_trusted", + exposure: "private", + host: "127.0.0.1", + port: 3100, + allowedHostnames: [], + serveUi: true, + }, + auth: { + baseUrlMode: "auto", + disableSignUp: false, + }, + storage: { + provider: "local_disk", + localDisk: { + baseDir: path.join(runtimeRoot, "storage"), + }, + s3: { + bucket: "paperclip", + region: "us-east-1", + prefix: "", + forcePathStyle: false, + }, + }, + secrets: { + provider: "local_encrypted", + strictMode: false, + localEncrypted: { + keyFilePath: path.join(runtimeRoot, "secrets", "master.key"), + }, + }, + }; + + fs.mkdirSync(path.dirname(configPath), { recursive: true }); + fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 }); + + return { configPath, configText: fs.readFileSync(configPath, "utf8") }; +} + +describe("onboard", () => { + beforeEach(() => { + process.env = { ...ORIGINAL_ENV }; + delete process.env.PAPERCLIP_AGENT_JWT_SECRET; + delete process.env.PAPERCLIP_SECRETS_MASTER_KEY; + delete process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE; + }); + + afterEach(() => { + process.env = { ...ORIGINAL_ENV }; + }); + + it("preserves an existing config when rerun without flags", async () => { + const fixture = createExistingConfigFixture(); + + await onboard({ config: fixture.configPath }); + + expect(fs.readFileSync(fixture.configPath, "utf8")).toBe(fixture.configText); + expect(fs.existsSync(`${fixture.configPath}.backup`)).toBe(false); + expect(fs.existsSync(path.join(path.dirname(fixture.configPath), ".env"))).toBe(true); + }); + + it("preserves an existing config when rerun with --yes", async () => { + const fixture = createExistingConfigFixture(); + + await onboard({ config: fixture.configPath, yes: true, invokedByRun: true }); + + expect(fs.readFileSync(fixture.configPath, "utf8")).toBe(fixture.configText); + expect(fs.existsSync(`${fixture.configPath}.backup`)).toBe(false); + expect(fs.existsSync(path.join(path.dirname(fixture.configPath), ".env"))).toBe(true); + }); +}); diff --git a/cli/src/commands/onboard.ts b/cli/src/commands/onboard.ts index 523484f3..d470354f 100644 --- a/cli/src/commands/onboard.ts +++ b/cli/src/commands/onboard.ts @@ -244,11 +244,12 @@ export async function onboard(opts: OnboardOptions): Promise { ), ); + let existingConfig: PaperclipConfig | null = null; if (configExists(opts.config)) { - p.log.message(pc.dim(`${configPath} exists, updating config`)); + p.log.message(pc.dim(`${configPath} exists`)); try { - readConfig(opts.config); + existingConfig = readConfig(opts.config); } catch (err) { p.log.message( pc.yellow( @@ -258,6 +259,76 @@ export async function onboard(opts: OnboardOptions): Promise { } } + if (existingConfig) { + p.log.message( + pc.dim("Existing Paperclip install detected; keeping the current configuration unchanged."), + ); + p.log.message(pc.dim(`Use ${pc.cyan("paperclipai configure")} if you want to change settings.`)); + + const jwtSecret = ensureAgentJwtSecret(configPath); + const envFilePath = resolveAgentJwtEnvFile(configPath); + if (jwtSecret.created) { + p.log.success(`Created ${pc.cyan("PAPERCLIP_AGENT_JWT_SECRET")} in ${pc.dim(envFilePath)}`); + } else if (process.env.PAPERCLIP_AGENT_JWT_SECRET?.trim()) { + p.log.info(`Using existing ${pc.cyan("PAPERCLIP_AGENT_JWT_SECRET")} from environment`); + } else { + p.log.info(`Using existing ${pc.cyan("PAPERCLIP_AGENT_JWT_SECRET")} in ${pc.dim(envFilePath)}`); + } + + const keyResult = ensureLocalSecretsKeyFile(existingConfig, configPath); + if (keyResult.status === "created") { + p.log.success(`Created local secrets key file at ${pc.dim(keyResult.path)}`); + } else if (keyResult.status === "existing") { + p.log.message(pc.dim(`Using existing local secrets key file at ${keyResult.path}`)); + } + + p.note( + [ + "Existing config preserved", + `Database: ${existingConfig.database.mode}`, + existingConfig.llm ? `LLM: ${existingConfig.llm.provider}` : "LLM: not configured", + `Logging: ${existingConfig.logging.mode} -> ${existingConfig.logging.logDir}`, + `Server: ${existingConfig.server.deploymentMode}/${existingConfig.server.exposure} @ ${existingConfig.server.host}:${existingConfig.server.port}`, + `Allowed hosts: ${existingConfig.server.allowedHostnames.length > 0 ? existingConfig.server.allowedHostnames.join(", ") : "(loopback only)"}`, + `Auth URL mode: ${existingConfig.auth.baseUrlMode}${existingConfig.auth.publicBaseUrl ? ` (${existingConfig.auth.publicBaseUrl})` : ""}`, + `Storage: ${existingConfig.storage.provider}`, + `Secrets: ${existingConfig.secrets.provider} (strict mode ${existingConfig.secrets.strictMode ? "on" : "off"})`, + "Agent auth: PAPERCLIP_AGENT_JWT_SECRET configured", + ].join("\n"), + "Configuration ready", + ); + + p.note( + [ + `Run: ${pc.cyan("paperclipai run")}`, + `Reconfigure later: ${pc.cyan("paperclipai configure")}`, + `Diagnose setup: ${pc.cyan("paperclipai doctor")}`, + ].join("\n"), + "Next commands", + ); + + let shouldRunNow = opts.run === true || opts.yes === true; + if (!shouldRunNow && !opts.invokedByRun && process.stdin.isTTY && process.stdout.isTTY) { + const answer = await p.confirm({ + message: "Start Paperclip now?", + initialValue: true, + }); + if (!p.isCancel(answer)) { + shouldRunNow = answer; + } + } + + if (shouldRunNow && !opts.invokedByRun) { + process.env.PAPERCLIP_OPEN_ON_LISTEN = "true"; + const { runCommand } = await import("./run.js"); + await runCommand({ config: configPath, repair: true, yes: true }); + return; + } + + p.outro("Existing Paperclip setup is ready."); + return; + } + let setupMode: SetupMode = "quickstart"; if (opts.yes) { p.log.message(pc.dim("`--yes` enabled: using Quickstart defaults.")); diff --git a/docs/cli/setup-commands.md b/docs/cli/setup-commands.md index 7dc5cd6a..448ab7bb 100644 --- a/docs/cli/setup-commands.md +++ b/docs/cli/setup-commands.md @@ -33,6 +33,8 @@ Interactive first-time setup: pnpm paperclipai onboard ``` +If Paperclip is already configured, rerunning `onboard` keeps the existing config in place. Use `paperclipai configure` to change settings on an existing install. + First prompt: 1. `Quickstart` (recommended): local defaults (embedded database, no LLM provider, local disk storage, default secrets) @@ -50,6 +52,8 @@ Non-interactive defaults + immediate start (opens browser on server listen): pnpm paperclipai onboard --yes ``` +On an existing install, `--yes` now preserves the current config and just starts Paperclip with that setup. + ## `paperclipai doctor` Health checks with optional auto-repair: diff --git a/docs/start/quickstart.md b/docs/start/quickstart.md index 1ad30fcd..2abe538b 100644 --- a/docs/start/quickstart.md +++ b/docs/start/quickstart.md @@ -13,6 +13,8 @@ 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 From 19b6adc415f767979f78f71f884e5b91c44f4a3d Mon Sep 17 00:00:00 2001 From: dotta Date: Sat, 28 Mar 2026 22:00:55 -0500 Subject: [PATCH 3/4] Use exported tsx CLI entrypoint Co-Authored-By: Paperclip --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 749cc8d0..e2095929 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "db:migrate": "pnpm --filter @paperclipai/db migrate", "secrets:migrate-inline-env": "tsx scripts/migrate-inline-env-secrets.ts", "db:backup": "./scripts/backup-db.sh", - "paperclipai": "node cli/node_modules/tsx/dist/cli.mjs cli/src/index.ts", + "paperclipai": "tsx cli/src/index.ts", "build:npm": "./scripts/build-npm.sh", "release": "./scripts/release.sh", "release:canary": "./scripts/release.sh canary", From fc2be204e23c665940b041bfbf7c3c01a770245e Mon Sep 17 00:00:00 2001 From: dotta Date: Mon, 30 Mar 2026 06:49:15 -0500 Subject: [PATCH 4/4] Fix CLI README Discord badge Co-Authored-By: Paperclip --- cli/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/README.md b/cli/README.md index 08f36ad4..1826e376 100644 --- a/cli/README.md +++ b/cli/README.md @@ -12,7 +12,7 @@

MIT License Stars - Discord + Discord