Merge pull request #2071 from paperclipai/pap-979-cli-onboarding
cli: preserve config when onboarding existing installs
This commit is contained in:
commit
29da357c5b
7 changed files with 479 additions and 3 deletions
|
|
@ -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
|
||||
|
|
|
|||
292
cli/README.md
Normal file
292
cli/README.md
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
<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/badge/discord-join%20chat-5865F2?logo=discord&logoColor=white" 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>
|
||||
105
cli/src/__tests__/onboard.test.ts
Normal file
105
cli/src/__tests__/onboard.test.ts
Normal file
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
@ -244,11 +244,12 @@ export async function onboard(opts: OnboardOptions): Promise<void> {
|
|||
),
|
||||
);
|
||||
|
||||
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<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";
|
||||
if (opts.yes) {
|
||||
p.log.message(pc.dim("`--yes` enabled: using Quickstart defaults."));
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue