Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit dedb07e

Browse files
committed
feat: implement intent-governed HookEngine and orchestration data model
- Add HookEngine middleware with pre/post-hooks for tool governance - Implement OrchestrationDataModel for .orchestration/ directory management - Create select_active_intent tool enforcing Reasoning Loop protocol - Integrate hooks into presentAssistantMessage for all destructive tools - Add UI-blocking authorization (HITL) for intent evolution - Implement scope enforcement and trace logging with content hashing
1 parent d878d57 commit dedb07e

13 files changed

Lines changed: 1116 additions & 8 deletions

File tree

.orchestration/AGENT.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Shared Knowledge Base
2+
3+
This file contains persistent knowledge shared across parallel sessions (Architect/Builder/Tester). Contains "Lessons Learned" and project-specific stylistic rules.
4+
5+
## Lessons Learned
6+
7+
<!--
8+
Example entry:
9+
### 2026-02-16: Authentication Refactoring
10+
- **Issue:** Initial JWT implementation caused circular dependency
11+
- **Solution:** Extracted token validation to separate utility module
12+
- **Impact:** Reduced coupling, improved testability
13+
- **Related Intent:** INT-001
14+
-->
15+
16+
## Project-Specific Rules
17+
18+
<!--
19+
Example entry:
20+
### Code Style
21+
- Always use async/await, never raw Promises
22+
- Prefer named exports over default exports
23+
- Use TypeScript strict mode
24+
-->
25+
26+
## Architectural Decisions
27+
28+
<!--
29+
Example entry:
30+
### 2026-02-16: Database Schema Change
31+
- **Decision:** Migrate from SQLite to PostgreSQL
32+
- **Rationale:** Need better concurrent access for parallel agents
33+
- **Impact:** All database queries must be updated
34+
- **Related Intent:** INT-002
35+
-->
36+

