nexus/.planning/phases/01-foundation/01-01-PLAN.md
Mikkel Georgsen 6c4272ce85 [nexus] chore: migrate .planning/ from agent repo to nexus repo
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>
2026-04-04 03:55:42 +00:00

346 lines
11 KiB
Markdown

---
phase: 01-foundation
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- packages/branding/package.json
- packages/branding/tsconfig.json
- packages/branding/src/index.ts
- packages/branding/src/vocab.ts
- packages/branding/src/vocab.test.ts
- packages/branding/vitest.config.ts
- vitest.config.ts
autonomous: true
requirements: [FOUND-01]
must_haves:
truths:
- "import { VOCAB } from '@paperclipai/branding' resolves and returns an object with all required vocabulary keys"
- "VOCAB.company equals 'Workspace', VOCAB.ceo equals 'Project Manager', VOCAB.appName equals 'Nexus'"
- "Unit tests pass confirming every VOCAB key has the correct string value"
artifacts:
- path: "packages/branding/package.json"
provides: "Workspace package definition"
contains: "@paperclipai/branding"
- path: "packages/branding/src/vocab.ts"
provides: "VOCAB constant with all display strings"
exports: ["VOCAB", "VocabKey"]
- path: "packages/branding/src/index.ts"
provides: "Package barrel export"
exports: ["VOCAB", "VocabKey"]
- path: "packages/branding/src/vocab.test.ts"
provides: "Unit tests for VOCAB shape and values"
min_lines: 20
key_links:
- from: "packages/branding/src/index.ts"
to: "packages/branding/src/vocab.ts"
via: "re-export"
pattern: "export.*from.*vocab"
- from: "vitest.config.ts"
to: "packages/branding"
via: "projects array entry"
pattern: "packages/branding"
---
<objective>
Create the `packages/branding/` workspace package that centralizes all Nexus fork-specific display strings in a single `VOCAB` constant. This is the string mutation surface that all downstream phases (2, 3, 4) will import from.
Purpose: Isolate all Nexus vocabulary from upstream Paperclip code so that rebase operations never conflict on display strings.
Output: A working, tested `@paperclipai/branding` package importable by any workspace member.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-foundation/01-RESEARCH.md
</context>
<interfaces>
<!-- Reference package pattern from packages/shared/ — executor should replicate this structure -->
From packages/shared/package.json:
```json
{
"name": "@paperclipai/shared",
"version": "0.3.1",
"license": "MIT",
"type": "module",
"exports": {
".": "./src/index.ts",
"./*": "./src/*.ts"
},
"publishConfig": {
"access": "public",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./*": {
"types": "./dist/*.d.ts",
"import": "./dist/*.js"
}
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"files": ["dist"],
"scripts": {
"build": "tsc",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit"
}
}
```
From packages/shared/tsconfig.json:
```json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
```
From vitest.config.ts (root):
```typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
projects: ["packages/db", "packages/adapters/opencode-local", "server", "ui", "cli"],
},
});
```
From pnpm-workspace.yaml (confirms packages/* glob):
```yaml
packages:
- packages/*
- packages/adapters/*
- packages/plugins/*
- packages/plugins/examples/*
- server
- ui
- cli
```
</interfaces>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Scaffold branding package and write VOCAB constant with tests</name>
<files>
packages/branding/package.json,
packages/branding/tsconfig.json,
packages/branding/src/vocab.ts,
packages/branding/src/vocab.test.ts,
packages/branding/src/index.ts,
packages/branding/vitest.config.ts
</files>
<read_first>
/Volumes/UsbNvme/repos/nexus/packages/shared/package.json,
/Volumes/UsbNvme/repos/nexus/packages/shared/tsconfig.json,
/Volumes/UsbNvme/repos/nexus/packages/shared/src/index.ts,
/Volumes/UsbNvme/repos/nexus/pnpm-workspace.yaml
</read_first>
<behavior>
- Test: VOCAB has key "company" with value "Workspace"
- Test: VOCAB has key "companies" with value "Workspaces"
- Test: VOCAB has key "ceo" with value "Project Manager"
- Test: VOCAB has key "board" with value "Owner"
- Test: VOCAB has key "hire" with value "Add"
- Test: VOCAB has key "fire" with value "Remove"
- Test: VOCAB has key "appName" with value "Nexus"
- Test: VOCAB has key "tagline" with value "Open-source orchestration for your agents"
- Test: VocabKey type is exported (TypeScript compilation succeeds)
- Test: All VOCAB values are non-empty strings
</behavior>
<action>
1. Create `packages/branding/package.json` following the `packages/shared/package.json` pattern exactly:
- `"name": "@paperclipai/branding"` (keep @paperclipai scope per upstream sync constraint)
- `"version": "0.1.0"`
- `"license": "MIT"`
- `"type": "module"`
- `"exports": { ".": "./src/index.ts", "./*": "./src/*.ts" }`
- `"publishConfig"` with dist paths matching shared pattern
- `"files": ["dist"]`
- `"scripts": { "build": "tsc", "clean": "rm -rf dist", "typecheck": "tsc --noEmit" }`
- `"devDependencies": { "typescript": "^5.7.3" }` — no runtime dependencies
2. Create `packages/branding/tsconfig.json`:
```json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
```
3. Create `packages/branding/vitest.config.ts`:
```typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
include: ["src/**/*.test.ts"],
},
});
```
4. Create `packages/branding/src/vocab.ts` with the VOCAB constant:
```typescript
export const VOCAB = {
// Entity renames (display only — code identifiers unchanged)
company: "Workspace",
companies: "Workspaces",
ceo: "Project Manager",
board: "Owner",
hire: "Add",
fire: "Remove",
// Brand name
appName: "Nexus",
tagline: "Open-source orchestration for your agents",
} as const;
export type VocabKey = keyof typeof VOCAB;
```
5. Create `packages/branding/src/index.ts`:
```typescript
export { VOCAB, type VocabKey } from "./vocab.js";
```
6. Create `packages/branding/src/vocab.test.ts` — RED first (write tests before verifying they pass):
```typescript
import { describe, it, expect } from "vitest";
import { VOCAB } from "./vocab.js";
describe("VOCAB", () => {
it("maps company to Workspace", () => {
expect(VOCAB.company).toBe("Workspace");
});
it("maps companies to Workspaces", () => {
expect(VOCAB.companies).toBe("Workspaces");
});
it("maps ceo to Project Manager", () => {
expect(VOCAB.ceo).toBe("Project Manager");
});
it("maps board to Owner", () => {
expect(VOCAB.board).toBe("Owner");
});
it("maps hire to Add", () => {
expect(VOCAB.hire).toBe("Add");
});
it("maps fire to Remove", () => {
expect(VOCAB.fire).toBe("Remove");
});
it("has appName as Nexus", () => {
expect(VOCAB.appName).toBe("Nexus");
});
it("has a non-empty tagline", () => {
expect(VOCAB.tagline).toBe("Open-source orchestration for your agents");
});
it("all values are non-empty strings", () => {
for (const [key, value] of Object.entries(VOCAB)) {
expect(typeof value).toBe("string");
expect(value.length).toBeGreaterThan(0);
}
});
});
```
7. Run `pnpm install` from repo root to link the new workspace package.
8. Run tests to confirm GREEN: `pnpm vitest run --project packages/branding`
</action>
<verify>
<automated>cd /Volumes/UsbNvme/repos/nexus && pnpm vitest run --project packages/branding</automated>
</verify>
<acceptance_criteria>
- packages/branding/package.json contains `"name": "@paperclipai/branding"`
- packages/branding/package.json contains `"type": "module"`
- packages/branding/package.json contains `"exports"`
- packages/branding/src/vocab.ts contains `export const VOCAB`
- packages/branding/src/vocab.ts contains `as const`
- packages/branding/src/vocab.ts contains `company: "Workspace"`
- packages/branding/src/vocab.ts contains `ceo: "Project Manager"`
- packages/branding/src/vocab.ts contains `appName: "Nexus"`
- packages/branding/src/vocab.ts contains `export type VocabKey`
- packages/branding/src/index.ts contains `export { VOCAB`
- packages/branding/src/vocab.test.ts contains `describe("VOCAB"`
- packages/branding/tsconfig.json contains `extends": "../../tsconfig.base.json"`
- `pnpm vitest run --project packages/branding` exits 0 with all tests passing
</acceptance_criteria>
<done>
All 9 VOCAB tests pass. Package exports VOCAB and VocabKey. Package is linked in pnpm workspace.
</done>
</task>
<task type="auto">
<name>Task 2: Register branding package in root vitest config</name>
<files>vitest.config.ts</files>
<read_first>
/Volumes/UsbNvme/repos/nexus/vitest.config.ts
</read_first>
<action>
Edit `vitest.config.ts` at the repo root to add `"packages/branding"` to the `projects` array:
```typescript
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
projects: ["packages/db", "packages/adapters/opencode-local", "server", "ui", "cli", "packages/branding"],
},
});
```
The only change is appending `"packages/branding"` to the end of the existing `projects` array.
After editing, run `pnpm vitest run --project packages/branding` to confirm the root config picks up the new project.
</action>
<verify>
<automated>cd /Volumes/UsbNvme/repos/nexus && pnpm vitest run --project packages/branding</automated>
</verify>
<acceptance_criteria>
- vitest.config.ts contains `"packages/branding"` in the projects array
- `pnpm vitest run --project packages/branding` exits 0
</acceptance_criteria>
<done>
Root vitest config includes branding package. Running `pnpm vitest run --project packages/branding` from root succeeds.
</done>
</task>
</tasks>
<verification>
1. `pnpm vitest run --project packages/branding` — all VOCAB tests pass
2. `node -e "const b = await import('./packages/branding/src/index.ts'); console.log(b.VOCAB.appName)"` — prints "Nexus" (requires tsx or similar TS runner)
3. `test -f packages/branding/package.json && echo OK` — package.json exists
</verification>
<success_criteria>
- `@paperclipai/branding` package exists at `packages/branding/`
- `VOCAB` constant exports 8 keys: company, companies, ceo, board, hire, fire, appName, tagline
- All values are correct Nexus display strings
- Unit tests pass via vitest
- Package is registered in root vitest config
</success_criteria>
<output>
After completion, create `.planning/phases/01-foundation/01-01-SUMMARY.md`
</output>