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
new file mode 100644
index 00000000..1826e376
--- /dev/null
+++ b/cli/README.md
@@ -0,0 +1,292 @@
+
+
+
+
+
+ Quickstart ·
+ Docs ·
+ GitHub ·
+ 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.
+
+
+
+
+
+
+
+## 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
+```
+
+If you already have Paperclip configured, rerunning `onboard` keeps the existing config in place. Use `paperclipai configure` to edit settings.
+
+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
+
+[](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.
+
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
diff --git a/package.json b/package.json
index 9433fbeb..6e4ce789 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",