Planning artifacts (milestones v1.0-v1.2.1, v1.3 queue, PROJECT.md, STATE.md, config) now live alongside the code they describe. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
272 lines
9.5 KiB
Markdown
272 lines
9.5 KiB
Markdown
# Technology Stack
|
|
|
|
**Analysis Date:** 2026-03-30
|
|
**Project Name:** Paperclip (package name `paperclip`, npm org `@paperclipai`)
|
|
|
|
---
|
|
|
|
## Languages
|
|
|
|
**Primary:**
|
|
- TypeScript 5.7.x — all source code across every package, compiled to ESM
|
|
- JavaScript (ESM) — build scripts, generated output
|
|
|
|
**Secondary:**
|
|
- Bash — release scripts, smoke tests, DB backup (`scripts/`, `tests/`)
|
|
|
|
---
|
|
|
|
## Runtime
|
|
|
|
**Environment:**
|
|
- Node.js >=20 (enforced via `engines` in root `package.json`)
|
|
- ESM-first: all packages set `"type": "module"`
|
|
- `tsx` (^4.19.2) used as TS runner during development and for CLI execution
|
|
|
|
**Package Manager:**
|
|
- pnpm 9.15.4 (pinned via `packageManager` field)
|
|
- Lockfile: `pnpm-lock.yaml` — present and committed
|
|
- Patched dependency: `embedded-postgres@18.1.0-beta.16` (patch in `patches/`)
|
|
|
|
---
|
|
|
|
## Monorepo Structure
|
|
|
|
**Workspace layout** (`pnpm-workspace.yaml`):
|
|
```
|
|
packages/*
|
|
packages/adapters/*
|
|
packages/plugins/*
|
|
packages/plugins/examples/*
|
|
server
|
|
ui
|
|
cli
|
|
```
|
|
|
|
**Packages:**
|
|
|
|
| Package | Name | Purpose |
|
|
|---------|------|---------|
|
|
| `server/` | `@paperclipai/server` | Express HTTP server + WebSocket + plugin host |
|
|
| `ui/` | `@paperclipai/ui` | React SPA (board UI) |
|
|
| `cli/` | `paperclipai` | CLI binary (Node.js, esbuild-bundled) |
|
|
| `packages/db/` | `@paperclipai/db` | Drizzle ORM schema, migrations, embedded-postgres helpers |
|
|
| `packages/shared/` | `@paperclipai/shared` | Shared Zod schemas and TypeScript types |
|
|
| `packages/adapter-utils/` | `@paperclipai/adapter-utils` | Shared utilities across AI adapters |
|
|
| `packages/adapters/claude-local/` | `@paperclipai/adapter-claude-local` | Adapter for Anthropic Claude Code CLI |
|
|
| `packages/adapters/codex-local/` | `@paperclipai/adapter-codex-local` | Adapter for OpenAI Codex CLI |
|
|
| `packages/adapters/cursor-local/` | `@paperclipai/adapter-cursor-local` | Adapter for Cursor editor agent |
|
|
| `packages/adapters/gemini-local/` | `@paperclipai/adapter-gemini-local` | Adapter for Google Gemini CLI |
|
|
| `packages/adapters/openclaw-gateway/` | `@paperclipai/adapter-openclaw-gateway` | Gateway adapter (WebSocket, external agent relay) |
|
|
| `packages/adapters/opencode-local/` | `@paperclipai/adapter-opencode-local` | Adapter for opencode-ai CLI |
|
|
| `packages/adapters/pi-local/` | `@paperclipai/adapter-pi-local` | Adapter for pi.ai |
|
|
| `packages/plugins/sdk/` | `@paperclipai/plugin-sdk` | Public plugin API (worker-side + UI bridge hooks) |
|
|
|
|
---
|
|
|
|
## Backend Framework
|
|
|
|
**HTTP Server:**
|
|
- Express 5.1.0 (`express`) — REST API, static file serving, middleware chain
|
|
- `@types/express` 5.0.0
|
|
|
|
**WebSocket (Realtime):**
|
|
- `ws` ^8.18.0 — native WebSocket server at `server/src/realtime/live-events-ws.ts`
|
|
- Used for live event streaming to the board UI
|
|
|
|
**Authentication:**
|
|
- `better-auth` 1.4.18 — pluggable auth library with Drizzle adapter
|
|
- Session handling at `server/src/auth/better-auth.ts`
|
|
- JWT used for agent-to-server auth (`server/src/agent-auth-jwt.ts`)
|
|
|
|
**Validation:**
|
|
- `zod` ^3.24.2 — schema validation throughout server and shared packages
|
|
- `ajv` ^8.18.0 + `ajv-formats` ^3.0.1 — JSON Schema validation (plugin manifests)
|
|
|
|
**Logging:**
|
|
- `pino` ^9.6.0 — structured JSON logging
|
|
- `pino-http` ^10.4.0 — HTTP request logging middleware
|
|
- `pino-pretty` ^13.1.3 — dev-mode pretty-print
|
|
|
|
**File Handling:**
|
|
- `multer` ^2.0.2 — multipart/form-data upload handling
|
|
- `sharp` ^0.34.5 — server-side image processing
|
|
|
|
**HTML Sanitization:**
|
|
- `dompurify` ^3.3.2 + `jsdom` ^28.1.0 — server-side sanitization of rich text
|
|
|
|
---
|
|
|
|
## Database
|
|
|
|
**ORM:**
|
|
- `drizzle-orm` ^0.38.4 — TypeScript ORM, query builder
|
|
- `drizzle-kit` ^0.31.9 — migration generation (`drizzle-kit generate`)
|
|
|
|
**Driver:**
|
|
- `postgres` ^3.4.5 — native PostgreSQL client
|
|
|
|
**Database Server:**
|
|
- PostgreSQL 17 (Docker: `postgres:17-alpine`)
|
|
- `embedded-postgres` ^18.1.0-beta.16 — bundled PostgreSQL for local/single-binary deployments (patched)
|
|
|
|
**Schema location:** `packages/db/src/schema/` — 50+ individual table files
|
|
**Migrations:** `packages/db/src/migrations/`
|
|
**Client factory:** `packages/db/src/client.ts` (`createDb(url)`)
|
|
|
|
**Database modes:**
|
|
- `embedded-postgres` — default for local CLI use (no external DB required)
|
|
- `postgres` — external PostgreSQL for Docker/production deployments
|
|
|
|
---
|
|
|
|
## Frontend Framework
|
|
|
|
**Framework:**
|
|
- React 19.0.0 (`react`, `react-dom`)
|
|
- React Router DOM 7.1.5 (`react-router-dom`) — SPA routing
|
|
- React Query / TanStack Query 5.x (`@tanstack/react-query`) — server state, data fetching
|
|
|
|
**Build Tool:**
|
|
- Vite 6.1.0 — dev server (port 5173) and production bundler
|
|
- `@vitejs/plugin-react` ^4.3.4 — JSX/Fast Refresh
|
|
- In dev mode, Vite runs as Express middleware via `vite.middlewares` integration
|
|
|
|
**Styling:**
|
|
- Tailwind CSS 4.0.7 — utility-first CSS
|
|
- `@tailwindcss/vite` ^4.0.7 — Vite plugin
|
|
- `@tailwindcss/typography` ^0.5.19 — prose styles
|
|
- `tailwind-merge` ^3.0+ — conditional class merging
|
|
- `class-variance-authority` ^0.7.1 — component variant management
|
|
- `clsx` ^2.1.1 — conditional class names
|
|
|
|
**UI Components:**
|
|
- `radix-ui` ^1.4.3 — unstyled accessible primitives
|
|
- `@radix-ui/react-slot` ^1.2.4
|
|
- Component files in `ui/src/components/ui/`: button, card, dialog, input, badge, tabs, tooltip, etc. (shadcn-style pattern)
|
|
- `lucide-react` ^0.574.0 — icon library
|
|
- `cmdk` ^1.1.1 — command palette
|
|
|
|
**Rich Text / Markdown:**
|
|
- `@mdxeditor/editor` ^3.52.4 — rich markdown editor component
|
|
- `lexical` 0.35.0 + `@lexical/link` — editor framework (peer dep of MDXEditor)
|
|
- `react-markdown` ^10.1.0 — Markdown rendering
|
|
- `remark-gfm` ^4.0.1 — GitHub-flavored Markdown
|
|
- `mermaid` ^11.12.0 — diagram rendering
|
|
|
|
**Drag-and-Drop:**
|
|
- `@dnd-kit/core` ^6.3.1, `@dnd-kit/sortable` ^10.0.0, `@dnd-kit/utilities` ^3.2.2
|
|
|
|
**Path Alias:** `@/` maps to `ui/src/` (configured in `vite.config.ts`)
|
|
|
|
---
|
|
|
|
## CLI
|
|
|
|
**Framework:**
|
|
- `commander` ^13.1.0 — command parsing
|
|
- `@clack/prompts` ^0.10.0 — interactive terminal prompts
|
|
- `picocolors` ^1.1.1 — terminal color output
|
|
|
|
**Build:**
|
|
- `esbuild` ^0.27.3 — bundles CLI to single `dist/index.js` (config: `cli/esbuild.config.mjs`)
|
|
|
|
---
|
|
|
|
## Storage
|
|
|
|
**Providers (runtime-selectable):**
|
|
- Local disk — `server/src/storage/local-disk-provider.ts` — default, stores under `PAPERCLIP_HOME`
|
|
- AWS S3 — `server/src/storage/s3-provider.ts` — via `@aws-sdk/client-s3` ^3.888.0
|
|
|
|
**Secrets:**
|
|
- Local encrypted provider — `server/src/secrets/local-encrypted-provider.ts`
|
|
- External stub providers — `server/src/secrets/external-stub-providers.ts`
|
|
|
|
---
|
|
|
|
## Testing Frameworks
|
|
|
|
**Unit / Integration:**
|
|
- Vitest ^3.0.5 — test runner (configured in root `vitest.config.ts` as multi-project)
|
|
- Projects under test: `packages/db`, `packages/adapters/opencode-local`, `server`, `ui`, `cli`
|
|
- Server tests: `server/src/__tests__/` (~95 test files)
|
|
- Server vitest config: `server/vitest.config.ts` (env: `node`)
|
|
- `supertest` ^7.0.0 — HTTP integration testing for Express routes
|
|
|
|
**E2E:**
|
|
- Playwright ^1.58.2 — browser E2E tests
|
|
- Config: `tests/e2e/playwright.config.ts`
|
|
- Browser: Chromium only
|
|
- `tests/e2e/` — feature specs, `tests/release-smoke/` — release smoke tests
|
|
|
|
**Evaluations:**
|
|
- `promptfoo` 0.103.3 — LLM prompt evaluation (`evals/promptfoo/`)
|
|
|
|
---
|
|
|
|
## Build and Tooling
|
|
|
|
**TypeScript:**
|
|
- TypeScript 5.7.3 across all packages
|
|
- Base config: `tsconfig.base.json` — target ES2023, `NodeNext` module resolution, strict mode
|
|
- Each package extends base or defines its own `tsconfig.json`
|
|
|
|
**Dev Runner:**
|
|
- `scripts/dev-runner.mjs` — coordinates parallel dev processes (server + UI)
|
|
- `chokidar` ^4.0.3 — file watching in server dev mode
|
|
|
|
**CLI published as:** `paperclipai` on npm (binary: `dist/index.js`)
|
|
**Server published as:** `@paperclipai/server` on npm
|
|
**Plugin SDK published as:** `@paperclipai/plugin-sdk` on npm
|
|
|
|
---
|
|
|
|
## Docker / Deployment
|
|
|
|
**Base image:** `node:lts-trixie-slim` (Debian-based)
|
|
|
|
**Multi-stage Dockerfile:**
|
|
1. `base` — Node + pnpm + ca-certificates + curl + git
|
|
2. `deps` — install all dependencies with frozen lockfile
|
|
3. `build` — build UI, plugin-sdk, server in order
|
|
4. `production` — copy build output; globally install `@anthropic-ai/claude-code`, `@openai/codex`, `opencode-ai`
|
|
|
|
**Port:** 3100 (configurable via `PORT` env var)
|
|
**Data volume:** `/paperclip` — all persistent state (DB, uploads, config)
|
|
|
|
**Compose variants:**
|
|
- `docker-compose.yml` — full stack with external Postgres 17
|
|
- `docker-compose.quickstart.yml` — single container, embedded Postgres
|
|
- `docker-compose.untrusted-review.yml` — special security sandbox mode
|
|
|
|
**Key env vars:**
|
|
- `DATABASE_URL` — external PostgreSQL URL (omit for embedded mode)
|
|
- `BETTER_AUTH_SECRET` — required auth secret
|
|
- `PAPERCLIP_DEPLOYMENT_MODE` — `authenticated` | `unauthenticated`
|
|
- `PAPERCLIP_DEPLOYMENT_EXPOSURE` — `private` | `public`
|
|
- `PAPERCLIP_PUBLIC_URL` — public-facing URL
|
|
- `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` — AI provider keys
|
|
- `PAPERCLIP_HOME` — data root directory (default `/paperclip` in Docker)
|
|
|
|
---
|
|
|
|
## AI Agent Integrations (Adapters)
|
|
|
|
Each adapter follows a consistent three-export pattern: `./server`, `./ui`, `./cli`.
|
|
|
|
| Adapter | Target Agent CLI |
|
|
|---------|-----------------|
|
|
| `adapter-claude-local` | `@anthropic-ai/claude-code` |
|
|
| `adapter-codex-local` | `@openai/codex` |
|
|
| `adapter-cursor-local` | Cursor editor |
|
|
| `adapter-gemini-local` | Gemini CLI |
|
|
| `adapter-openclaw-gateway` | Remote agent relay (WebSocket, `ws`) |
|
|
| `adapter-opencode-local` | `opencode-ai` |
|
|
| `adapter-pi-local` | pi.ai |
|
|
|
|
The `hermes-paperclip-adapter` 0.1.1 is an additional server-side dependency (third-party adapter protocol).
|
|
|
|
---
|
|
|
|
*Stack analysis: 2026-03-30*
|