forge-dev-framework 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.claude/commands/forge/README.md +156 -189
  2. package/.claude/commands/forge/add-phase.md +4 -3
  3. package/.claude/commands/forge/complete-milestone.md +1 -1
  4. package/.claude/commands/forge/convert.md +31 -0
  5. package/.claude/commands/forge/debug.md +12 -154
  6. package/.claude/commands/forge/discuss.md +60 -107
  7. package/.claude/commands/forge/execute.md +67 -142
  8. package/.claude/commands/forge/generate.md +8 -107
  9. package/.claude/commands/forge/help.md +9 -114
  10. package/.claude/commands/forge/init.md +10 -74
  11. package/.claude/commands/forge/insert-phase.md +4 -3
  12. package/.claude/commands/forge/new-milestone.md +1 -1
  13. package/.claude/commands/forge/new-project.md +12 -91
  14. package/.claude/commands/forge/pause-work.md +2 -2
  15. package/.claude/commands/forge/plan.md +114 -129
  16. package/.claude/commands/forge/quick.md +17 -106
  17. package/.claude/commands/forge/remove-phase.md +3 -2
  18. package/.claude/commands/forge/resume.md +22 -0
  19. package/.claude/commands/forge/team-add.md +24 -0
  20. package/.claude/commands/forge/team-create.md +22 -0
  21. package/.claude/commands/forge/team-remove.md +24 -0
  22. package/.claude/commands/forge/team-start.md +22 -0
  23. package/.claude/commands/forge/team-view.md +18 -0
  24. package/.claude/commands/forge/verify.md +68 -147
  25. package/.claude/hooks/forge-context-cleanup.cjs +79 -0
  26. package/.claude/hooks/forge-event-guard.cjs +36 -0
  27. package/.claude/hooks/forge-size-guard.cjs +55 -0
  28. package/.claude/rules/api-patterns.md +13 -98
  29. package/.claude/rules/context-efficiency.md +10 -0
  30. package/.claude/rules/security-baseline.md +18 -204
  31. package/.claude/rules/testing-standards.md +16 -177
  32. package/.claude/rules/ui-conventions.md +17 -142
  33. package/bin/forge.js +5 -3
  34. package/dist/bin/forge.js +5 -3
  35. package/dist/cli/index.d.ts.map +1 -1
  36. package/dist/cli/index.js +15 -1
  37. package/dist/cli/index.js.map +1 -1
  38. package/dist/commands/convert.d.ts +6 -0
  39. package/dist/commands/convert.d.ts.map +1 -0
  40. package/dist/commands/convert.js +132 -0
  41. package/dist/commands/convert.js.map +1 -0
  42. package/dist/commands/generate.d.ts.map +1 -1
  43. package/dist/commands/generate.js +3 -2
  44. package/dist/commands/generate.js.map +1 -1
  45. package/dist/commands/index.d.ts +4 -4
  46. package/dist/commands/index.d.ts.map +1 -1
  47. package/dist/commands/index.js +4 -4
  48. package/dist/commands/index.js.map +1 -1
  49. package/dist/generators/gsd-converter.d.ts +100 -0
  50. package/dist/generators/gsd-converter.d.ts.map +1 -0
  51. package/dist/generators/gsd-converter.js +335 -0
  52. package/dist/generators/gsd-converter.js.map +1 -0
  53. package/dist/templates/.claude/rules/api-patterns.md.template +212 -0
  54. package/dist/templates/.claude/rules/security-baseline.md.template +322 -0
  55. package/dist/templates/.claude/rules/testing-standards.md.template +280 -0
  56. package/dist/templates/.claude/rules/ui-conventions.md.template +264 -0
  57. package/dist/templates/.planning/forge.config.json.template +75 -0
  58. package/dist/templates/CLAUDE.md.template +161 -0
  59. package/dist/templates/PLAN.md.template +177 -0
  60. package/dist/templates/PROJECT.md.template +156 -0
  61. package/dist/templates/REQUIREMENTS.md.template +221 -0
  62. package/dist/templates/ROADMAP.md.template +130 -0
  63. package/dist/types/index.d.ts +2 -2
  64. package/dist/types/index.d.ts.map +1 -1
  65. package/dist/types/index.js +2 -2
  66. package/dist/types/index.js.map +1 -1
  67. package/dist/utils/index.d.ts +5 -5
  68. package/dist/utils/index.d.ts.map +1 -1
  69. package/dist/utils/index.js +5 -5
  70. package/dist/utils/index.js.map +1 -1
  71. package/dist/utils/template-client.d.ts.map +1 -1
  72. package/dist/utils/template-client.js +3 -2
  73. package/dist/utils/template-client.js.map +1 -1
  74. package/package.json +6 -4
  75. package/.claude/commands/forge/resume-work.md +0 -122
  76. package/dist/git/__tests__/worktree.test.d.ts +0 -5
  77. package/dist/git/__tests__/worktree.test.d.ts.map +0 -1
  78. package/dist/git/__tests__/worktree.test.js +0 -121
  79. package/dist/git/__tests__/worktree.test.js.map +0 -1
  80. package/dist/git/codeowners.d.ts +0 -101
  81. package/dist/git/codeowners.d.ts.map +0 -1
  82. package/dist/git/codeowners.js +0 -216
  83. package/dist/git/codeowners.js.map +0 -1
  84. package/dist/git/commit.d.ts +0 -135
  85. package/dist/git/commit.d.ts.map +0 -1
  86. package/dist/git/commit.js +0 -223
  87. package/dist/git/commit.js.map +0 -1
  88. package/dist/git/hooks/commit-msg.d.ts +0 -8
  89. package/dist/git/hooks/commit-msg.d.ts.map +0 -1
  90. package/dist/git/hooks/commit-msg.js +0 -34
  91. package/dist/git/hooks/commit-msg.js.map +0 -1
  92. package/dist/git/hooks/pre-commit.d.ts +0 -8
  93. package/dist/git/hooks/pre-commit.d.ts.map +0 -1
  94. package/dist/git/hooks/pre-commit.js +0 -34
  95. package/dist/git/hooks/pre-commit.js.map +0 -1
  96. package/dist/git/pre-commit-hooks.d.ts +0 -117
  97. package/dist/git/pre-commit-hooks.d.ts.map +0 -1
  98. package/dist/git/pre-commit-hooks.js +0 -270
  99. package/dist/git/pre-commit-hooks.js.map +0 -1
  100. package/dist/git/wipe-protocol.d.ts +0 -281
  101. package/dist/git/wipe-protocol.d.ts.map +0 -1
  102. package/dist/git/wipe-protocol.js +0 -237
  103. package/dist/git/wipe-protocol.js.map +0 -1
  104. package/dist/git/worktree.d.ts +0 -69
  105. package/dist/git/worktree.d.ts.map +0 -1
  106. package/dist/git/worktree.js +0 -202
  107. package/dist/git/worktree.js.map +0 -1
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: forge:resume
3
+ description: Resume work from previous session with full context restoration
4
+ argument-hint: ""
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Bash
9
+ ---
10
+
11
+ Resume work by loading `.continue-here.md` handoff file.
12
+
13
+ **Read:** .continue-here.md, state/STATE.json
14
+
15
+ **Steps:**
16
+
17
+ 1. Check for `.continue-here.md`. If missing, check STATE.json for last phase.
18
+ 2. Parse and display: phase, status, position, completed work, remaining work, decisions, blockers
19
+ 3. Ask "Ready to continue?"
20
+ 4. Submit WORK_RESUMED event to state/events/
21
+ 5. Route to next action: `/forge:execute`, manual work, or `/forge:discuss`
22
+ 6. After completing work, remove .continue-here.md and submit WORK_COMPLETED event
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: forge:team-add
3
+ description: Add a new member to the FORGE agent team.
4
+ argument-hint: <name> <role> <agent-type>
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Edit
9
+ - Bash
10
+ - TeamCreate
11
+ - Task
12
+ ---
13
+
14
+ Add a new specialist to FORGE team by updating AgentTeam.md and recreating team.
15
+
16
+ **Read:** .planning/AgentTeam.md, ~/.claude/teams/forge/config.json
17
+
18
+ **Steps:**
19
+
20
+ 1. Validate AgentTeam.md exists
21
+ 2. Prompt for details if not in args: name (kebab-case), role, agent type, model, owned paths
22
+ 3. Add member section to AgentTeam.md, increment version
23
+ 4. Confirm with user, shutdown old team via SendMessage, recreate with TeamCreate, spawn all teammates
24
+ 5. Verify with `/forge:team-view`
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: forge:team-create
3
+ description: Create a FORGE agent team from AgentTeam.md specification.
4
+ argument-hint: [--team-name <name>]
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Bash
9
+ - TeamCreate
10
+ - Task
11
+ ---
12
+
13
+ Create FORGE agent team from `.planning/AgentTeam.md`.
14
+
15
+ **Read:** .planning/AgentTeam.md (or .planning/AgentTeam.template.md as reference)
16
+
17
+ **Steps:**
18
+
19
+ 1. If AgentTeam.md missing, spawn Explore subagent to analyze codebase and generate it
20
+ 2. Show team config to user, confirm creation
21
+ 3. Create team with TeamCreate, spawn all specialist teammates via Task tool
22
+ 4. Verify at `~/.claude/teams/forge/config.json`
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: forge:team-remove
3
+ description: Remove a member from the FORGE agent team.
4
+ argument-hint: <member-name>
5
+ allowed-tools:
6
+ - Read
7
+ - Write
8
+ - Edit
9
+ - Bash
10
+ - TeamCreate
11
+ - Task
12
+ - SendMessage
13
+ ---
14
+
15
+ Remove specialist $ARGUMENTS from FORGE team by updating AgentTeam.md and recreating team.
16
+
17
+ **Read:** .planning/AgentTeam.md, ~/.claude/teams/forge/config.json
18
+
19
+ **Steps:**
20
+
21
+ 1. Show current members, confirm which to remove
22
+ 2. Remove member section from AgentTeam.md, renumber remaining, increment version
23
+ 3. Shutdown old team, recreate with TeamCreate, spawn remaining teammates
24
+ 4. Verify with `/forge:team-view`
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: forge:team-start
3
+ description: Start the FORGE agent team by spawning all teammates.
4
+ argument-hint: [--team-name <name>]
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - TeamCreate
9
+ - Task
10
+ ---
11
+
12
+ Spawn all specialist teammates defined in AgentTeam.md.
13
+
14
+ **Read:** .planning/AgentTeam.md, ~/.claude/teams/forge/config.json
15
+
16
+ **Steps:**
17
+
18
+ 1. Validate AgentTeam.md exists
19
+ 2. Parse all specialist roles (name, agent type, model, prompt)
20
+ 3. Check existing team for inactive members
21
+ 4. Spawn team-lead first, then all specialists via Task tool
22
+ 5. Verify team is active, show member summary
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: forge:team-view
3
+ description: View FORGE agent team members and configuration.
4
+ argument-hint: [--team-name <name>]
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ ---
9
+
10
+ Display current FORGE team configuration.
11
+
12
+ **Read:** ~/.claude/teams/forge/config.json, .planning/AgentTeam.md
13
+
14
+ **Steps:**
15
+
16
+ 1. Read team config, extract: name, description, members
17
+ 2. Display formatted table: name, type, model, role, owned paths, active/idle status
18
+ 3. Compare with AgentTeam.md, flag differences
@@ -1,174 +1,95 @@
1
1
  ---
2
2
  name: forge:verify
3
- description: Verify a phase plan against requirements and success criteria. Use when user says "forge verify <phase>" or wants to validate a plan.
3
+ description: Verify all phase plans against requirements and generate gap closure plans.
4
4
  argument-hint: <phase-name>
5
5
  allowed-tools:
6
6
  - Read
7
+ - Write
7
8
  - Glob
8
9
  - Grep
9
10
  - Bash
11
+ - Task
10
12
  ---
11
13
 
12
- <objective>
13
- Verify that a phase plan achieves its goals and covers all requirements through goal-backward analysis.
14
+ Verify phase $ARGUMENTS plans cover all requirements via goal-backward analysis. If gaps are found, generate numbered gap closure plan files (same format as regular plans) that can be executed with `/forge:execute {phase} --gaps`.
14
15
 
15
- Purpose: Validate plan completeness before execution.
16
- Output: VERIFICATION.md with coverage analysis and gaps identified.
17
- </objective>
16
+ **Read:** All `.planning/phases/{phase}/*-PLAN.md` files, all `*-SUMMARY.md` files (if execution happened), REQUIREMENTS.md, ROADMAP.md, state/STATE.json
18
17
 
19
- <execution_context>
20
- **Load these files NOW:**
18
+ **Steps:**
21
19
 
