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>
342 lines
22 KiB
Markdown
342 lines
22 KiB
Markdown
# Codebase Concerns — Paperclip Fork (Nexus)
|
|
|
|
**Analysis Date:** 2026-03-30
|
|
**Source repo:** `/Volumes/UsbNvme/repos/nexus`
|
|
**Fork goal:** Rename company→project, CEO→Project Manager, Board→Owner. UI overhaul, onboarding redesign, directory restructure.
|
|
|
|
---
|
|
|
|
## Terminology Embedding Depth
|
|
|
|
### "company" — Pervasive at All Layers
|
|
|
|
The word `company` is not a UI display string. It is a core identifier embedded at every layer of the stack.
|
|
|
|
**Database schema — DO NOT rename columns:**
|
|
- `packages/db/src/schema/companies.ts` — table `companies`, all columns use `company_id`
|
|
- `packages/db/src/schema/agents.ts` — `company_id` FK column on every agent
|
|
- `packages/db/src/schema/approvals.ts` — `company_id` column
|
|
- `packages/db/src/schema/company_memberships.ts` — table name + `company_id`
|
|
- `packages/db/src/schema/goals.ts` — `company_id` column; `level` field has value `"company"` as a constant
|
|
- `packages/db/src/schema/company_logos.ts`, `company_secrets.ts`, `company_skills.ts` — table names with `company_` prefix
|
|
- 47 migration SQL files in `packages/db/src/migrations/` reference `company_id` columns — renaming is impossible without new migrations and data migration
|
|
|
|
**TypeScript types — must be renamed carefully:**
|
|
- `packages/shared/src/types/company.ts` — exports `interface Company`
|
|
- `packages/shared/src/types/company-portability.ts` — ~15 exported interfaces all named `CompanyPortability*`
|
|
- `packages/shared/src/types/agent.ts` — `companyId` field on `Agent`, `AgentInstructionsBundle`, `AgentAccessState`
|
|
- `packages/shared/src/constants.ts` — `COMPANY_STATUSES`, `BUDGET_SCOPE_TYPES` contains `"company"` string, `GOAL_LEVELS` contains `"company"` string, `PLUGIN_CAPABILITIES` contains `"companies.read"`, `PLUGIN_RESERVED_COMPANY_ROUTE_SEGMENTS` contains `"company"` and `"companies"`, plugin event types include `"company.created"` and `"company.updated"`
|
|
|
|
**API routes — affect URL shape:**
|
|
- `server/src/routes/companies.ts` — `/api/companies/:companyId` prefix for all company operations
|
|
- `server/src/routes/*.ts` — almost every route file takes `/:companyId` in the path
|
|
- `packages/shared/src/api.ts` — `API.companies = "/api/companies"` constant drives all frontend API calls
|
|
- `ui/src/api/companies.ts` — all company API calls
|
|
- `ui/src/context/CompanyContext.tsx` — `CompanyContext`, `CompanyProvider`, `useCompany`, `createCompany`; also uses `localStorage.setItem("paperclip.selectedCompanyId", ...)` as a persisted key
|
|
|
|
**UI components:**
|
|
- `ui/src/components/CompanyRail.tsx`, `CompanySwitcher.tsx`, `CompanyPatternIcon.tsx`
|
|
- `ui/src/pages/Companies.tsx`, `CompanySettings.tsx`, `CompanySkills.tsx`, `CompanyExport.tsx`, `CompanyImport.tsx`
|
|
- `ui/src/hooks/useCompanyPageMemory.ts`
|
|
- `ui/src/lib/company-routes.ts` — routing helpers named `BOARD_ROUTE_ROOTS`, `extractCompanyPrefixFromPath`, `normalizeCompanyPrefix`
|
|
- `ui/src/lib/company-export-selection.ts`, `company-portability-sidebar.ts`, `company-page-memory.ts`
|
|
|
|
**CLI — user-visible command names:**
|
|
- `cli/src/commands/client/company.ts` — CLI commands named `company import`, `company export`, etc.
|
|
- `cli/src/__tests__/company.test.ts`, `company-delete.test.ts`, `company-import-*.test.ts`
|
|
- `cli/src/index.ts` — registers company sub-commands on the CLI tree
|
|
|
|
**Server services:**
|
|
- `server/src/services/companies.ts` — `companyService()`
|
|
- `server/src/services/company-portability.ts`, `company-skills.ts`, `company-export-readme.ts`
|
|
|
|
**Impact:** Renaming `company` to `project` in code will conflict with the existing `projects` concept (there is already a `Project` entity distinct from `Company`). This is the single highest-risk rename.
|
|
|
|
---
|
|
|
|
### "CEO" — In Code, Not Just UI
|
|
|
|
**Constants (breaking if changed):**
|
|
- `packages/shared/src/constants.ts` line 38: `AGENT_ROLES` array contains `"ceo"` as a string literal
|
|
- `packages/shared/src/constants.ts` line 53: `AGENT_ROLE_LABELS` maps `ceo: "CEO"`
|
|
- `packages/shared/src/constants.ts` line 332: `INVITE_TYPES` contains `"bootstrap_ceo"`
|
|
- `packages/shared/src/constants.ts` line 187: `APPROVAL_TYPES` contains `"approve_ceo_strategy"`
|
|
- `packages/shared/src/types/agent.ts` — `taskAssignSource` field has literal value `"ceo_role"`
|
|
|
|
**CLI commands:**
|
|
- `cli/src/commands/auth-bootstrap-ceo.ts` — exported function `bootstrapCeoInvite`
|
|
- `cli/src/index.ts` line 146: `.command("bootstrap-ceo")` — this is a user-typed command
|
|
- `cli/src/commands/onboard.ts` — calls `bootstrapCeoInvite`, displays "Generating bootstrap CEO invite" in terminal output, generates invite URL with path `/invite/...` and message "Created bootstrap CEO invite"
|
|
- `cli/src/commands/run.ts` — imports `bootstrapCeoInvite`
|
|
|
|
**Server services:**
|
|
- `server/src/services/default-agent-instructions.ts` — `resolveDefaultAgentInstructionsBundleRole()` returns `"ceo"` for the ceo role; `DEFAULT_AGENT_BUNDLE_FILES` has `ceo:` key; reads from `onboarding-assets/ceo/` directory
|
|
- `server/src/services/approvals.ts` lines 112, 179 — checks `type === "hire_agent"` (not CEO specifically but linked)
|
|
|
|
**Onboarding assets — must be rewritten:**
|
|
- `server/src/onboarding-assets/ceo/SOUL.md` — "You are the CEO." throughout; contains `"board"`, `"hire"`, `"fire"` language extensively
|
|
- `server/src/onboarding-assets/ceo/AGENTS.md` — "You are the CEO. Your job is to lead the company..."; references board, hire, fire, CTO, CMO, delegates using `paperclip-create-agent` skill
|
|
- `server/src/onboarding-assets/ceo/HEARTBEAT.md`, `TOOLS.md` — same corpus
|
|
- `server/src/onboarding-assets/default/AGENTS.md` — likely also contains company/board references
|
|
|
|
**UI:**
|
|
- `ui/src/components/OnboardingWizard.tsx` line 114: `agentName` default is `"CEO"`
|
|
- `ui/src/components/OnboardingWizard.tsx` line 71: `DEFAULT_TASK_DESCRIPTION` starts with `"You are the CEO. You set the direction for the company."` and contains `"hire a founding engineer"`
|
|
- `ui/src/components/ApprovalPayload.tsx` lines 5-6: `approve_ceo_strategy: "CEO Strategy"` in display map; line 21: `approve_ceo_strategy: Lightbulb` in icon map
|
|
- `ui/src/pages/App.tsx` line 62: shows `pnpm paperclipai auth bootstrap-ceo` as UI copy
|
|
- `ui/src/pages/InviteLanding.tsx` — checks `invite.inviteType === "bootstrap_ceo"` in 5 places; displays "Bootstrap your Paperclip instance"
|
|
|
|
**Database values (stored in rows):**
|
|
- The `role` column on the `agents` table can contain `"ceo"`. Any existing databases have `"ceo"` stored as a role value. A rename would require a data migration.
|
|
- The `invites.invite_type` column stores `"bootstrap_ceo"` as a string value.
|
|
- The `approvals.type` column stores `"approve_ceo_strategy"` as a string value.
|
|
|
|
---
|
|
|
|
### "Board" — Auth System Identity
|
|
|
|
**Board = the human operator role.** This is deeply baked into the auth and API key system.
|
|
|
|
**Service layer:**
|
|
- `server/src/services/board-auth.ts` — `boardAuthService()`, `createBoardApiToken()` returns tokens prefixed `pcp_board_...`, `touchBoardApiKey()`, `revokeBoardApiKey()`, `resolveBoardAccess()`, `resolveBoardActivityCompanyIds()`
|
|
- `server/src/middleware/board-mutation-guard.ts` — middleware that guards write operations by board users
|
|
- `server/src/board-claim.ts` — dedicated board claim flow
|
|
|
|
**Database schema:**
|
|
- `packages/db/src/schema/board_api_keys.ts` — table named `board_api_keys`
|
|
- `packages/db/src/schema/cli_auth_challenges.ts` — column `requested_access` stores `"board"` as a value
|
|
|
|
**Token prefixes (stored in DB, shared with CLI):**
|
|
- `server/src/services/board-auth.ts` line 30: `pcp_board_${...}` — tokens with this prefix are stored in the DB and used by the CLI
|
|
- `cli/src/client/board-auth.ts` — CLI-side board authentication
|
|
|
|
**Constants:**
|
|
- `packages/db/src/schema/companies.ts` line 16: `requireBoardApprovalForNewAgents` column
|
|
- `packages/shared/src/types/company.ts`: `requireBoardApprovalForNewAgents` field on `Company`
|
|
- `packages/shared/src/types/company-portability.ts`: `requireBoardApprovalForNewAgents` in the manifest type
|
|
|
|
**UI:**
|
|
- `ui/src/pages/BoardClaim.tsx` — page for claiming board access
|
|
- `ui/src/lib/company-routes.ts` line 1: `BOARD_ROUTE_ROOTS` set used for routing logic; the name encodes the concept
|
|
|
|
**Impact:** Renaming `board` to `owner` requires changing token prefixes (`pcp_board_` → `pcp_owner_`), the `board_api_keys` DB table name (requires migration), and all auth middleware. Token prefix changes break existing issued tokens — any users with `pcp_board_*` tokens will be logged out.
|
|
|
|
---
|
|
|
|
### "hire" / "fire" — In Approval Types and Agent Instructions
|
|
|
|
**Code-level occurrences:**
|
|
- `packages/shared/src/constants.ts` line 187: `APPROVAL_TYPES` contains `"hire_agent"` — stored in DB `approvals.type` column
|
|
- `server/src/services/hire-hook.ts` — entire file named after hire; exports `notifyHireApproved`, uses `HireApprovedPayload` type from `packages/adapter-utils/src/types.ts`
|
|
- `packages/adapter-utils/src/types.ts` line 213: `HireApprovedPayload` interface; line 277: `onHireApproved` lifecycle hook on `ServerAdapterModule`
|
|
- `server/src/routes/agents.ts` line 1228: creates `type: "hire_agent"` approval
|
|
- `server/src/routes/approvals.ts` line 66, 281: checks `type === "hire_agent"`
|
|
- `cli/src/commands/client/approval.ts` line 114: CLI option says `hire_agent|approve_ceo_strategy`
|
|
- `ui/src/components/ApprovalPayload.tsx` line 5: `hire_agent: "Hire Agent"` in label map
|
|
- `ui/src/components/ApprovalPayload.tsx` line 131: branching on `type === "hire_agent"`
|
|
|
|
**Agent instruction content:**
|
|
- `server/src/onboarding-assets/ceo/SOUL.md` line 15: "Hire slow, fire fast"
|
|
- `server/src/onboarding-assets/ceo/AGENTS.md` line 6: "Hire new agents when the team needs capacity"
|
|
- `server/src/onboarding-assets/ceo/AGENTS.md` line 16: delegates via `paperclip-create-agent` skill with instruction to hire
|
|
- `skills/paperclip-create-agent/` skill is entirely named around hiring
|
|
|
|
**Stored DB values:** `hire_agent` appears in the `approvals.type` column. Existing rows cannot be silently changed. A rename requires either a data migration or keeping the stored value while changing the label only.
|
|
|
|
---
|
|
|
|
## Data Directory Concerns
|
|
|
|
### `~/.paperclip` — The Home Directory
|
|
|
|
**All path roots use the name "paperclip":**
|
|
- `server/src/home-paths.ts` line 18: `path.resolve(os.homedir(), ".paperclip")` — default home dir
|
|
- `server/src/home-paths.ts` — exported functions: `resolvePaperclipHomeDir()`, `resolvePaperclipInstanceId()`, `resolvePaperclipInstanceRoot()`
|
|
- `cli/src/config/home.ts` line 10: same `.paperclip` default
|
|
- `server/src/paths.ts` line 13: looks for `.paperclip/config.json` when searching ancestor directories for config
|
|
- `cli/src/config/store.ts` line 16: same ancestor search for `.paperclip/config.json`
|
|
- `cli/src/client/context.ts` line 25: looks for `.paperclip/context.json`
|
|
|
|
**Environment variable names:**
|
|
- `PAPERCLIP_HOME` — overrides the home directory
|
|
- `PAPERCLIP_INSTANCE_ID` — overrides instance ID
|
|
- `PAPERCLIP_CONFIG` — overrides config path
|
|
- `PAPERCLIP_AGENT_JWT_SECRET` — agent auth secret
|
|
- `PAPERCLIP_PUBLIC_URL`, `PAPERCLIP_DEPLOYMENT_MODE`, `PAPERCLIP_DEPLOYMENT_EXPOSURE`, `PAPERCLIP_ALLOWED_HOSTNAMES`, `PAPERCLIP_AUTH_*`, `PAPERCLIP_STORAGE_*`, `PAPERCLIP_SECRETS_*`
|
|
- These appear in ~25+ places across `cli/src/commands/onboard.ts`, `server/src/home-paths.ts`, `server/src/startup-banner.ts`, `server/src/ui-branding.ts`, Docker files
|
|
|
|
**Impact:** Renaming `~/.paperclip` to `~/.nexus` requires changing:
|
|
1. The default string in `server/src/home-paths.ts` and `cli/src/config/home.ts`
|
|
2. All `PAPERCLIP_*` env var names (breaking change for existing deployments)
|
|
3. Docker config `PAPERCLIP_HOME: "/home/reviewer/.paperclip-review"` in `docker-compose.untrusted-review.yml`
|
|
4. Shell scripts `scripts/provision-worktree.sh` and `scripts/backup-db.sh`
|
|
5. Docs in `doc/DATABASE.md`, `doc/DOCKER.md`, `doc/SPEC-implementation.md`
|
|
6. The `.paperclip/config.json` ancestor-search path logic
|
|
|
|
---
|
|
|
|
### "companies" Subdirectory in Instance Root
|
|
|
|
- `server/src/services/agent-instructions.ts` line 135: agent instructions are stored at `~/.paperclip/instances/<id>/companies/<companyId>/agents/<agentId>/instructions/`
|
|
- `server/src/services/company-skills.ts` line 1282: skills stored at `~/.paperclip/instances/<id>/skills/<companyId>`
|
|
- `server/src/home-paths.ts` line 85: managed project workspaces stored at `~/.paperclip/instances/<id>/projects/<companyId>/<projectId>/<repoName>/`
|
|
|
|
These paths are embedded in the filesystem on any existing deployment. Renaming `companies` in the path would break existing agent instruction directories unless a migration script is provided.
|
|
|
|
---
|
|
|
|
### `.paperclip.yaml` Portability File
|
|
|
|
- `server/src/services/company-portability.ts` — the export format emits `.paperclip.yaml` as a sidecar file
|
|
- `cli/src/commands/client/company.ts` lines 183, 189-190: CLI detects and processes `.paperclip.yaml` and `.paperclip.yml`
|
|
- `ui/src/pages/CompanyExport.tsx` lines 75, 778-785: UI references `.paperclip.yaml`
|
|
- The file format is documented in `docs/companies/companies-spec.md` under the `schema: paperclip/v1` header
|
|
|
|
**Impact:** Any exported company bundles from the upstream will have `.paperclip.yaml` files. If Nexus renames to `.nexus.yaml`, these files become incompatible. Either keep reading `.paperclip.yaml` (and emit `.nexus.yaml`) or accept breaking import compatibility.
|
|
|
|
---
|
|
|
|
## "paperclip" Brand in Package Names and Token Prefixes
|
|
|
|
**npm package names:**
|
|
- `cli/package.json`: `"name": "paperclipai"` — the CLI binary is named `paperclipai`
|
|
- `packages/shared/package.json`: `"name": "@paperclipai/shared"`
|
|
- `packages/db/package.json`: `"name": "@paperclipai/db"`
|
|
- `packages/adapter-utils/package.json`: `"name": "@paperclipai/adapter-utils"`
|
|
- All internal imports use `@paperclipai/*` throughout the entire monorepo
|
|
|
|
**Impact:** Renaming packages requires updating every `import` statement in the codebase (thousands of occurrences). The `pnpm-workspace.yaml` and all `package.json` dependency declarations must also change. This is purely mechanical but extremely high volume.
|
|
|
|
**API token prefixes:**
|
|
- `pcp_board_*` — board API keys stored in DB
|
|
- `pcp_bootstrap_*` — CEO bootstrap invite tokens stored in DB
|
|
- `pcp_cli_auth_*` — CLI auth challenge tokens stored in DB
|
|
|
|
These are stored as values in the database. If renamed, existing tokens become invalid unless the server accepts both prefixes.
|
|
|
|
**CLI binary name:**
|
|
- `package.json` script: `"paperclipai": "node cli/node_modules/tsx/dist/cli.mjs cli/src/index.ts"`
|
|
- CLI displays `paperclipai onboard`, `paperclipai run`, `paperclipai auth bootstrap-ceo`
|
|
- `ui/src/App.tsx` renders `pnpm paperclipai auth bootstrap-ceo` as literal user-facing instruction
|
|
- `server/src/startup-banner.ts` line 96: `run \`pnpm paperclipai onboard\`` as warning text
|
|
|
|
---
|
|
|
|
## Onboarding Flow — High Complexity Change
|
|
|
|
### UI Onboarding Wizard
|
|
|
|
The onboarding wizard (`ui/src/components/OnboardingWizard.tsx`) is the primary first-run experience. It is deeply coupled to the corporate metaphor:
|
|
|
|
- Step 1 prompts for "company name" and "company goal" — variables named `companyName`, `companyGoal`
|
|
- Step 2 creates the first agent with default name `"CEO"`, default description: *"You are the CEO. You set the direction for the company. - hire a founding engineer - write a hiring plan..."*
|
|
- Step 3 creates the first task with `taskTitle` defaulting to `"Hire your first engineer and create a hiring plan"`
|
|
- The entire flow uses `companiesApi.create()` which calls `/api/companies`
|
|
- `ui/src/lib/onboarding-launch.ts` — `ONBOARDING_PROJECT_NAME = "Onboarding"` and `selectDefaultCompanyGoalId()` filters `goal.level === "company"`
|
|
|
|
**The onboarding wizard must be substantially rewritten** to replace company creation with project creation (given company maps to project in Nexus). However, since the DB entity is still `company`, this is a UI-layer rename only — the API calls still go to `/api/companies`.
|
|
|
|
### CLI Onboarding
|
|
|
|
`cli/src/commands/onboard.ts` is the other half of onboarding:
|
|
- Displays banner: `p.intro(pc.bgCyan(pc.black(" paperclipai onboard ")))`
|
|
- Calls `bootstrapCeoInvite` on completion
|
|
- Displays "Start Paperclip now?" prompt
|
|
- Generates next-steps text: `paperclipai run`, `paperclipai configure`, `paperclipai doctor`
|
|
|
|
All terminal strings that reference `paperclipai` and `Paperclip` are hardcoded — there is no i18n or constant layer for branding strings.
|
|
|
|
---
|
|
|
|
## Schema References That Should NOT Change
|
|
|
|
Per the fork PRD, the database schema must stay compatible with upstream. The following identifiers should be left as-is in the database layer, treating them as opaque internal keys:
|
|
|
|
- Table names: `companies`, `company_memberships`, `company_secrets`, `company_skills`, `company_logos`, `board_api_keys`
|
|
- Column names: all `company_id` foreign keys
|
|
- Stored enum values: `"ceo"` in `agents.role`, `"hire_agent"` and `"approve_ceo_strategy"` in `approvals.type`, `"bootstrap_ceo"` in `invites.invite_type`, `"company"` in `goals.level`, `"board"` in `cli_auth_challenges.requested_access`
|
|
|
|
These values exist in the running DB and in migration history. Any rename here requires new migration SQL + data migration.
|
|
|
|
---
|
|
|
|
## Hardcoded Strings vs Constants
|
|
|
|
There is NO i18n or centralized string table for user-facing copy. All UI labels are inline JSX strings or TypeScript constants.
|
|
|
|
**Somewhat centralised (easier to change):**
|
|
- `packages/shared/src/constants.ts` — `AGENT_ROLE_LABELS` maps roles to display strings; changing `ceo: "CEO"` here propagates to wherever the label map is used
|
|
- `packages/shared/src/api.ts` — `API.companies` constant drives all frontend API path construction
|
|
- `ui/src/components/ApprovalPayload.tsx` lines 5-6 — `hire_agent: "Hire Agent"`, `approve_ceo_strategy: "CEO Strategy"` are display-only labels
|
|
|
|
**Fully hardcoded (harder to change):**
|
|
- All terminal output in `cli/src/commands/onboard.ts` — every `p.log.*` call is a literal string
|
|
- `server/src/startup-banner.ts` — the ASCII art says "PAPERCLIP", `resolveAgentJwtSecretStatus` message references `pnpm paperclipai onboard`
|
|
- `ui/src/components/OnboardingWizard.tsx` — `DEFAULT_TASK_DESCRIPTION`, `taskTitle` default, `agentName` default are all hardcoded literals
|
|
- `server/src/onboarding-assets/ceo/SOUL.md` and `AGENTS.md` — plain Markdown prose
|
|
|
|
---
|
|
|
|
## Plugin System Concerns
|
|
|
|
The plugin API surface exposes company-centric types to third-party plugins:
|
|
|
|
- `packages/shared/src/constants.ts` — `PLUGIN_CAPABILITIES` includes `"companies.read"` — this is a capability string that plugins declare in their manifests; changing it breaks all plugins that declare this capability
|
|
- `packages/shared/src/constants.ts` — `PLUGIN_EVENT_TYPES` includes `"company.created"` and `"company.updated"` — changing these breaks plugin event subscriptions
|
|
- `packages/shared/src/constants.ts` — `PLUGIN_RESERVED_COMPANY_ROUTE_SEGMENTS` includes `"company"` and `"companies"` — changing this affects URL routing validation
|
|
- `packages/shared/src/constants.ts` — `PLUGIN_STATE_SCOPE_KINDS` includes `"company"` — plugin state scoped to a company would break
|
|
|
|
Any fork that changes these strings is breaking the plugin API contract. If Nexus wants to maintain upstream plugin compatibility, these must remain unchanged.
|
|
|
|
---
|
|
|
|
## Upstream Sync Risk
|
|
|
|
If this fork intends to periodically merge upstream Paperclip changes:
|
|
|
|
- Any rename of package names (`@paperclipai/*` → `@nexusai/*`) will cause merge conflicts on every upstream file that imports those packages — this is nearly every file
|
|
- Renames of `company` to `project` in service/route files will conflict heavily with upstream changes to the `companies.ts` service
|
|
- Renamed function names (`bootstrapCeoInvite`, `companyService`, `boardAuthService`) will not patch-merge cleanly
|
|
- The `server/src/onboarding-assets/ceo/` directory name, if renamed, creates a merge conflict on any upstream changes to those files
|
|
|
|
**Recommendation:** If upstream sync is a requirement, keep all code-level identifiers unchanged and do only display-layer (UI string) renames. Make a clear boundary between "DB/code identity" (unchanged) and "display vocabulary" (renamed).
|
|
|
|
---
|
|
|
|
## Test Coverage Gaps for Fork Changes
|
|
|
|
**Untested areas relevant to the fork:**
|
|
- The `DEFAULT_TASK_DESCRIPTION` and default `agentName = "CEO"` in `OnboardingWizard.tsx` have no unit tests — changing them is safe but unverified
|
|
- `server/src/onboarding-assets/ceo/` content is loaded at runtime via `fs.readFile` in `default-agent-instructions.ts` — no test validates the file content structure, only the loading mechanism
|
|
- CLI terminal output strings (`p.log.*` calls in `onboard.ts`) are not covered by automated tests — manual smoke tests in `tests/release-smoke/` cover the auth flow but not every string
|
|
|
|
**Covered by tests (risky to change):**
|
|
- `cli/src/__tests__/board-auth.test.ts` — tests the board auth flow including token prefix behavior
|
|
- `server/src/__tests__/hire-hook.test.ts` — tests the hire approval hook
|
|
- `server/src/__tests__/invite-onboarding-text.test.ts` — likely tests invite text containing "CEO"; check before renaming
|
|
- `server/src/__tests__/company-branding-route.test.ts`, `company-portability.test.ts`, `company-portability-routes.test.ts` — all test company-named routes; renaming these routes breaks these tests
|
|
|
|
---
|
|
|
|
## Summary Risk Table
|
|
|
|
| Area | Risk | Breaking Change |
|
|
|------|------|----------------|
|
|
| DB table/column names (`companies`, `company_id`) | **Critical** | Yes — requires migration |
|
|
| Stored enum values (`"ceo"`, `"hire_agent"`, `"bootstrap_ceo"`) | **Critical** | Yes — data migration |
|
|
| `pcp_board_*` token prefix | **High** | Yes — existing tokens invalidated |
|
|
| `@paperclipai/*` package names | **High** | Yes — breaks every import |
|
|
| `PAPERCLIP_*` env var names | **High** | Yes — breaks all existing deployments |
|
|
| `~/.paperclip` home dir | **High** | Yes — breaks existing data paths |
|
|
| `companies/` subdir in instance root | **High** | Yes — breaks existing instruction files |
|
|
| CLI binary name `paperclipai` | **Medium** | Yes — users must relearn commands |
|
|
| `bootstrap-ceo` CLI subcommand | **Medium** | Yes — changes user-facing command |
|
|
| `company.created` plugin event types | **Medium** | Yes — breaks third-party plugins |
|
|
| `.paperclip.yaml` export format | **Medium** | Yes — breaks import of upstream bundles |
|
|
| UI display strings ("company", "CEO", "board") | **Low** | No — display only |
|
|
| `OnboardingWizard` default task/agent text | **Low** | No — display only |
|
|
| Onboarding asset prose (SOUL.md, AGENTS.md) | **Low** | No — content only |
|
|
|
|
---
|
|
|
|
*Concerns audit: 2026-03-30*
|