.orchestration/active_intents.yaml

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
active_intents:
2+
- id: INT-001
3+
name: INT-001 — Intent-Code Traceability (Spec)
4+
status: IN_PROGRESS
5+
owned_scope:
6+
- src/core/assistant-message/**
7+
- src/core/tools/**
8+
- src/core/hooks/**
9+
- src/core/orchestration/**
10+
- src/core/prompts/**
11+
- .orchestration/**
12+
constraints:
13+
- Must enforce **intent selection before any destructive tool**
14+
(`write_to_file`, `edit_file`, `apply_diff`, etc.).
15+
- "Must keep **privilege separation**: UI emits events; extension host
16+
executes privileged actions; hooks are middleware."
17+
- Must log **spatially independent** traces via content hashing.
18+
acceptance_criteria:
19+
- Agent cannot write code before calling `select_active_intent(intent_id)`.
20+
- "When a file is written, a JSONL entry is appended to
21+
`.orchestration/agent_trace.jsonl` that includes:"
22+
- intent id
23+
- file path
24+
- line range (best-effort)
25+
- "`sha256:` content hash of the modified block"
26+
- "`.orchestration/active_intents.yaml` exists and contains this intent."
27+
created_at: 2026-02-18T08:56:57.063Z
28+
updated_at: 2026-02-18T08:56:57.086Z
29+
spec_hash: sha256:7966563e9a7886587d3c421761708195d8a1ce21addd4632f560965411fd839b
30+
spec_file: specs/INT-001-intent-code-traceability.md
31+
- id: INT-002
32+
name: INT-002 — Hook System Implementation
33+
status: IN_PROGRESS
34+
owned_scope:
35+
- src/core/hooks/**
36+
- src/core/assistant-message/presentAssistantMessage.ts
37+
- src/core/tools/**
38+
- .orchestration/**
39+
constraints:
40+
- Must integrate with existing `presentAssistantMessage()` function
41+
without breaking current tool execution flow.
42+
- Pre-hooks must run **before** `tool.handle()` is called.
43+
- Post-hooks must run **after** `tool.execute()` completes but before
44+
result is returned.
45+
- Hook system must be non-blocking for non-destructive tools (read-only
46+
operations).
47+
- Must maintain backward compatibility with existing tools.
48+
acceptance_criteria:
49+
- "`HookEngine` class exists in `src/core/hooks/HookEngine.ts`."
50+
- Pre-hook validates intent selection for destructive tools
51+
(`write_to_file`, `edit_file`, `execute_command`, etc.).
52+
- Pre-hook enforces scope validation (file path must be within intent's
53+
`owned_scope`).
54+
- Post-hook logs trace entries to `.orchestration/agent_trace.jsonl` for
55+
mutating actions.
56+
- "`presentAssistantMessage()` integrates `HookEngine` with Pre-Hook and
57+
Post-Hook calls."
58+
- All existing tests pass after hook integration.
59+
created_at: 2026-02-18T08:56:57.094Z
60+
updated_at: 2026-02-18T08:56:57.094Z
61+
spec_hash: sha256:e10e923c607996643684be16016bc8305d7259b543eae623e92b5e49db8b902c
62+
spec_file: specs/INT-002-hook-system-implementation.md
63+
- id: INT-003
64+
name: INT-003 — Two-Stage Reasoning Loop
65+
status: IN_PROGRESS
66+
owned_scope:
67+
- src/core/hooks/HookEngine.ts
68+
- src/core/prompts/sections/tool-use-guidelines.ts
69+
- src/core/tools/SelectActiveIntentTool.ts
70+
- src/core/task/Task.ts
71+
constraints:
72+
- "**Stage 1 (Reasoning Intercept):** Agent MUST call
73+
`select_active_intent(intent_id)` before any destructive tool."
74+
- "**Stage 2 (Contextualized Action):** Agent receives intent context and
75+
must include it when making code changes."
76+
- System prompt must enforce this protocol in tool-use guidelines.
77+
- Intent context must be injected into the agent's context before code
78+
generation.
79+
acceptance_criteria:
80+
- System prompt includes instructions requiring `select_active_intent`
81+
before code changes.
82+
- "`SelectActiveIntentTool` returns XML `<intent_context>` block with
83+
scope, constraints, and acceptance criteria."
84+
- Pre-hook blocks destructive tools if no active intent is selected.
85+
- Agent receives intent context in subsequent tool calls.
86+
- Intent context is logged in `agent_trace.jsonl` entries.
87+
created_at: 2026-02-18T08:56:57.098Z
88+
updated_at: 2026-02-18T08:56:57.098Z
89+
spec_hash: sha256:a75817698c5b1479c68e43dd41b04752d3a6df7c4af71f3ab60fdedf705e4dda
90+
spec_file: specs/INT-003-reasoning-loop.md
91+
- id: INT-004
92+
name: INT-004 — Orchestration Directory Management
93+
status: IN_PROGRESS
94+
owned_scope:
95+
- src/core/orchestration/OrchestrationDataModel.ts
96+
- .orchestration/active_intents.yaml
97+
- .orchestration/agent_trace.jsonl
98+
- .orchestration/intent_map.md
99+
- .orchestration/AGENT.md
100+
constraints:
101+
- "`.orchestration/` directory must be machine-managed (not user-edited
102+
directly)."
103+
- "`active_intents.yaml` must be valid YAML and follow the schema defined
104+
in `document.md`."
105+
- "`agent_trace.jsonl` must be append-only (no modifications, only
106+
appends)."
107+
- All file operations must be atomic (write to temp file, then rename).
108+
- Directory and files must be initialized on first use.
109+
acceptance_criteria:
110+
- "`OrchestrationDataModel` class provides methods:"
111+
- "`initialize()`: Creates directory and initializes files if missing."
112+
- "`readActiveIntents()`: Parses and returns active intents."
113+
- "`appendAgentTrace()`: Appends trace entry to JSONL file."
114+
- "`updateIntentMap()`: Updates intent-to-file mapping."
115+
- "`appendAgentKnowledge()`: Appends to AGENT.md."
116+
- All methods handle errors gracefully and log failures.
117+
- Files are created with proper templates if missing.
118+
- YAML parsing validates schema and reports errors clearly.
119+
created_at: 2026-02-18T08:56:57.099Z
120+
updated_at: 2026-02-18T08:56:57.099Z
121+
spec_hash: sha256:659bd435cecc3223171c3fce81f671c26baac9ce354c9a6e3c967164983ed9fb
122+
spec_file: specs/INT-004-orchestration-directory.md
123+
- id: INT-005
124+
name: INT-005 — Logging & Traceability
125+
status: IN_PROGRESS
126+
owned_scope:
127+
- src/core/hooks/HookEngine.ts` (Post-Hook implementation)
128+
- src/core/orchestration/OrchestrationDataModel.ts
129+
- .orchestration/agent_trace.jsonl
130+
- src/utils/git.ts` (for VCS revision tracking)
131+
constraints:
132+
- Trace entries must include `sha256:` content hash of modified code
133+
blocks.
134+
- Line ranges must be best-effort (may be approximate for complex edits).
135+
- "Each trace entry must link to:"
136+
- Intent ID
137+
- File path (relative to workspace root)
138+
- VCS revision (Git SHA)
139+
- Timestamp
140+
- Model identifier
141+
- Content hashing must be spatially independent (same code block = same
142+
hash regardless of file location).
143+
acceptance_criteria:
144+
- Post-hook computes SHA-256 hash of modified content for file tools.
145+
- "Trace entry includes all required fields per `document.md` schema:"
146+
- "`id` (UUID)"
147+
- "`timestamp` (ISO 8601)"
148+
- "`vcs.revision_id` (Git SHA)"
149+
- "`files[]` with `relative_path`, `conversations[]`, `ranges[]`,
150+
`content_hash`"
151+
- Trace entries are appended atomically to `agent_trace.jsonl`.
152+
- "Content hash format: `sha256:<hex>`."
153+
- Git SHA is retrieved from workspace root (handles non-Git repos
154+
gracefully).
155+
created_at: 2026-02-18T08:56:57.099Z
156+
updated_at: 2026-02-18T08:56:57.099Z
157+
spec_hash: sha256:2b3421a22c9e27a817e27aea652f3332cdbc821338b52e112ff654ff88c36317
158+
spec_file: specs/INT-005-logging-traceability.md
159+
- id: INT-006
160+
name: INT-006 — Testing & Validation
161+
status: IN_PROGRESS
162+
owned_scope:
163+
- src/core/hooks/**/*.test.ts
164+
- src/core/orchestration/**/*.test.ts
165+
- src/core/tools/SelectActiveIntentTool.test.ts
166+
- tests/integration/hook-system.test.ts
167+
- tests/e2e/intent-traceability.test.ts
168+
constraints:
169+
- Tests must not modify production `.orchestration/` files (use temp
170+
directories).
171+
- Tests must be deterministic and isolated (no shared state).
172+
- Integration tests must verify hook system works with real tool execution.
173+
- E2E tests must simulate full agent workflow (intent selection → code
174+
change → trace logging).
175+
acceptance_criteria:
176+
- Unit tests for `HookEngine.preHook()` and `HookEngine.postHook()`.
177+
- Unit tests for `OrchestrationDataModel` file operations.
178+
- Unit tests for `SelectActiveIntentTool` intent loading and context
179+
generation.
180+
- "Integration test: Verify Pre-Hook blocks destructive tool without
181+
intent."
182+
- "Integration test: Verify Post-Hook logs trace entry after file write."
183+
- "E2E test: Full workflow from intent selection to trace logging."
184+
- All tests pass in CI/CD pipeline.
185+
- Test coverage > 80% for hook and orchestration modules.
186+
created_at: 2026-02-18T08:56:57.099Z
187+
updated_at: 2026-02-18T08:56:57.100Z
188+
spec_hash: sha256:f8343d2839370244e2f1d7b6622494a96438c86b21f42b98b159eb34e33a59c6
189+
spec_file: specs/INT-006-testing-validation.md
190+
- id: INT-007
191+
name: INT-007 — Documentation & Knowledge Base
192+
status: IN_PROGRESS
193+
owned_scope:
194+
- ARCHITECTURE_NOTES.md
195+
- README.md` (Intent-Code Traceability section)
196+
- .orchestration/AGENT.md
197+
- docs/intent-traceability/
198+
- CHANGELOG.md` (relevant entries)
199+
constraints:
200+
- "`ARCHITECTURE_NOTES.md` must document all injection points and hook
201+
integration."
202+
- '`AGENT.md` must be append-only knowledge base for "Lessons Learned".'
203+
- Documentation must be kept in sync with code changes.
204+
- API documentation must include examples for each public method.
205+
acceptance_criteria:
206+
- "`ARCHITECTURE_NOTES.md` includes:"
207+
- Tool execution flow diagram
208+
- Hook injection points with line numbers
209+
- System prompt modification points
210+
- Data model schemas
211+
- "`AGENT.md` includes:"
212+
- Lessons learned from implementation
213+
- Common pitfalls and solutions
214+
- Performance optimizations
215+
- Stylistic rules for intent specifications
216+
- README includes setup instructions and usage examples.
217+
- All public APIs are documented with JSDoc comments.
218+
- Documentation is reviewed and updated with each major change.
219+
created_at: 2026-02-18T08:56:57.100Z
220+
updated_at: 2026-02-18T08:56:57.100Z
221+
spec_hash: sha256:50566c7bdbddce41c4f739cab9631172321f2880e8cb7a35fdf8c0d1a1aa56b4
222+
spec_file: specs/INT-007-documentation.md

.orchestration/agent_trace.jsonl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Agent Trace Ledger (JSONL format - one JSON object per line)
2+
# Append-only, machine-readable history of every mutating action.
3+
# Links abstract Intent to concrete Code Hash for spatial independence.
4+
#
5+
# Example entry:
6+
# {"id":"trace-1234567890-abc","timestamp":"2026-02-16T12:00:00Z","vcs":{"revision_id":"abc123def456"},"files":[{"relative_path":"src/auth/middleware.ts","conversations":[{"url":"task-xyz","contributor":{"entity_type":"AI","model_identifier":"claude-3-5-sonnet"},"ranges":[{"start_line":15,"end_line":45,"content_hash":"sha256:a8f5f167f44f4964e6c998dee827110c"}],"related":[{"type":"intent","value":"INT-001"}]}]}]}
7+

.orchestration/intent_map.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Intent Map
2+
3+
This file maps high-level business intents to physical files and AST nodes. When a manager asks, "Where is the billing logic?", this file provides the answer.
4+
5+
## Intents
6+
7+
<!--
8+
Example entry:
9+
## INT-001: JWT Authentication Migration
10+
- **Status:** IN_PROGRESS
11+
- **Files:**
12+
- `src/auth/middleware.ts` (lines 15-45)
13+
- `src/middleware/jwt.ts` (entire file)
14+
- **AST Nodes:**
15+
- `JwtAuthMiddleware` class
16+
- `validateToken()` function
17+
- **Last Updated:** 2026-02-16T12:00:00Z
18+
-->
19+

packages/types/src/tool.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const toolNames = [
4646
"skill",
4747
"generate_image",
4848
"custom_tool",
49+
"select_active_intent",
4950
] as const
5051

5152
export const toolNamesSchema = z.enum(toolNames)

src/core/assistant-message/presentAssistantMessage.ts

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@ import { generateImageTool } from "../tools/GenerateImageTool"
3737
import { applyDiffTool as applyDiffToolClass } from "../tools/ApplyDiffTool"
3838
import { isValidToolName, validateToolUse } from "../tools/validateToolUse"
3939
import { codebaseSearchTool } from "../tools/CodebaseSearchTool"
40+
import { selectActiveIntentTool } from "../tools/SelectActiveIntentTool"
4041

4142
import { formatResponse } from "../prompts/responses"
4243
import { sanitizeToolUseId } from "../../utils/tool-id"
44+
import { HookEngine } from "../hooks/HookEngine"
4345

4446
/**
4547
* Processes and presents assistant message content to the user interface.
@@ -675,15 +677,45 @@ export async function presentAssistantMessage(cline: Task) {
675677
}
676678
}
677679

680+
// Initialize hook engine for this task
681+
const hookEngine = new HookEngine(cline.cwd)
682+
await hookEngine.initialize()
683+
684+
// Pre-Hook: Intercept tool execution
685+
const preHookResult = await hookEngine.preHook(block.name as ToolName, block, cline)
686+
if (!preHookResult.shouldProceed) {
687+
pushToolResult(formatResponse.toolError(preHookResult.errorMessage || "Tool execution blocked by hook"))
688+
break
689+
}
690+
678691
switch (block.name) {
679-
case "write_to_file":
680-
await checkpointSaveAndMark(cline)
681-
await writeToFileTool.handle(cline, block as ToolUse<"write_to_file">, {
692+
case "select_active_intent":
693+
await selectActiveIntentTool.handle(cline, block as ToolUse<"select_active_intent">, {
682694
askApproval,
683695
handleError,
684696
pushToolResult,
685697
})
686698
break
699+
case "write_to_file":
700+
await checkpointSaveAndMark(cline)
701+
let writeSuccess = false
702+
let writeResult: string | undefined
703+
try {
704+
await writeToFileTool.handle(cline, block as ToolUse<"write_to_file">, {
705+
askApproval,
706+
handleError,
707+
pushToolResult: (result) => {
708+
writeResult = typeof result === "string" ? result : JSON.stringify(result)
709+
pushToolResult(result)
710+
},
711+
})
712+
writeSuccess = true
713+
} catch (error) {
714+
writeSuccess = false
715+
}
716+
// Post-Hook: Log trace entry
717+
await hookEngine.postHook(block.name as ToolName, block, cline, writeSuccess, writeResult)
718+
break
687719
case "update_todo_list":
688720
await updateTodoListTool.handle(cline, block as ToolUse<"update_todo_list">, {
689721
askApproval,
@@ -718,11 +750,23 @@ export async function presentAssistantMessage(cline: Task) {
718750
break
719751
case "edit_file":
720752
await checkpointSaveAndMark(cline)
721-
await editFileTool.handle(cline, block as ToolUse<"edit_file">, {
722-
askApproval,
723-
handleError,
724-
pushToolResult,
725-
})
753+
let editSuccess = false
754+
let editResult: string | undefined
755+
try {
756+
await editFileTool.handle(cline, block as ToolUse<"edit_file">, {
757+
askApproval,
758+
handleError,
759+
pushToolResult: (result) => {
760+
editResult = typeof result === "string" ? result : JSON.stringify(result)
761+
pushToolResult(result)
762+
},
763+
})
764+
editSuccess = true
765+
} catch (error) {
766+
editSuccess = false
767+
}
768+
// Post-Hook: Log trace entry
769+
await hookEngine.postHook(block.name as ToolName, block, cline, editSuccess, editResult)
726770
break
727771
case "apply_patch":
728772
await checkpointSaveAndMark(cline)

0 commit comments

Comments
 (0)