docs(01): create phase 1 plan

Phase 01: Core Infrastructure
- 5 plans in 3 waves
- Wave 1: Project foundation (01-01)
- Wave 2: CLI, process mgmt, logging (01-02, 01-03, 01-04) [parallel]
- Wave 3: Server mode & shutdown (01-05)
- Ready for execution
This commit is contained in:
Lukas May
2026-01-30 13:06:38 +01:00
parent a315b286fd
commit 074f79b855
7 changed files with 529 additions and 7 deletions

View File

@@ -29,11 +29,14 @@ None
**Depends on**: Nothing (first phase)
**Requirements**: INFRA-01, INFRA-02, INFRA-03, INFRA-04, INFRA-05
**Research**: Unlikely (Node.js process patterns well-documented)
**Plans**: TBD
**Plans**: 5 plans in 3 waves
Plans:
- [ ] 01-01: TBD
- [ ] 01-02: TBD
- [ ] 01-01: Project Foundation (Wave 1)
- [ ] 01-02: CLI Entry Point (Wave 2)
- [ ] 01-03: Process Management (Wave 2)
- [ ] 01-04: Logging Infrastructure (Wave 2)
- [ ] 01-05: Coordination Server & Shutdown (Wave 3)
### Phase 2: Data Layer
**Goal**: SQLite database with Drizzle ORM, task hierarchy schema (initiative → phase → plan → task)
@@ -109,7 +112,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
| 1. Core Infrastructure | 0/? | Not started | - |
| 1. Core Infrastructure | 0/5 | Planned | - |
| 2. Data Layer | 0/? | Not started | - |
| 3. Git Integration | 0/? | Not started | - |
| 4. Agent Lifecycle | 0/? | Not started | - |

View File

@@ -10,9 +10,9 @@ See: .planning/PROJECT.md (updated 2026-01-30)
## Current Position
Phase: 1 of 7 (Core Infrastructure)
Plan: Not started
Status: Ready to plan
Last activity: 2026-01-30 — Project initialized
Plan: 5 plans created, ready to execute
Status: Ready to execute
Last activity: 2026-01-30 — Phase 1 planned
Progress: ░░░░░░░░░░ 0%

View File

@@ -0,0 +1,103 @@
---
phase: 01-core-infrastructure
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: [package.json, tsconfig.json, src/index.ts, bin/cw]
autonomous: true
---
<objective>
Initialize TypeScript project with ESM, build tooling, and bin directory structure.
Purpose: Establish the project foundation that all other Phase 1 plans depend on.
Output: Buildable TypeScript project with `npm run build` and `npm run dev` working.
</objective>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Initialize Node.js project with TypeScript and ESM</name>
<files>package.json, tsconfig.json, .gitignore</files>
<action>
Initialize project with `npm init -y`. Configure for ESM:
- package.json: "type": "module"
- Add dependencies: typescript, @types/node, commander (CLI), execa (process mgmt)
- Add devDependencies: tsx (dev runner), rimraf (clean)
- Configure scripts: build (tsc), dev (tsx watch), clean (rimraf dist)
- Set "bin": { "cw": "./dist/bin/cw.js" }
- Set "main": "./dist/index.js"
tsconfig.json:
- target: ES2022
- module: NodeNext
- moduleResolution: NodeNext
- outDir: ./dist
- rootDir: ./src
- strict: true
- esModuleInterop: true
- declaration: true
Add node_modules and dist to .gitignore.
</action>
<verify>npm install succeeds, npm run build succeeds (even with empty src)</verify>
<done>package.json has correct config, tsconfig.json exists, dependencies installed</done>
</task>
<task type="auto">
<name>Task 2: Create source structure and entry point</name>
<files>src/index.ts, src/bin/cw.ts</files>
<action>
Create directory structure:
- src/bin/cw.ts - CLI entry point (will be built to dist/bin/cw.js)
- src/index.ts - library entry point (exports public API)
src/bin/cw.ts:
- Add shebang: #!/usr/bin/env node
- Import and call main function placeholder
- Log "cw cli v0.0.1" for now
src/index.ts:
- Export version constant
- Export placeholder for future modules
Ensure the bin file is executable after build.
</action>
<verify>npm run build succeeds, node dist/bin/cw.js prints version message</verify>
<done>Build outputs to dist/, bin entry point runs, prints version</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] `npm install` runs without errors
- [ ] `npm run build` compiles TypeScript without errors
- [ ] `node dist/bin/cw.js` outputs version message
- [ ] dist/ contains compiled .js and .d.ts files
- [ ] .gitignore includes node_modules and dist
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- Project builds successfully
- Bin entry point executes
</success_criteria>
<output>
After completion, create `.planning/phases/01-core-infrastructure/01-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,95 @@
---
phase: 01-core-infrastructure
plan: 02
type: execute
wave: 2
depends_on: ["01-01"]
files_modified: [src/bin/cw.ts, src/cli/index.ts, src/cli/commands/index.ts]
autonomous: true
---
<objective>
Create CLI foundation with commander, help system, and version display.
Purpose: Establish the `cw` command as the user-facing entry point for all operations.
Output: Working CLI with `cw --help` and `cw --version` that can be globally installed.
</objective>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-core-infrastructure/01-01-SUMMARY.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Create CLI with commander</name>
<files>src/cli/index.ts, src/bin/cw.ts</files>
<action>
Create src/cli/index.ts:
- Import { Command } from 'commander'
- Create program with name('cw'), description, version from package.json
- Add placeholder commands: 'status', 'agent', 'task' (just stubs that log "not implemented")
- Export createCli() function that returns configured program
Update src/bin/cw.ts:
- Import createCli from '../cli/index.js'
- Call program.parse(process.argv)
- Handle uncaught errors gracefully (log and exit 1)
Read version from package.json using import with assert { type: "json" } or createRequire pattern.
</action>
<verify>npm run build succeeds, node dist/bin/cw.js --help shows commands</verify>
<done>CLI shows help with status/agent/task placeholders, version displays correctly</done>
</task>
<task type="auto">
<name>Task 2: Enable global installation via npm link</name>
<files>package.json, src/bin/cw.ts</files>
<action>
Verify package.json bin field points to correct path: "bin": { "cw": "./dist/bin/cw.js" }
Ensure the built bin file:
- Has correct shebang (#!/usr/bin/env node)
- Is executable (add postbuild script to chmod if needed)
Test npm link workflow:
- Run npm run build
- Run npm link
- Verify 'cw' command available globally
Document in comments: users can install via npm link during development or npm i -g for release.
</action>
<verify>After npm link, running 'cw --version' in any directory shows version</verify>
<done>Global cw command works, help and version display correctly</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] `npm run build` succeeds
- [ ] `cw --help` displays usage with command list
- [ ] `cw --version` displays version from package.json
- [ ] `cw status` outputs "not implemented" placeholder
- [ ] Global install via npm link works
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- CLI is the single entry point for all commands
- Foundation ready for adding real commands in later phases
</success_criteria>
<output>
After completion, create `.planning/phases/01-core-infrastructure/01-02-SUMMARY.md`
</output>

View File

@@ -0,0 +1,100 @@
---
phase: 01-core-infrastructure
plan: 03
type: execute
wave: 2
depends_on: ["01-01"]
files_modified: [src/process/registry.ts, src/process/manager.ts, src/process/types.ts]
autonomous: true
---
<objective>
Create process management utilities for spawning, tracking, and stopping child processes.
Purpose: Infrastructure for managing agent processes in later phases. Agents are child processes that need lifecycle management.
Output: ProcessManager class with spawn, stop, list, and restart operations.
</objective>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Create process types and registry</name>
<files>src/process/types.ts, src/process/registry.ts</files>
<action>
Create src/process/types.ts:
- ProcessInfo interface: { id: string, pid: number, command: string, args: string[], startedAt: Date, status: 'running' | 'stopped' | 'crashed' }
- SpawnOptions: { id: string, command: string, args?: string[], cwd?: string, env?: Record<string, string> }
Create src/process/registry.ts:
- ProcessRegistry class with Map<string, ProcessInfo> storage
- register(info: ProcessInfo): void
- unregister(id: string): void
- get(id: string): ProcessInfo | undefined
- getAll(): ProcessInfo[]
- getByPid(pid: number): ProcessInfo | undefined
- clear(): void
Registry is in-memory for now (Phase 2 adds SQLite persistence).
</action>
<verify>TypeScript compiles, registry can add/remove/list processes</verify>
<done>ProcessRegistry class works with full CRUD operations</done>
</task>
<task type="auto">
<name>Task 2: Create process manager with spawn/stop</name>
<files>src/process/manager.ts, src/process/index.ts</files>
<action>
Create src/process/manager.ts:
- Import execa for process spawning
- ProcessManager class:
- constructor takes ProcessRegistry instance
- spawn(options: SpawnOptions): Promise<ProcessInfo> - spawns detached child, registers in registry, returns info
- stop(id: string): Promise<void> - sends SIGTERM, waits up to 5s, then SIGKILL if needed
- stopAll(): Promise<void> - stops all registered processes
- restart(id: string): Promise<ProcessInfo> - stops then respawns with same config
- isRunning(id: string): boolean - checks if process is alive
Use execa with { detached: true } for background processes.
Store spawned process reference to enable stop/restart.
Handle process exit events to update registry status.
Create src/process/index.ts - export ProcessManager, ProcessRegistry, types.
</action>
<verify>Can spawn a simple process (e.g., sleep 10), list it, stop it</verify>
<done>ProcessManager can spawn, stop, restart, and list child processes</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] `npm run build` succeeds
- [ ] ProcessRegistry correctly tracks process info
- [ ] ProcessManager.spawn() starts a detached process
- [ ] ProcessManager.stop() terminates running process
- [ ] ProcessManager.isRunning() correctly reports status
- [ ] Process exit updates registry status automatically
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- Process lifecycle (spawn → track → stop) works end-to-end
- Infrastructure ready for agent management in Phase 4
</success_criteria>
<output>
After completion, create `.planning/phases/01-core-infrastructure/01-03-SUMMARY.md`
</output>

View File

@@ -0,0 +1,104 @@
---
phase: 01-core-infrastructure
plan: 04
type: execute
wave: 2
depends_on: ["01-01"]
files_modified: [src/logging/types.ts, src/logging/writer.ts, src/logging/manager.ts, src/logging/index.ts]
autonomous: true
---
<objective>
Create file-based logging infrastructure for per-process stdout/stderr capture.
Purpose: Each agent process needs its own log files. This creates the logging infrastructure that agent processes will use.
Output: LogManager that creates and manages per-process log files in a dedicated directory.
</objective>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Create log directory management</name>
<files>src/logging/types.ts, src/logging/manager.ts</files>
<action>
Create src/logging/types.ts:
- LogLevel: 'debug' | 'info' | 'warn' | 'error'
- LogEntry: { timestamp: Date, level: LogLevel, processId: string, message: string }
- LogConfig: { baseDir: string, maxFileSize?: number, retainDays?: number }
Create src/logging/manager.ts:
- LogManager class:
- constructor(config: LogConfig) - baseDir defaults to ~/.cw/logs
- ensureLogDir(): Promise<void> - creates log directory if not exists
- getLogPath(processId: string, stream: 'stdout' | 'stderr'): string
- cleanOldLogs(retainDays: number): Promise<number> - removes logs older than N days
- listLogs(): Promise<string[]> - lists all log files
Use node:fs/promises for all file operations.
Use node:path and node:os for cross-platform paths.
Log directory structure: ~/.cw/logs/{processId}/stdout.log, stderr.log
</action>
<verify>LogManager creates ~/.cw/logs directory, returns correct paths</verify>
<done>Log directory management works, paths are cross-platform correct</done>
</task>
<task type="auto">
<name>Task 2: Create per-process log writer</name>
<files>src/logging/writer.ts, src/logging/index.ts</files>
<action>
Create src/logging/writer.ts:
- ProcessLogWriter class:
- constructor(processId: string, logManager: LogManager)
- open(): Promise<void> - opens file handles for stdout/stderr
- writeStdout(data: string | Buffer): Promise<void>
- writeStderr(data: string | Buffer): Promise<void>
- close(): Promise<void> - flushes and closes file handles
- getStdoutStream(): fs.WriteStream
- getStderrStream(): fs.WriteStream
Use fs.createWriteStream with { flags: 'a' } for append mode.
Add timestamps to each line of output.
Handle backpressure properly (pause source if drain needed).
Create src/logging/index.ts:
- Export LogManager, ProcessLogWriter, types
- Export createLogger(processId: string) convenience function
</action>
<verify>ProcessLogWriter creates files, writes stdout/stderr with timestamps</verify>
<done>Per-process logging captures output to separate files with timestamps</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] `npm run build` succeeds
- [ ] LogManager creates ~/.cw/logs/ directory
- [ ] ProcessLogWriter creates per-process log files
- [ ] Stdout and stderr go to separate files
- [ ] Log entries include timestamps
- [ ] File handles close properly (no resource leaks)
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- Logging infrastructure ready for agent process output capture
- Satisfies INFRA-05 (basic logging captures stdout/stderr per agent)
</success_criteria>
<output>
After completion, create `.planning/phases/01-core-infrastructure/01-04-SUMMARY.md`
</output>

View File

@@ -0,0 +1,117 @@
---
phase: 01-core-infrastructure
plan: 05
type: execute
wave: 3
depends_on: ["01-02", "01-03", "01-04"]
files_modified: [src/server/index.ts, src/server/shutdown.ts, src/cli/commands/server.ts, src/bin/cw.ts]
autonomous: true
---
<objective>
Add server mode to CLI with HTTP health endpoint and graceful shutdown handling.
Purpose: `cw --server` runs the background coordination server that manages agents. Server must handle signals gracefully.
Output: Server mode with health endpoint, PID file, and clean shutdown on SIGTERM/SIGINT.
</objective>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-core-infrastructure/01-02-SUMMARY.md
@.planning/phases/01-core-infrastructure/01-03-SUMMARY.md
@.planning/phases/01-core-infrastructure/01-04-SUMMARY.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Create HTTP server with health endpoint and PID file</name>
<files>src/server/index.ts, src/server/types.ts, src/cli/index.ts</files>
<action>
Create src/server/types.ts:
- ServerConfig: { port: number, host: string, pidFile: string }
- ServerState: { startedAt: Date, processCount: number }
Create src/server/index.ts:
- Use node:http (not Express - keep it minimal)
- CoordinationServer class:
- constructor(config: ServerConfig, processManager: ProcessManager, logManager: LogManager)
- start(): Promise<void> - starts HTTP server, writes PID file
- stop(): Promise<void> - stops server, removes PID file
- isRunning(): boolean
HTTP routes (simple path matching):
- GET /health → { status: 'ok', uptime: number, processCount: number }
- GET /status → { server: ServerState, processes: ProcessInfo[] }
PID file: ~/.cw/server.pid - contains process ID, checked to prevent duplicate servers.
Default port: 3847 (arbitrary, configurable via env CW_PORT).
Update src/cli/index.ts:
- Add --server flag that starts CoordinationServer instead of CLI commands
- Add --port option for custom port
</action>
<verify>cw --server starts HTTP server, curl localhost:3847/health returns OK</verify>
<done>Server mode works, health endpoint responds, PID file created</done>
</task>
<task type="auto">
<name>Task 2: Implement graceful shutdown</name>
<files>src/server/shutdown.ts, src/server/index.ts</files>
<action>
Create src/server/shutdown.ts:
- GracefulShutdown class:
- constructor(server: CoordinationServer, processManager: ProcessManager, logManager: LogManager)
- install(): void - registers signal handlers for SIGTERM, SIGINT, SIGHUP
- shutdown(signal: string): Promise<void> - orchestrates cleanup
Shutdown sequence:
1. Log "Received {signal}, shutting down..."
2. Stop accepting new connections
3. Stop all managed processes (ProcessManager.stopAll())
4. Close all log file handles
5. Remove PID file
6. Exit with code 0
Timeout: If cleanup takes >10s, force exit with code 1.
Handle double-signal: If SIGINT received twice, force immediate exit.
Integrate into CoordinationServer.start() - install shutdown handlers after server starts.
</action>
<verify>cw --server responds to Ctrl+C by logging shutdown and cleaning up</verify>
<done>SIGTERM/SIGINT triggers graceful shutdown, all resources cleaned up</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] `npm run build` succeeds
- [ ] `cw --server` starts server on port 3847
- [ ] `curl localhost:3847/health` returns JSON with status: 'ok'
- [ ] PID file created at ~/.cw/server.pid
- [ ] Ctrl+C (SIGINT) triggers graceful shutdown message
- [ ] PID file removed after shutdown
- [ ] Cannot start second server (PID file check prevents it)
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- Server mode is the foundation for agent coordination
- Graceful shutdown satisfies INFRA-04
- Health endpoint enables monitoring
</success_criteria>
<output>
After completion, create `.planning/phases/01-core-infrastructure/01-05-SUMMARY.md`
</output>