Implementation Plan: Section 1 — Project Foundation
Implementation Plan: Section 1 — Project Foundation
Document Version: 1.0 Date: 2026-02-07 Status: Ready for Implementation Scope: Complete project initialization for Forge MVP
Overview
This plan provides step-by-step instructions to initialize the Forge project from scratch. It covers project setup, dependency selection, repository structure, TypeScript configuration, development tooling, build scripts, CI setup, and enforcement of the five design principles. By following this plan, a developer can set up the entire project skeleton without ambiguity.
Design Principles Reminder
- Start simple, earn complexity — Sequential pipeline first, parallel agents later
- Learn from everything — Every execution feeds the memory system
- Safe by default — Circuit breakers and human gates baked in
- Observable — Every decision logged with rationale, every action attributed
- Tool-agnostic — Swap LLM providers, CI systems, or git hosts without rewriting agents
1. Project Initialization
1.1 Prerequisites
Ensure the following are installed:
- Bun >= 1.0.0 (
curl -fsSL https://bun.sh/install | bash) - Git >= 2.40.0
- Node.js >= 20 (for tooling compatibility, even though Bun is the runtime)
1.2 Create Project Directory
bashmkdir -p forge cd forge bun init -y
This creates a basic Bun project with package.json, tsconfig.json, and README.md.
1.3 Initialize Git Repository
bashgit init echo "node_modules/" > .gitignore echo ".env" >> .gitignore echo ".forge/" >> .gitignore echo "*.db" >> .gitignore echo "*.log" >> .gitignore git add . git commit -m "chore: initialize Forge project"
1.4 Project Metadata
Edit package.json to set project metadata:
json{ "name": "forge", "version": "0.1.0", "description": "An opinionated, buildable AI-driven SDLC orchestrator", "type": "module", "main": "./dist/index.js", "bin": { "forge": "./dist/cli/index.js" }, "scripts": { "dev": "bun --watch src/cli/index.ts", "build": "bun build src/cli/index.ts --outdir dist --target node --minify", "start": "bun dist/cli/index.js", "typecheck": "tsc --noEmit", "lint": "biome check src/", "lint:fix": "biome check --write src/", "format": "biome format --write src/", "test": "bun test", "test:watch": "bun test --watch", "db:generate": "drizzle-kit generate", "db:migrate": "bun src/scripts/migrate.ts", "db:studio": "drizzle-kit studio" }, "keywords": ["ai", "sdlc", "agent", "orchestration", "automation"], "author": "Your Name", "license": "MIT", "engines": { "bun": ">=1.0.0" } }
2. Dependency Selection
2.1 Core Dependencies
bashbun add drizzle-orm better-sqlite3 bun add zod bun add ulid bun add dotenv
Justifications:
| Package | Version | Purpose |
|---|---|---|
drizzle-orm | ^0.36.4 | Type-safe SQL ORM for SQLite |
better-sqlite3 | ^11.7.0 | Fast synchronous SQLite driver |
zod | ^3.24.1 | Runtime schema validation |
ulid | ^2.3.0 | Sortable unique identifiers |
dotenv | ^16.4.7 | Environment variable management |
2.2 LLM Integration
bashbun add @anthropic-ai/sdk
Justification: Official Anthropic SDK for Claude integration. Supports streaming, tool use, and message API.
2.3 Git Operations
bashbun add simple-git
Justification: Simple wrapper for git CLI operations. Async-friendly, well-maintained.
2.4 CLI Tooling
bashbun add commander bun add chalk bun add ora bun add prompts
Justifications:
| Package | Purpose |
|---|---|
commander | CLI argument parsing and command routing |
chalk | Terminal color output |
ora | Spinners and progress indicators |
prompts | Interactive CLI prompts |
2.5 Development Dependencies
bashbun add -D typescript @types/bun @types/better-sqlite3 bun add -D drizzle-kit bun add -D @biomejs/biome bun add -D @types/prompts
Justifications:
| Package | Purpose |
|---|---|
typescript | Type checking |
@types/* | Type definitions |
drizzle-kit | Database migrations and introspection |
@biomejs/biome | Fast linter and formatter (replaces ESLint + Prettier) |
2.6 Final package.json Dependencies Section
json{ "dependencies": { "@anthropic-ai/sdk": "^0.34.0", "better-sqlite3": "^11.7.0", "chalk": "^5.3.0", "commander": "^12.1.0", "dotenv": "^16.4.7", "drizzle-orm": "^0.36.4", "ora": "^8.1.1", "prompts": "^2.4.2", "simple-git": "^3.27.0", "ulid": "^2.3.0", "zod": "^3.24.1" }, "devDependencies": { "@biomejs/biome": "^1.9.4", "@types/better-sqlite3": "^7.6.12", "@types/bun": "^1.1.14", "@types/prompts": "^2.4.9", "drizzle-kit": "^0.29.1", "typescript": "^5.7.3" } }
3. Repository Structure
3.1 Complete Directory Tree
forge/
├── .github/
│ └── workflows/
│ ├── ci.yml
│ └── release.yml
├── .vscode/
│ ├── settings.json
│ └── extensions.json
├── drizzle/
│ └── (auto-generated migration files)
├── src/
│ ├── core/
│ │ ├── types.ts
│ │ ├── bus.ts
│ │ ├── config.ts
│ │ └── errors.ts
│ ├── safety/
│ │ ├── breakers.ts
│ │ ├── gates.ts
│ │ └── budget.ts
│ ├── memory/
│ │ ├── schema.ts
│ │ ├── store.ts
│ │ ├── episodes.ts
│ │ ├── patterns.ts
│ │ ├── procedures.ts
│ │ └── consolidate.ts
│ ├── tools/
│ │ ├── registry.ts
│ │ ├── sandbox.ts
│ │ ├── llm.ts
│ │ ├── git.ts
│ │ ├── github.ts
│ │ ├── runner.ts
│ │ ├── linter.ts
│ │ └── test-runner.ts
│ ├── agents/
│ │ ├── base.ts
│ │ ├── planner.ts
│ │ ├── implementer.ts
│ │ ├── reviewer.ts
│ │ ├── tester.ts
│ │ └── deployer.ts
│ ├── orchestrator/
│ │ ├── pipeline.ts
│ │ ├── checkpoint.ts
│ │ └── context.ts
│ ├── cli/
│ │ ├── index.ts
│ │ ├── commands/
│ │ │ ├── run.ts
│ │ │ ├── review.ts
│ │ │ ├── test.ts
│ │ │ ├── status.ts
│ │ │ └── history.ts
│ │ └── ui.ts
│ ├── scripts/
│ │ └── migrate.ts
│ └── index.ts
├── tests/
│ ├── unit/
│ ├── integration/
│ └── fixtures/
├── .env.example
├── .gitignore
├── biome.json
├── drizzle.config.ts
├── forge.config.ts
├── package.json
├── README.md
└── tsconfig.json
3.2 Create Directory Structure
bashmkdir -p .github/workflows mkdir -p .vscode mkdir -p src/core src/safety src/memory src/tools src/agents src/orchestrator src/cli/commands src/scripts mkdir -p tests/unit tests/integration tests/fixtures mkdir -p drizzle
3.3 Module Map Alignment
This structure matches the Module Map from SYSTEM-DESIGN.md Section 4:
| Design Module | Implementation Path |
|---|---|
core/ | src/core/ |
safety/ | src/safety/ |
memory/ | src/memory/ |
tools/ | src/tools/ |
agents/ | src/agents/ |
orchestrator/ | src/orchestrator/ |
cli/ | src/cli/ |
4. TypeScript Configuration
4.1 tsconfig.json
json{ "compilerOptions": { // Language and module options "target": "ES2022", "module": "ESNext", "lib": ["ES2022"], "moduleResolution": "bundler", // Emit options "outDir": "./dist", "rootDir": "./src", "declaration": true, "declarationMap": true, "sourceMap": true, "removeComments": false, "importHelpers": false, // Type checking - STRICT MODE "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "noImplicitReturns": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "noPropertyAccessFromIndexSignature": true, // Module resolution "resolveJsonModule": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, // Path aliases "baseUrl": ".", "paths": { "@/*": ["src/*"], "@core/*": ["src/core/*"], "@safety/*": ["src/safety/*"], "@memory/*": ["src/memory/*"], "@tools/*": ["src/tools/*"], "@agents/*": ["src/agents/*"], "@orchestrator/*": ["src/orchestrator/*"], "@cli/*": ["src/cli/*"] }, // Bun compatibility "types": ["bun-types"], "allowImportingTsExtensions": true, "noEmit": true }, "include": ["src/**/*", "tests/**/*"], "exclude": ["node_modules", "dist", "drizzle"] }
4.2 Strict Mode Enforcement
Design Principle Mapping: Principle #3 (Safe by default)
strict: true— Catches type errors at compile timenoUnusedLocals/Parameters— Enforces clean codenoUncheckedIndexedAccess— Prevents runtime undefined errorsexactOptionalPropertyTypes— No implicit undefined in optional props
4.3 Path Aliases
Path aliases enable clean imports:
typescript// Before import { EventBus } from '../../../core/bus'; // After import { EventBus } from '@core/bus';
5. Development Tooling
5.1 Biome Configuration (biome.json)
Biome replaces ESLint + Prettier with a single fast tool.
json{ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "organizeImports": { "enabled": true }, "linter": { "enabled": true, "rules": { "recommended": true, "complexity": { "noExtraBooleanCast": "error", "noMultipleSpacesInRegularExpressionLiterals": "error", "noUselessCatch": "error", "noUselessConstructor": "error", "noUselessLabel": "error", "noUselessRename": "error", "noUselessSwitchCase": "error", "noWith": "error" }, "correctness": { "noConstAssign": "error", "noConstantCondition": "error", "noEmptyPattern": "error", "noGlobalObjectCalls": "error", "noInnerDeclarations": "error", "noInvalidConstructorSuper": "error", "noNewSymbol": "error", "noUnreachable": "error", "noUnreachableSuper": "error", "noUnsafeFinally": "error", "noUnsafeOptionalChaining": "error", "noUnusedVariables": "error", "useValidForDirection": "error" }, "style": { "noNonNullAssertion": "warn", "useConst": "error", "useTemplate": "warn" }, "suspicious": { "noArrayIndexKey": "warn", "noAsyncPromiseExecutor": "error", "noCatchAssign": "error", "noClassAssign": "error", "noCompareNegZero": "error", "noDebugger": "error", "noDoubleEquals": "error", "noDuplicateCase": "error", "noDuplicateClassMembers": "error", "noDuplicateObjectKeys": "error", "noEmptyBlockStatements": "warn", "noExplicitAny": "warn", "noFallthroughSwitchClause": "error", "noFunctionAssign": "error", "noGlobalAssign": "error", "noImportAssign": "error", "noRedeclare": "error", "noShadowRestrictedNames": "error", "noUnsafeNegation": "error" } } }, "formatter": { "enabled": true, "formatWithErrors": false, "indentStyle": "space", "indentWidth": 2, "lineWidth": 100, "lineEnding": "lf" }, "javascript": { "formatter": { "quoteStyle": "single", "trailingCommas": "es5", "semicolons": "always", "arrowParentheses": "asNeeded" } }, "files": { "ignore": ["node_modules", "dist", "drizzle", "*.config.ts"] } }
5.2 Git Hooks (Simple Husky Alternative)
Create .husky/pre-commit:
bashmkdir -p .husky cat > .husky/pre-commit << 'EOF' #!/bin/sh bun run typecheck && bun run lint EOF chmod +x .husky/pre-commit
Add to package.json:
json{ "scripts": { "prepare": "husky install || true" } }
Install husky:
bashbun add -D husky bun run prepare
5.3 VS Code Configuration
.vscode/settings.json:
json{ "editor.formatOnSave": true, "editor.defaultFormatter": "biomejs.biome", "editor.codeActionsOnSave": { "quickfix.biome": "explicit", "source.organizeImports.biome": "explicit" }, "[typescript]": { "editor.defaultFormatter": "biomejs.biome" }, "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true }
.vscode/extensions.json:
json{ "recommendations": [ "biomejs.biome", "oven.bun-vscode" ] }
5.4 Testing Framework
Bun has a built-in test runner. Create tests/setup.ts:
typescriptimport { beforeAll, afterAll } from 'bun:test'; beforeAll(() => { // Global test setup process.env.NODE_ENV = 'test'; }); afterAll(() => { // Global test teardown });
Add to package.json:
json{ "scripts": { "test": "bun test --preload ./tests/setup.ts", "test:watch": "bun test --watch --preload ./tests/setup.ts" } }
6. Build & Run Scripts
6.1 Development
bashbun run dev
Runs the CLI in watch mode. Changes auto-reload.
6.2 Build
bashbun run build
Creates optimized production bundle in dist/.
6.3 Start
bashbun run start
Runs the built CLI from dist/.
6.4 Type Checking
bashbun run typecheck
Runs TypeScript compiler in check-only mode.
6.5 Linting and Formatting
bashbun run lint # Check for issues bun run lint:fix # Auto-fix issues bun run format # Format code
6.6 Database Management
bashbun run db:generate # Generate migrations from schema bun run db:migrate # Apply migrations bun run db:studio # Open Drizzle Studio (GUI)
6.7 Testing
bashbun run test # Run all tests bun run test:watch # Watch mode
7. CI Setup
7.1 GitHub Actions Workflow (.github/workflows/ci.yml)
yamlname: CI on: push: branches: [main, master] pull_request: branches: [main, master] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install dependencies run: bun install --frozen-lockfile - name: Type check run: bun run typecheck - name: Lint run: bun run lint - name: Test run: bun run test - name: Build run: bun run build
7.2 Release Workflow (.github/workflows/release.yml)
yamlname: Release on: push: tags: - 'v*' jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install dependencies run: bun install --frozen-lockfile - name: Build run: bun run build - name: Create Release uses: softprops/action-gh-release@v2 with: files: | dist/**/* env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8. Design Principles Enforcement
Principle 1: Start Simple, Earn Complexity
Implementation:
- Sequential pipeline in
src/orchestrator/pipeline.ts(no parallelization in MVP) - Single-agent execution per phase
- Linear state machine:
plan → implement → review → test → deploy
Code Pattern:
typescript// src/orchestrator/pipeline.ts export async function executePipeline(task: string): Promise<void> { const plan = await planner.execute(task); const code = await implementer.execute(plan); const review = await reviewer.execute(code); const tests = await tester.execute(review); await deployer.execute(tests); }
Principle 2: Learn from Everything
Implementation:
- Event bus in
src/core/bus.tscaptures all actions - Every agent emits events via
ctx.bus.emit() - Memory store in
src/memory/store.tspersists learnings - Post-execution reflection in agents
Code Pattern:
typescript// Every agent action ctx.bus.emit({ type: `${this.type}.action`, source: this.id, payload: { action, result }, traceId: ctx.traceId, });
Principle 3: Safe by Default
Implementation:
- Circuit breakers in
src/safety/breakers.tscheck on every iteration - Human gates in
src/safety/gates.tsrequire approval for high-risk actions - Cost budget tracking in
src/safety/budget.ts - Error taxonomy in
src/core/errors.tsclassifies all failures
Code Pattern:
typescript// Check circuit breakers before every action const breakerResult = ctx.safety.check({ iteration, cost, elapsed }); if (breakerResult.shouldBreak) { throw new CircuitBreakerError(breakerResult); }
Principle 4: Observable
Implementation:
- Every event logged to SQLite
eventstable traceIdgroups all events in one pipeline run- Cost tracking (
tokensUsed,costUsd) on every LLM call - Replay function:
bus.replay(traceId)reconstructs execution
Code Pattern:
typescript// Every LLM call logs cost const response = await ctx.llm.chat({ ... }); ctx.bus.emit({ type: 'llm.call', payload: { tokens: response.usage.totalTokens }, cost: { tokens: response.usage.totalTokens, usd: response.cost }, });
Principle 5: Tool-Agnostic
Implementation:
- LLM provider abstraction in
src/tools/llm.ts - Git operations abstracted in
src/tools/git.ts - GitHub API wrapped in
src/tools/github.ts - Tool registry in
src/tools/registry.tsallows swapping implementations
Code Pattern:
typescript// src/tools/llm.ts export interface LLMProvider { chat(request: ChatRequest): Promise<ChatResponse>; } export class AnthropicProvider implements LLMProvider { ... } export class OpenAIProvider implements LLMProvider { ... }
9. Entry Points
9.1 CLI Entry Point
File: src/cli/index.ts
typescript#!/usr/bin/env bun import { Command } from 'commander'; import { runCommand } from './commands/run'; import { reviewCommand } from './commands/review'; import { testCommand } from './commands/test'; import { statusCommand } from './commands/status'; import { historyCommand } from './commands/history'; const program = new Command(); program .name('forge') .description('AI-driven SDLC orchestrator') .version('0.1.0'); program .command('run') .description('Execute a full SDLC pipeline') .argument('<task>', 'Task description') .option('-c, --config <path>', 'Config file path', './forge.config.ts') .action(runCommand); program .command('review') .description('Review a PR or codebase') .argument('<target>', 'PR number or file path') .action(reviewCommand); program .command('test') .description('Run tests with AI analysis') .option('-s, --select', 'Use AI test selection') .action(testCommand); program .command('status') .description('Show current pipeline status') .action(statusCommand); program .command('history') .description('Show execution history') .option('-l, --limit <n>', 'Number of runs to show', '10') .action(historyCommand); program.parse();
Make it executable:
bashchmod +x src/cli/index.ts
9.2 Library Entry Point
File: src/index.ts
typescript// Core types export * from './core/types'; export * from './core/bus'; export * from './core/config'; export * from './core/errors'; // Safety export * from './safety/breakers'; export * from './safety/gates'; export * from './safety/budget'; // Memory export * from './memory/store'; export * from './memory/episodes'; export * from './memory/patterns'; export * from './memory/procedures'; // Tools export * from './tools/registry'; export * from './tools/llm'; export * from './tools/git'; // Agents export * from './agents/base'; export * from './agents/planner'; export * from './agents/implementer'; export * from './agents/reviewer'; export * from './agents/tester'; // Orchestrator export * from './orchestrator/pipeline'; export * from './orchestrator/context';
9.3 Usage Examples
As a CLI tool:
bashforge run "add user authentication" forge review PR#42 forge test --select forge status
As a library:
typescriptimport { executePipeline, Config } from 'forge'; const config: Config = { llm: { provider: 'anthropic', model: 'claude-sonnet-4' }, safety: { costPerRun: 50 }, }; await executePipeline('add user authentication', config);
10. Naming Conventions
10.1 File Naming
| Type | Convention | Example |
|---|---|---|
| Core modules | kebab-case.ts | event-bus.ts |
| Agent implementations | singular-noun.ts | planner.ts, reviewer.ts |
| Interfaces/types | Colocated in implementation | types.ts for shared types |
| Tests | *.test.ts | planner.test.ts |
| Config files | *.config.ts | forge.config.ts, drizzle.config.ts |
10.2 Variable Naming
typescript// Constants: SCREAMING_SNAKE_CASE const MAX_ITERATIONS = 10; const DEFAULT_COST_BUDGET = 50; // Variables: camelCase const userName = 'Alice'; const iterationCount = 0; // Private class members: _camelCase class Agent { private _workingMemory: Memory[]; } // Boolean variables: is/has/can prefix const isComplete = false; const hasError = true; const canRetry = result.retryable;
10.3 Type Naming
typescript// Interfaces: PascalCase, descriptive interface AgentContext { ... } interface PhaseInput { ... } interface LearningEvent { ... } // Type aliases: PascalCase type AgentType = 'planner' | 'implementer' | 'reviewer' | 'tester' | 'deployer'; type PhaseName = 'plan' | 'implement' | 'review' | 'test' | 'deploy'; // Enums: PascalCase for type, SCREAMING_SNAKE_CASE for values enum ErrorSeverity { INFO = 'INFO', WARNING = 'WARNING', ERROR = 'ERROR', CRITICAL = 'CRITICAL', } // Avoid: I-prefix for interfaces (IAgent ❌, Agent ✅)
10.4 Function Naming
typescript// Functions: camelCase, verb-first function executeAgent(agent: Agent): Promise<Result> { ... } function parseRequirements(input: string): Requirements { ... } // Async functions: async prefix optional (rely on return type) async function fetchMemories(context: string): Promise<Memory[]> { ... } // Boolean return: is/has/can prefix function isRetryable(error: Error): boolean { ... } function hasCircuitBreakerTripped(ctx: Context): boolean { ... } // Event handlers: on-prefix function onAgentComplete(result: PhaseOutput): void { ... }
10.5 Class Naming
typescript// Classes: PascalCase, noun-first class EventBus { ... } class BaseAgent { ... } class CircuitBreakerError extends Error { ... } // Agent classes: Agent suffix class PlannerAgent { ... } class ReviewerAgent { ... } // Avoid: suffixes like Manager, Helper, Util (be specific) // ❌ MemoryManager // ✅ MemoryStore
10.6 Module Structure
typescript// Each module exports a primary interface/class and supporting types // src/core/bus.ts export class EventBus { ... } export interface ForgeEvent { ... } export interface EventHandler { ... } // src/memory/store.ts export class MemoryStore { ... } export interface Memory { ... } export interface MemoryQuery { ... }
11. Configuration Files
11.1 Drizzle Configuration (drizzle.config.ts)
typescriptimport type { Config } from 'drizzle-kit'; export default { schema: './src/memory/schema.ts', out: './drizzle', dialect: 'sqlite', dbCredentials: { url: process.env.DB_PATH || '.forge/memory.db', }, } satisfies Config;
11.2 Environment Variables (.env.example)
bash# LLM Provider ANTHROPIC_API_KEY=sk-ant-... # Database DB_PATH=.forge/memory.db # GitHub Integration (optional) GITHUB_TOKEN=ghp_... # Safety Limits MAX_COST_PER_RUN=50 MAX_ITERATIONS=10 # Logging LOG_LEVEL=info
11.3 Project Configuration (forge.config.ts)
typescriptimport { defineConfig } from './src/core/config'; export default defineConfig({ name: 'my-app', language: 'typescript', llm: { provider: 'anthropic', model: 'claude-sonnet-4-5-20250929', fastModel: 'claude-haiku-4-5-20251001', }, tools: { testCommand: 'bun test', lintCommand: 'bun run lint', buildCommand: 'bun run build', typecheckCommand: 'bun run typecheck', }, safety: { costPerRun: 50, costPerDay: 200, automationLevel: 1, }, github: { owner: 'myorg', repo: 'my-app', reviewOnPR: true, postComments: true, }, memory: { dbPath: '.forge/memory.db', consolidateInterval: '1d', maxMemories: 10_000, }, });
12. Initial File Stubs
To complete the project skeleton, create stub files for each module.
12.1 Core Stubs
src/core/types.ts:
typescriptexport interface Agent { id: string; type: AgentType; execute(input: PhaseInput, ctx: AgentContext): Promise<PhaseOutput>; } export interface ForgeEvent { id: string; traceId: string; timestamp: Date; source: string; type: string; payload: unknown; cost?: { tokens: number; usd: number }; } export interface Tool<TInput = unknown, TOutput = unknown> { name: string; description: string; schema: { input: ZodSchema<TInput>; output: ZodSchema<TOutput> }; execute(input: TInput, ctx: ToolContext): Promise<TOutput>; } export interface Phase { name: PhaseName; agent: Agent; guards: Guard[]; gates: HumanGate[]; breakers: CircuitBreaker[]; next: PhaseName | null; } export interface Memory { id: string; type: 'episodic' | 'semantic' | 'procedural'; content: string; embedding?: Float32Array; confidence: number; context: string; createdAt: Date; lastAccessed: Date; accessCount: number; } export interface Checkpoint { id: string; traceId: string; phase: PhaseName; state: Record<string, unknown>; timestamp: Date; } export type AgentType = 'planner' | 'implementer' | 'reviewer' | 'tester' | 'deployer'; export type PhaseName = 'plan' | 'implement' | 'review' | 'test' | 'deploy'; export type PhaseInput = unknown; export type PhaseOutput = unknown; export type AgentContext = unknown; export type ToolContext = unknown; export type Guard = unknown; export type HumanGate = unknown; export type CircuitBreaker = unknown; export type ZodSchema<T> = unknown;
src/core/bus.ts:
typescriptimport { ForgeEvent } from './types'; export class EventBus { async emit(event: Omit<ForgeEvent, 'id' | 'timestamp'>): Promise<void> { // TODO: Implement event emission } on(type: string, handler: (event: ForgeEvent) => void): () => void { // TODO: Implement event subscription return () => {}; } async replay(traceId: string): Promise<ForgeEvent[]> { // TODO: Implement event replay return []; } }
src/core/config.ts:
typescriptexport function defineConfig(config: Config): Config { return config; } export interface Config { name: string; language: string; llm: LLMConfig; tools: ToolsConfig; safety: SafetyConfig; github?: GitHubConfig; memory: MemoryConfig; } export interface LLMConfig { provider: 'anthropic' | 'openai' | 'ollama'; model: string; fastModel?: string; } export interface ToolsConfig { testCommand: string; lintCommand: string; buildCommand: string; typecheckCommand: string; } export interface SafetyConfig { costPerRun: number; costPerDay: number; automationLevel: 0 | 1 | 2 | 3 | 4; } export interface GitHubConfig { owner: string; repo: string; reviewOnPR: boolean; postComments: boolean; } export interface MemoryConfig { dbPath: string; consolidateInterval: string; maxMemories: number; }
src/core/errors.ts:
typescriptexport class ForgeError extends Error { constructor( message: string, public severity: ErrorSeverity, public source: string, public recoverable: boolean ) { super(message); this.name = 'ForgeError'; } } export class CircuitBreakerError extends ForgeError { constructor(reason: string) { super(`Circuit breaker tripped: ${reason}`, 'CRITICAL', 'safety', false); } } export type ErrorSeverity = 'INFO' | 'WARNING' | 'ERROR' | 'CRITICAL';
12.2 Memory Schema (src/memory/schema.ts)
typescriptimport { sqliteTable, text, integer, real, blob } from 'drizzle-orm/sqlite-core'; export const events = sqliteTable('events', { id: text('id').primaryKey(), traceId: text('trace_id').notNull(), timestamp: integer('timestamp', { mode: 'timestamp_ms' }).notNull(), source: text('source').notNull(), type: text('type').notNull(), phase: text('phase'), payload: text('payload', { mode: 'json' }), tokensUsed: integer('tokens_used'), costUsd: real('cost_usd'), durationMs: integer('duration_ms'), }); export const memories = sqliteTable('memories', { id: text('id').primaryKey(), type: text('type').notNull(), content: text('content').notNull(), context: text('context').notNull(), embedding: blob('embedding'), confidence: real('confidence').notNull(), source: text('source'), tags: text('tags', { mode: 'json' }), createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(), lastAccessed: integer('last_accessed', { mode: 'timestamp_ms' }).notNull(), accessCount: integer('access_count').notNull().default(0), }); export const patterns = sqliteTable('patterns', { id: text('id').primaryKey(), type: text('type').notNull(), trigger: text('trigger').notNull(), pattern: text('pattern').notNull(), resolution: text('resolution'), frequency: integer('frequency').notNull().default(1), successRate: real('success_rate'), confidence: real('confidence').notNull(), lastSeen: integer('last_seen', { mode: 'timestamp_ms' }).notNull(), }); export const checkpoints = sqliteTable('checkpoints', { id: text('id').primaryKey(), traceId: text('trace_id').notNull(), phase: text('phase').notNull(), state: text('state', { mode: 'json' }).notNull(), timestamp: integer('timestamp', { mode: 'timestamp_ms' }).notNull(), }); export const runs = sqliteTable('runs', { id: text('id').primaryKey(), task: text('task').notNull(), status: text('status').notNull(), currentPhase: text('current_phase'), config: text('config', { mode: 'json' }), startedAt: integer('started_at', { mode: 'timestamp_ms' }).notNull(), completedAt: integer('completed_at', { mode: 'timestamp_ms' }), totalCostUsd: real('total_cost_usd').default(0), totalTokens: integer('total_tokens').default(0), error: text('error'), }); export const findings = sqliteTable('findings', { id: text('id').primaryKey(), runId: text('run_id').notNull(), phase: text('phase').notNull(), severity: text('severity').notNull(), category: text('category').notNull(), message: text('message').notNull(), file: text('file'), line: integer('line'), confidence: real('confidence'), fixable: integer('fixable', { mode: 'boolean' }), fix: text('fix'), dismissed: integer('dismissed', { mode: 'boolean' }).default(false), dismissedBy: text('dismissed_by'), });
12.3 Database Migration Script (src/scripts/migrate.ts)
typescript#!/usr/bin/env bun import { migrate } from 'drizzle-orm/better-sqlite3/migrator'; import { drizzle } from 'drizzle-orm/better-sqlite3'; import Database from 'better-sqlite3'; const dbPath = process.env.DB_PATH || '.forge/memory.db'; const sqlite = new Database(dbPath); const db = drizzle(sqlite); console.log('Running migrations...'); migrate(db, { migrationsFolder: './drizzle' }); console.log('Migrations complete!'); sqlite.close();
13. Validation Checklist
Before proceeding to Week 1 implementation, verify:
- Bun installed and version >= 1.0.0
- Project initialized with
bun init - All dependencies installed (
bun install) - Directory structure matches Module Map
-
tsconfig.jsonhas strict mode enabled -
biome.jsonconfigured - Git hooks set up (
.husky/pre-commit) - CI workflow created (
.github/workflows/ci.yml) - VS Code settings configured
- All stub files created
- Database schema defined (
src/memory/schema.ts) - Migration script executable (
src/scripts/migrate.ts) - CLI entry point executable (
src/cli/index.ts) - Library entry point exports core types (
src/index.ts) - Configuration files created (
.env.example,forge.config.ts,drizzle.config.ts) - Type checking passes (
bun run typecheck) - Linting passes (
bun run lint) - All scripts in
package.jsonare valid
14. Next Steps
After completing this plan:
-
Generate initial database migration:
bashbun run db:generate -
Run migrations to create tables:
bashbun run db:migrate -
Verify type checking:
bashbun run typecheck -
Commit the skeleton:
bashgit add . git commit -m "feat: complete project foundation" -
Proceed to Week 1 implementation (core skeleton + event bus).
Appendix A: Common Commands Reference
bash# Project setup bun install # Install dependencies bun run prepare # Set up git hooks # Development bun run dev # Start CLI in watch mode bun run typecheck # Type check without building bun run lint # Check code quality bun run lint:fix # Auto-fix issues bun run format # Format code # Testing bun test # Run all tests bun test --watch # Watch mode bun test src/core/bus.test.ts # Run specific test # Database bun run db:generate # Generate migration bun run db:migrate # Apply migrations bun run db:studio # Open GUI # Build bun run build # Production build bun run start # Run built CLI # CLI usage (after build) forge run "task description" forge review PR#42 forge test --select forge status forge history --limit 5
Appendix B: Troubleshooting
Issue: bun: command not found
Solution:
bashcurl -fsSL https://bun.sh/install | bash source ~/.bashrc # or ~/.zshrc
Issue: Type errors with Bun types
Solution: Ensure @types/bun is installed and tsconfig.json includes "types": ["bun-types"].
Issue: Biome not formatting on save
Solution: Install the Biome VS Code extension and verify .vscode/settings.json is configured.
Issue: Git hooks not running
Solution:
bashchmod +x .husky/pre-commit bun run prepare
Issue: Database migrations fail
Solution: Check drizzle.config.ts points to the correct schema file and DB_PATH is set.
End of Plan