22
- - @.planning/phases/<phase>/PLAN.md (Task breakdown)
23
- - @REQUIREMENTS.md (Project requirements)
24
- - @ROADMAP.md (Milestone context)
25
- - @CLAUDE.md (Success criteria patterns)
26
- </execution_context>
20
+ 1. **Discover all plan and summary files:**
21
+ - Glob `.planning/phases/{phase}/*-PLAN.md` parse each plan's frontmatter and tasks
22
+ - Glob `.planning/phases/{phase}/*-SUMMARY.md` check execution results
23
+ - Build complete picture: what was planned, what was executed, what succeeded
27
24
 
28
- <context>
29
- **Phase:** $ARGUMENTS
30
- **Verification Type:** Goal-backward analysis
31
- **Focus:** Requirements coverage, integration completeness, end-to-end flows
32
- </context>
25
+ 2. **Requirements coverage** — Map each requirement from REQUIREMENTS.md → plans/tasks that cover it. Mark each as:
26
+ - **Covered** — task exists and (if executed) summary confirms completion
27
+ - **Planned** task exists but not yet executed
28
+ - **Gap** no task addresses this requirement
33
29
 
34
- <process>
35
- **Execute verification workflow:**
30
+ 3. **Goal-backward analysis** — For each milestone goal from ROADMAP.md:
31
+ - Trace: goal → plans → tasks → acceptance criteria
32
+ - Flag missing links in the chain
36
33
 
37
- 1. **Load Plan & Requirements**
38
- - Read PLAN.md task list
39
- - Read REQUIREMENTS.md entries
40
- - Load milestone goals from ROADMAP.md
34
+ 4. **Integration completeness** Check cross-plan contracts defined, integration points covered, no conflicting file modifications across plans in the same wave.
41
35
 
42
- 2. **Requirements Coverage Analysis**
36
+ 5. **Dependency validation** — Verify plan dependency graph is acyclic, all depends_on references are valid plan numbers, wave assignments are correct.
43
37
 
44
- For each requirement in REQUIREMENTS.md:
45
- ```
46
- REQ-1: User authentication
47
- ├─ Covered by: auth-001, auth-002
48
- ├─ Task acceptance criteria maps to requirement? ✅
49
- └─ Verification method defined? ✅
50
-
51
- REQ-2: API rate limiting
52
- ├─ Covered by: None
53
- └─ ❌ GAP: No task for rate limiting
54
- ```
55
-
56
- 3. **Goal-Backward Verification**
57
-
58
- For each milestone goal:
59
- ```
60
- Goal: "Users can authenticate and authorize"
61
- └─ Can we trace from goal → tasks → acceptance?
62
- ├─ auth-001: Login endpoint ✅
63
- ├─ auth-002: Session management ✅
64
- ├─ auth-003: Permission checks ✅
65
- └─ Integration flow tested? ❌ Missing
66
- ```
38
+ 6. **Scope validation** Cross-reference with CONTEXT.md:
39
+ - Deferred ideas should NOT appear in any plan
40
+ - Locked decisions should be implemented as specified
41
+ - Claude's discretion areas should have reasonable choices
67
42
 
68
- 4. **Integration Completeness**
69
-
70
- Check cross-phase integration:
71
- ```
72
- Phase A (API) Phase B (Frontend)
73
- ├─ API contract defined? ✅ contracts/auth-api.yaml
74
- ├─ Frontend consumes API? ✅ ui-auth-001
75
- └─ Integration test exists? ❌ Gap
76
- ```
77
-
78
- 5. **Dependency Validation**
79
-
80
- Verify dependency graph:
81
- ```
82
- ✅ No circular dependencies
83
- ✅ All dependencies have tasks
84
- ✅ Critical path identified
85
- ⚠ Long dependency chain: api-001 → api-002 → api-003 → api-004
86
- ```
43
+ 7. **Write VERIFICATION.md** — `.planning/phases/{phase}/VERIFICATION.md` with:
44
+ ```markdown
45
+ # {Phase} Verification
46
+ **Verified:** [timestamp]
47
+ **Result:** {PASS | GAPS FOUND}
87
48
 
88
- 6. **Task Atomicity Check**
49
+ ## Requirements Coverage
50
+ | Requirement | Status | Covered By |
51
+ |-------------|--------|------------|
52
+ | REQ-001 | Covered | Plan 01, Task 1 |
53
+ | REQ-003 | GAP | — |
89
54
 
90
- Verify each task is atomic:
91
- ```
92
- ✅ auth-001: Single owner, single concept
93
- ❌ ui-002: Too broad (split into ui-002a, ui-002b)
94
- ```
55
+ ## Goal-Backward Analysis
56
+ [Results per goal]
95
57
 
96
- 7. **Generate VERIFICATION.md**
97
- ```markdown
98
- # <Phase> Verification
58
+ ## Integration Check
59
+ [Results]
99
60
 
100
- ## Requirements Coverage
101
- - REQ-1: ✅ Covered (auth-001, auth-002)
102
- - REQ-2: ❌ Gap - no rate limiting task
103
- ...
104
-
105
- ## Goals Verification
106
- - Goal 1: ✅ Achievable through tasks
107
- - Goal 2: ⚠ Gap - integration test missing
108
- ...
109
-
110
- ## Integration Checks
111
- - Phase A → Phase B: ✅ Contract defined
112
- - Frontend → API: ⚠ Integration test missing
113
- ...
114
-
115
- ## Task Atomicity
116
- - All tasks atomic? ✅
117
- - Task count within limit? ✅ (5/6)
118
-
119
- ## Gaps Identified
120
- 1. REQ-2: No rate limiting
121
- 2. Integration test for auth flow
122
- ...
123
-
124
- ## Recommendations
125
- - Add task api-005 for rate limiting
126
- - Add task int-001 for integration tests
127
- ...
128
- ```
61
+ ## Dependency Validation
62
+ [Results]
129
63
 
130
- 8. **Route Decision**
64
+ ## Scope Validation
65
+ [Results]
131
66
 
132
- If gaps found:
133
- ```
134
- - Ask user: "Add tasks for gaps?"
135
- - If yes: Update PLAN.md
136
- - If no: Document and proceed
67
+ ## Gaps Summary
68
+ {count} gaps identified requiring remediation.
137
69
  ```
138
70
 
139
- If verification passes:
140
- ```
141
- - Mark phase ready for execution
142
- - Offer `forge execute <phase>`
143
- ```
144
- </process>
145
-
146
- <deliverables>
147
- - .planning/phases/<phase>/VERIFICATION.md
148
- - Updated PLAN.md (if gaps addressed)
149
- - Requirements coverage matrix
150
- - Gap analysis report
151
- </deliverables>
152
-
153
- <verification_criteria>
154
- Plan passes verification when:
155
- - All requirements covered (or gaps documented)
156
- - All goals achievable through tasks
157
- - ✅ Integration points identified and tested
158
- - ✅ Dependency graph valid (no cycles)
159
- - All tasks atomic (single concept, single owner)
160
- - Task count 6
161
- - Acceptance criteria defined
162
- - ✅ Verification methods specified
163
- </verification_criteria>
164
-
165
- <next_steps>
166
- If verification passes:
167
- - Run `forge execute <phase>` to start execution
168
- - Or manually assign tasks to agents
169
-
170
- If gaps found:
171
- - Update PLAN.md with additional tasks
172
- - Re-run `forge verify <phase>`
173
- - Or document risks and proceed
174
- </next_steps>
71
+ 8. **If gaps found — generate gap closure plan files:**
72
+ - Determine next plan number (highest existing + 1)
73
+ - Create `.planning/phases/{phase}/{phase}-{next}-PLAN.md` for each gap cluster
74
+ - Each gap closure plan uses the same format as regular plans with frontmatter:
75
+ ```yaml
76
+ ---
77
+ phase: {phase-name}
78
+ plan: {next-number}
79
+ wave: 1
80
+ depends_on: []
81
+ files_modified: [...]
82
+ autonomous: true
83
+ gap_closure: true
84
+ ---
85
+ ```
86
+ - Gap closure plans contain 2-3 remediation tasks each (same XML task format)
87
+ - Number sequentially after existing plans
88
+ - Gap plan limit: max 3 gap closure plans. If more gaps exist, recommend breaking into sub-phases.
89
+
90
+ 9. **Routing:**
91
+ - If **no gaps:** "All requirements covered. Ready to execute." → Offer `/forge:execute {phase}`
92
+ - If **gaps found:** Show gap summary, list generated gap closure plans → Offer `/forge:execute {phase} --gaps` to run only gap closure plans
93
+ - If **already executed and gaps in results:** Generate plans targeting execution failures
94
+
95
+ **Pass criteria:** All requirements covered, goals achievable, deps valid, scope aligned with CONTEXT.md.
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ // FORGE Hook: Context Cleanup (SessionStart)
3
+ // Archives old events, cleans temp files, reports context health
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const cwd = process.cwd();
9
+ const eventsDir = path.join(cwd, 'state', 'events');
10
+ const archiveDir = path.join(cwd, 'state', 'events', 'archive');
11
+ const planningDir = path.join(cwd, '.planning');
12
+
13
+ // Only run if this looks like a FORGE project
14
+ if (!fs.existsSync(path.join(cwd, 'state', 'STATE.json'))) {
15
+ process.exit(0);
16
+ }
17
+
18
+ let archived = 0;
19
+ let cleaned = 0;
20
+
21
+ // 1. Archive events older than 7 days
22
+ if (fs.existsSync(eventsDir)) {
23
+ const cutoff = Date.now() - (7 * 24 * 60 * 60 * 1000);
24
+ const files = fs.readdirSync(eventsDir)
25
+ .filter(f => f.endsWith('.json') && f !== 'archive');
26
+
27
+ for (const file of files) {
28
+ const fp = path.join(eventsDir, file);
29
+ try {
30
+ const stat = fs.statSync(fp);
31
+ if (stat.mtime.getTime() < cutoff) {
32
+ if (!fs.existsSync(archiveDir)) {
33
+ fs.mkdirSync(archiveDir, { recursive: true });
34
+ }
35
+ fs.renameSync(fp, path.join(archiveDir, file));
36
+ archived++;
37
+ }
38
+ } catch (e) {}
39
+ }
40
+ }
41
+
42
+ // 2. Clean up orphaned .continue-here.md if older than 3 days
43
+ const continueFile = path.join(cwd, '.continue-here.md');
44
+ if (fs.existsSync(continueFile)) {
45
+ try {
46
+ const stat = fs.statSync(continueFile);
47
+ const age = Date.now() - stat.mtime.getTime();
48
+ if (age > 3 * 24 * 60 * 60 * 1000) {
49
+ fs.unlinkSync(continueFile);
50
+ cleaned++;
51
+ }
52
+ } catch (e) {}
53
+ }
54
+
55
+ // 3. Clean up empty quick task dirs
56
+ const quickDir = path.join(planningDir, 'quick');
57
+ if (fs.existsSync(quickDir)) {
58
+ const dirs = fs.readdirSync(quickDir);
59
+ for (const dir of dirs) {
60
+ const dp = path.join(quickDir, dir);
61
+ try {
62
+ if (fs.statSync(dp).isDirectory()) {
63
+ const contents = fs.readdirSync(dp);
64
+ if (contents.length === 0) {
65
+ fs.rmdirSync(dp);
66
+ cleaned++;
67
+ }
68
+ }
69
+ } catch (e) {}
70
+ }
71
+ }
72
+
73
+ // Report if anything happened
74
+ if (archived > 0 || cleaned > 0) {
75
+ const parts = [];
76
+ if (archived > 0) parts.push(`archived ${archived} old event(s)`);
77
+ if (cleaned > 0) parts.push(`cleaned ${cleaned} temp file(s)`);
78
+ process.stderr.write(`\x1b[34m→ FORGE cleanup: ${parts.join(', ')}\x1b[0m\n`);
79
+ }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ // FORGE Hook: Event Immutability Guard
3
+ // PreToolUse on Edit — prevents modifying existing event files in state/events/
4
+ // Events are append-only per FORGE architecture
5
+
6
+ const path = require('path');
7
+
8
+ let input = '';
9
+ process.stdin.setEncoding('utf8');
10
+ process.stdin.on('data', chunk => input += chunk);
11
+ process.stdin.on('end', () => {
12
+ try {
13
+ const data = JSON.parse(input);
14
+ const toolName = data.tool_name || '';
15
+ const filePath = data.tool_input?.file_path || '';
16
+
17
+ // Only guard Edit operations on event files
18
+ if (toolName === 'Edit' && filePath) {
19
+ const resolved = path.resolve(filePath);
20
+ const eventsDir = path.resolve(process.cwd(), 'state', 'events');
21
+
22
+ if (resolved.startsWith(eventsDir) && resolved.endsWith('.json')) {
23
+ process.stdout.write(JSON.stringify({
24
+ decision: 'block',
25
+ reason: 'FORGE: Events are append-only. Cannot edit files in state/events/. Write new events instead.'
26
+ }));
27
+ return;
28
+ }
29
+ }
30
+
31
+ process.stdout.write(JSON.stringify({ decision: 'approve' }));
32
+ } catch (e) {
33
+ // Don't block on parse errors
34
+ process.stdout.write(JSON.stringify({ decision: 'approve' }));
35
+ }
36
+ });
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ // FORGE Hook: File Size Guard
3
+ // PostToolUse on Write/Edit — warns when artifacts exceed token limits
4
+ // Limits: CLAUDE.md ~2000t, rules ~1000t, REQUIREMENTS.md ~4000t, PLAN.md ~6000t
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ // Approximate tokens as chars/4
10
+ const LIMITS = {
11
+ 'CLAUDE.md': { tokens: 2000, chars: 8000 },
12
+ 'REQUIREMENTS.md': { tokens: 4000, chars: 16000 },
13
+ 'PLAN.md': { tokens: 6000, chars: 24000 },
14
+ };
15
+ const RULES_LIMIT = { tokens: 1000, chars: 4000 };
16
+
17
+ let input = '';
18
+ process.stdin.setEncoding('utf8');
19
+ process.stdin.on('data', chunk => input += chunk);
20
+ process.stdin.on('end', () => {
21
+ try {
22
+ const data = JSON.parse(input);
23
+ const filePath = data.tool_input?.file_path || data.tool_result?.file_path || '';
24
+
25
+ if (!filePath) {
26
+ process.stdout.write(JSON.stringify({ decision: 'approve' }));
27
+ return;
28
+ }
29
+
30
+ const basename = path.basename(filePath);
31
+ const resolved = path.resolve(filePath);
32
+
33
+ // Check specific file limits
34
+ let limit = LIMITS[basename];
35
+
36
+ // Check rules directory
37
+ if (!limit && resolved.includes('.claude/rules/') && resolved.endsWith('.md')) {
38
+ limit = RULES_LIMIT;
39
+ }
40
+
41
+ if (limit && fs.existsSync(resolved)) {
42
+ const size = fs.statSync(resolved).size;
43
+ if (size > limit.chars) {
44
+ const approxTokens = Math.round(size / 4);
45
+ process.stderr.write(
46
+ `\x1b[33m⚠ FORGE: ${basename} is ~${approxTokens} tokens (limit: ~${limit.tokens}). Consider trimming.\x1b[0m\n`
47
+ );
48
+ }
49
+ }
50
+
51
+ process.stdout.write(JSON.stringify({ decision: 'approve' }));
52
+ } catch (e) {
53
+ process.stdout.write(JSON.stringify({ decision: 'approve' }));
54
+ }
55
+ });
@@ -1,98 +1,13 @@
1
- # FORGE API Design Patterns
2
-
3
- > **Scope:** Internal FORGE APIs and interfaces between components.
4
-
5
- ## File Naming
6
-
7
- - Use `kebab-case.ts` for files
8
- - Use `PascalCase` for types, interfaces, classes
9
- - Use `camelCase` for functions, variables
10
-
11
- ## Module Structure
12
-
13
- Each module exports:
14
- 1. Types/interfaces first
15
- 2. Functions/operations
16
- 3. Constants at the end
17
-
18
- ```typescript
19
- // src/state/event-types.ts
20
- export interface StateEvent { ... }
21
- export interface TaskStartedEvent extends StateEvent { ... }
22
-
23
- export function createEvent(type: EventType, payload: unknown): StateEvent { ... }
24
-
25
- export const EVENT_TYPES = ['TASK_STARTED', 'TASK_COMPLETED', ...] as const;
26
- ```
27
-
28
- ## Error Handling
29
-
30
- - Define custom error types extending `Error`
31
- - Include error codes for programmatic handling
32
- - Provide context in error messages
33
-
34
- ```typescript
35
- export class StateValidationError extends Error {
36
- constructor(
37
- public schema: string,
38
- public errors: z.ZodError,
39
- ) {
40
- super(`State validation failed for ${schema}: ${errors.message}`);
41
- this.name = 'StateValidationError';
42
- }
43
- }
44
- ```
45
-
46
- ## Async Operations
47
-
48
- - Use `async/await`, not Promises directly
49
- - Return typed promises: `Promise<T>`
50
- - Handle rejections with try/catch
51
-
52
- ```typescript
53
- export async function loadState(path: string): Promise<State> {
54
- try {
55
- const content = await fs.readFile(path, 'utf-8');
56
- return JSON.parse(content);
57
- } catch (error) {
58
- throw new StateLoadError(path, error);
59
- }
60
- }
61
- ```
62
-
63
- ## Input Validation
64
-
65
- - Use Zod schemas for all public APIs
66
- - Validate at module boundaries
67
- - Return typed results, never `any`
68
-
69
- ```typescript
70
- import { z } from 'zod';
71
-
72
- const EventSchema = z.object({
73
- eventId: z.string(),
74
- timestamp: z.string().datetime(),
75
- taskId: z.string(),
76
- actor: z.string(),
77
- type: z.enum(EVENT_TYPES),
78
- payload: z.unknown(),
79
- });
80
-
81
- export function parseEvent(data: unknown): StateEvent {
82
- return EventSchema.parse(data);
83
- }
84
- ```
85
-
86
- ## File I/O
87
-
88
- - Use absolute paths from project root
89
- - Check file existence before reading
90
- - Use atomic writes (write to temp, then rename)
91
-
92
- ```typescript
93
- export async function writeState(path: string, state: State): Promise<void> {
94
- const tmpPath = `${path}.tmp`;
95
- await fs.writeFile(tmpPath, JSON.stringify(state, null, 2));
96
- await fs.rename(tmpPath, path);
97
- }
98
- ```
1
+ ---
2
+ globs:
3
+ - "src/**/*.ts"
4
+ ---
5
+
6
+ # API Design Patterns
7
+
8
+ - **Files:** `kebab-case.ts` | **Types:** `PascalCase` | **Functions:** `camelCase`
9
+ - **Module exports order:** types/interfaces → functions → constants
10
+ - **Errors:** Custom error classes extending `Error` with error codes and context
11
+ - **Async:** Use `async/await` with typed `Promise<T>` returns, try/catch for rejections
12
+ - **Validation:** Zod schemas at all public API boundaries — never return `any`
13
+ - **File I/O:** Absolute paths from project root, check existence, atomic writes (write to temp → rename)
@@ -0,0 +1,10 @@
1
+ # Context Efficiency
2
+
3
+ - **Read selectively:** Use `offset`/`limit` for large files — don't read entire files when only a section matters
4
+ - **Minimize re-reads:** Cache key info in your working memory instead of re-reading the same file multiple times
5
+ - **Short outputs:** Prefer concise tool output — pipe through `head`/`tail` when full output isn't needed
6
+ - **Atomic tasks:** One task = one focused context. Don't accumulate unrelated work in a single session
7
+ - **Summarize early:** After reading large files, extract what you need and move on — don't keep raw content in context
8
+ - **Event hygiene:** Old events auto-archive after 7 days (SessionStart hook). Don't read archived events unless replaying state
9
+ - **File size limits:** CLAUDE.md ~2000t, rules ~1000t each, REQUIREMENTS.md ~4000t, PLAN.md ~6000t (enforced by PostToolUse hook)
10
+ - **Team messages:** Keep inter-agent messages concise — include only actionable information