Compare commits
No commits in common. "19b6adc415f767979f78f71f884e5b91c44f4a3d" and "6a72faf83b3aeb35ee44da51898fe8cbce6f5002" have entirely different histories.
19b6adc415
...
6a72faf83b
7 changed files with 3 additions and 479 deletions
|
|
@ -177,8 +177,6 @@ Open source. Self-hosted. No Paperclip account required.
|
||||||
npx paperclipai onboard --yes
|
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:
|
Or manually:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
292
cli/README.md
292
cli/README.md
|
|
@ -1,292 +0,0 @@
|
||||||
<p align="center">
|
|
||||||
<img src="https://raw.githubusercontent.com/paperclipai/paperclip/master/doc/assets/header.png" alt="Paperclip — runs your business" width="720" />
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="#quickstart"><strong>Quickstart</strong></a> ·
|
|
||||||
<a href="https://paperclip.ing/docs"><strong>Docs</strong></a> ·
|
|
||||||
<a href="https://github.com/paperclipai/paperclip"><strong>GitHub</strong></a> ·
|
|
||||||
<a href="https://discord.gg/m4HZY7xNG3"><strong>Discord</strong></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://github.com/paperclipai/paperclip/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License" /></a>
|
|
||||||
<a href="https://github.com/paperclipai/paperclip/stargazers"><img src="https://img.shields.io/github/stars/paperclipai/paperclip?style=flat" alt="Stars" /></a>
|
|
||||||
<a href="https://discord.gg/m4HZY7xNG3"><img src="https://img.shields.io/discord/000000000?label=discord" alt="Discord" /></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<video src="https://github.com/user-attachments/assets/773bdfb2-6d1e-4e30-8c5f-3487d5b70c8f" width="600" controls></video>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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. |
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
> **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.
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<div align="center">
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><strong>Works<br/>with</strong></td>
|
|
||||||
<td align="center"><img src="https://raw.githubusercontent.com/paperclipai/paperclip/master/doc/assets/logos/openclaw.svg" width="32" alt="OpenClaw" /><br/><sub>OpenClaw</sub></td>
|
|
||||||
<td align="center"><img src="https://raw.githubusercontent.com/paperclipai/paperclip/master/doc/assets/logos/claude.svg" width="32" alt="Claude" /><br/><sub>Claude Code</sub></td>
|
|
||||||
<td align="center"><img src="https://raw.githubusercontent.com/paperclipai/paperclip/master/doc/assets/logos/codex.svg" width="32" alt="Codex" /><br/><sub>Codex</sub></td>
|
|
||||||
<td align="center"><img src="https://raw.githubusercontent.com/paperclipai/paperclip/master/doc/assets/logos/cursor.svg" width="32" alt="Cursor" /><br/><sub>Cursor</sub></td>
|
|
||||||
<td align="center"><img src="https://raw.githubusercontent.com/paperclipai/paperclip/master/doc/assets/logos/bash.svg" width="32" alt="Bash" /><br/><sub>Bash</sub></td>
|
|
||||||
<td align="center"><img src="https://raw.githubusercontent.com/paperclipai/paperclip/master/doc/assets/logos/http.svg" width="32" alt="HTTP" /><br/><sub>HTTP</sub></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<em>If it can receive a heartbeat, it's hired.</em>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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**
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td align="center" width="33%">
|
|
||||||
<h3>🔌 Bring Your Own Agent</h3>
|
|
||||||
Any agent, any runtime, one org chart. If it can receive a heartbeat, it's hired.
|
|
||||||
</td>
|
|
||||||
<td align="center" width="33%">
|
|
||||||
<h3>🎯 Goal Alignment</h3>
|
|
||||||
Every task traces back to the company mission. Agents know <em>what</em> to do and <em>why</em>.
|
|
||||||
</td>
|
|
||||||
<td align="center" width="33%">
|
|
||||||
<h3>💓 Heartbeats</h3>
|
|
||||||
Agents wake on a schedule, check work, and act. Delegation flows up and down the org chart.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center">
|
|
||||||
<h3>💰 Cost Control</h3>
|
|
||||||
Monthly budgets per agent. When they hit the limit, they stop. No runaway costs.
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<h3>🏢 Multi-Company</h3>
|
|
||||||
One deployment, many companies. Complete data isolation. One control plane for your portfolio.
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<h3>🎫 Ticket System</h3>
|
|
||||||
Every conversation traced. Every decision explained. Full tool-call tracing and immutable audit log.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center">
|
|
||||||
<h3>🛡️ Governance</h3>
|
|
||||||
You're the board. Approve hires, override strategy, pause or terminate any agent — at any time.
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<h3>📊 Org Chart</h3>
|
|
||||||
Hierarchies, roles, reporting lines. Your agents have a boss, a title, and a job description.
|
|
||||||
</td>
|
|
||||||
<td align="center">
|
|
||||||
<h3>📱 Mobile Ready</h3>
|
|
||||||
Monitor and manage your autonomous businesses from anywhere.
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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. |
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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. |
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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. |
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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+
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT © 2026 Paperclip
|
|
||||||
|
|
||||||
## Star History
|
|
||||||
|
|
||||||
[](https://www.star-history.com/?repos=paperclipai%2Fpaperclip&type=date&legend=top-left)
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<img src="https://raw.githubusercontent.com/paperclipai/paperclip/master/doc/assets/footer.jpg" alt="" width="720" />
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p align="center">
|
|
||||||
<sub>Open source under MIT. Built for people who want to run companies, not babysit agents.</sub>
|
|
||||||
</p>
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -244,12 +244,11 @@ export async function onboard(opts: OnboardOptions): Promise<void> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let existingConfig: PaperclipConfig | null = null;
|
|
||||||
if (configExists(opts.config)) {
|
if (configExists(opts.config)) {
|
||||||
p.log.message(pc.dim(`${configPath} exists`));
|
p.log.message(pc.dim(`${configPath} exists, updating config`));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
existingConfig = readConfig(opts.config);
|
readConfig(opts.config);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
p.log.message(
|
p.log.message(
|
||||||
pc.yellow(
|
pc.yellow(
|
||||||
|
|
@ -259,76 +258,6 @@ export async function onboard(opts: OnboardOptions): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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";
|
let setupMode: SetupMode = "quickstart";
|
||||||
if (opts.yes) {
|
if (opts.yes) {
|
||||||
p.log.message(pc.dim("`--yes` enabled: using Quickstart defaults."));
|
p.log.message(pc.dim("`--yes` enabled: using Quickstart defaults."));
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,6 @@ Interactive first-time setup:
|
||||||
pnpm paperclipai onboard
|
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:
|
First prompt:
|
||||||
|
|
||||||
1. `Quickstart` (recommended): local defaults (embedded database, no LLM provider, local disk storage, default secrets)
|
1. `Quickstart` (recommended): local defaults (embedded database, no LLM provider, local disk storage, default secrets)
|
||||||
|
|
@ -52,8 +50,6 @@ Non-interactive defaults + immediate start (opens browser on server listen):
|
||||||
pnpm paperclipai onboard --yes
|
pnpm paperclipai onboard --yes
|
||||||
```
|
```
|
||||||
|
|
||||||
On an existing install, `--yes` now preserves the current config and just starts Paperclip with that setup.
|
|
||||||
|
|
||||||
## `paperclipai doctor`
|
## `paperclipai doctor`
|
||||||
|
|
||||||
Health checks with optional auto-repair:
|
Health checks with optional auto-repair:
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,6 @@ npx paperclipai onboard --yes
|
||||||
|
|
||||||
This walks you through setup, configures your environment, and gets Paperclip running.
|
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:
|
To start Paperclip again later:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
"db:migrate": "pnpm --filter @paperclipai/db migrate",
|
"db:migrate": "pnpm --filter @paperclipai/db migrate",
|
||||||
"secrets:migrate-inline-env": "tsx scripts/migrate-inline-env-secrets.ts",
|
"secrets:migrate-inline-env": "tsx scripts/migrate-inline-env-secrets.ts",
|
||||||
"db:backup": "./scripts/backup-db.sh",
|
"db:backup": "./scripts/backup-db.sh",
|
||||||
"paperclipai": "tsx cli/src/index.ts",
|
"paperclipai": "node cli/node_modules/tsx/dist/cli.mjs cli/src/index.ts",
|
||||||
"build:npm": "./scripts/build-npm.sh",
|
"build:npm": "./scripts/build-npm.sh",
|
||||||
"release": "./scripts/release.sh",
|
"release": "./scripts/release.sh",
|
||||||
"release:canary": "./scripts/release.sh canary",
|
"release:canary": "./scripts/release.sh canary",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue