mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
feat: prioritize user config, do not merge default tools
Changed loadClaudeCliTools() to only load tools explicitly defined in user config. Previously, DEFAULT_TOOLS_CONFIG.tools was spread before user tools, causing all default tools to be loaded even if not present in user config. User config now has complete control over which tools are loaded.
This commit is contained in:
@@ -41,8 +41,8 @@ PROJECT CONTEXT:
|
|||||||
## Execution Steps
|
## Execution Steps
|
||||||
|
|
||||||
1. **Read all progress**
|
1. **Read all progress**
|
||||||
- Load worker outputs from `.loop/{loopId}.workers/`
|
- Load worker outputs from `.workflow/.loop/{loopId}.workers/`
|
||||||
- Read progress files from `.loop/{loopId}.progress/`
|
- Read progress files from `.workflow/.loop/{loopId}.progress/`
|
||||||
- Consolidate findings
|
- Consolidate findings
|
||||||
|
|
||||||
2. **Verify completeness**
|
2. **Verify completeness**
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ You are a CCW Loop Executor - a stateless iterative development specialist that
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Read current state
|
// Read current state
|
||||||
const state = JSON.parse(Read('.loop/{loopId}.json'))
|
const state = JSON.parse(Read('.workflow/.loop/{loopId}.json'))
|
||||||
|
|
||||||
// Check control signals
|
// Check control signals
|
||||||
if (state.status === 'paused') {
|
if (state.status === 'paused') {
|
||||||
@@ -110,7 +110,7 @@ NEXT_ACTION_NEEDED: {action_name} | WAITING_INPUT | COMPLETED | PAUSED
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function updateState(loopId, skillStateUpdates) {
|
function updateState(loopId, skillStateUpdates) {
|
||||||
const state = JSON.parse(Read(`.loop/${loopId}.json`))
|
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
state.updated_at = getUtc8ISOString()
|
state.updated_at = getUtc8ISOString()
|
||||||
state.skill_state = {
|
state.skill_state = {
|
||||||
...state.skill_state,
|
...state.skill_state,
|
||||||
@@ -118,7 +118,7 @@ function updateState(loopId, skillStateUpdates) {
|
|||||||
last_action: currentAction,
|
last_action: currentAction,
|
||||||
completed_actions: [...state.skill_state.completed_actions, currentAction]
|
completed_actions: [...state.skill_state.completed_actions, currentAction]
|
||||||
}
|
}
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ function updateState(loopId, skillStateUpdates) {
|
|||||||
5. Update state with skill_state
|
5. Update state with skill_state
|
||||||
|
|
||||||
**Output**:
|
**Output**:
|
||||||
- `.loop/{loopId}.progress/develop.md` (initialized)
|
- `.workflow/.loop/{loopId}.progress/develop.md` (initialized)
|
||||||
- State: skill_state populated with tasks
|
- State: skill_state populated with tasks
|
||||||
|
|
||||||
### DEVELOP Action
|
### DEVELOP Action
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ Spawn multiple workers simultaneously, batch wait for results.
|
|||||||
## Session Structure
|
## Session Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
.loop/
|
.workflow/.loop/
|
||||||
+-- {loopId}.json # Master state
|
+-- {loopId}.json # Master state
|
||||||
+-- {loopId}.workers/ # Worker outputs
|
+-- {loopId}.workers/ # Worker outputs
|
||||||
| +-- init.output.json
|
| +-- init.output.json
|
||||||
@@ -184,7 +184,7 @@ Coordinator adapts to mode:
|
|||||||
|
|
||||||
### 3. State Management
|
### 3. State Management
|
||||||
|
|
||||||
Unified state at `.loop/{loopId}.json`:
|
Unified state at `.workflow/.loop/{loopId}.json`:
|
||||||
- **API compatible**: Works with CCW API
|
- **API compatible**: Works with CCW API
|
||||||
- **Extension fields**: Skill-specific data in `skill_state`
|
- **Extension fields**: Skill-specific data in `skill_state`
|
||||||
- **Worker outputs**: Structured JSON for each action
|
- **Worker outputs**: Structured JSON for each action
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ Coordinator -> spawn [develop, debug, validate] in parallel -> wait({ ids: all }
|
|||||||
## Session Structure
|
## Session Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
.loop/
|
.workflow/.loop/
|
||||||
+-- {loopId}.json # Master state
|
+-- {loopId}.json # Master state
|
||||||
+-- {loopId}.workers/ # Worker outputs
|
+-- {loopId}.workers/ # Worker outputs
|
||||||
| +-- develop.output.json
|
| +-- develop.output.json
|
||||||
@@ -242,9 +242,9 @@ function buildWorkerPrompt(action, loopId, state) {
|
|||||||
|
|
||||||
- **Loop ID**: ${loopId}
|
- **Loop ID**: ${loopId}
|
||||||
- **Action**: ${action}
|
- **Action**: ${action}
|
||||||
- **State File**: .loop/${loopId}.json
|
- **State File**: .workflow/.loop/${loopId}.json
|
||||||
- **Output File**: .loop/${loopId}.workers/${action}.output.json
|
- **Output File**: .workflow/.loop/${loopId}.workers/${action}.output.json
|
||||||
- **Progress File**: .loop/${loopId}.progress/${action}.md
|
- **Progress File**: .workflow/.loop/${loopId}.progress/${action}.md
|
||||||
|
|
||||||
## CURRENT STATE
|
## CURRENT STATE
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Read state -> Select mode -> Spawn workers -> Wait results -> Merge -> Update st
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function readState(loopId) {
|
function readState(loopId) {
|
||||||
const stateFile = `.loop/${loopId}.json`
|
const stateFile = `.workflow/.loop/${loopId}.json`
|
||||||
return fs.existsSync(stateFile)
|
return fs.existsSync(stateFile)
|
||||||
? JSON.parse(Read(stateFile))
|
? JSON.parse(Read(stateFile))
|
||||||
: null
|
: null
|
||||||
@@ -252,6 +252,6 @@ function parseWorkerResult(output) {
|
|||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
1. **Worker 生命周期**: spawn → wait → close,不保留 worker
|
1. **Worker 生命周期**: spawn → wait → close,不保留 worker
|
||||||
2. **结果持久化**: Worker 输出写入 `.loop/{loopId}.workers/`
|
2. **结果持久化**: Worker 输出写入 `.workflow/.loop/{loopId}.workers/`
|
||||||
3. **状态同步**: 每次 worker 完成后更新 state
|
3. **状态同步**: 每次 worker 完成后更新 state
|
||||||
4. **超时处理**: send_input 请求收敛,再超时则跳过
|
4. **超时处理**: send_input 请求收敛,再超时则跳过
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
|
|
||||||
## Worker Output Structure
|
## Worker Output Structure
|
||||||
|
|
||||||
Each worker writes to `.loop/{loopId}.workers/{action}.output.json`:
|
Each worker writes to `.workflow/.loop/{loopId}.workers/{action}.output.json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -81,7 +81,7 @@ Each worker writes to `.loop/{loopId}.workers/{action}.output.json`:
|
|||||||
|
|
||||||
## Progress File Structure
|
## Progress File Structure
|
||||||
|
|
||||||
Human-readable progress in `.loop/{loopId}.progress/{action}.md`:
|
Human-readable progress in `.workflow/.loop/{loopId}.progress/{action}.md`:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Develop Progress
|
# Develop Progress
|
||||||
@@ -165,7 +165,7 @@ When `mode === 'parallel'`:
|
|||||||
## Directory Structure
|
## Directory Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
.loop/
|
.workflow/.loop/
|
||||||
+-- loop-b-20260122-abc123.json # Master state
|
+-- loop-b-20260122-abc123.json # Master state
|
||||||
+-- loop-b-20260122-abc123.workers/
|
+-- loop-b-20260122-abc123.workers/
|
||||||
| +-- init.output.json
|
| +-- init.output.json
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ Files are in `.codex/skills/ccw-loop/`:
|
|||||||
|
|
||||||
```
|
```
|
||||||
1. Parse arguments (task or --loop-id)
|
1. Parse arguments (task or --loop-id)
|
||||||
2. Create/read state from .loop/{loopId}.json
|
2. Create/read state from .workflow/.loop/{loopId}.json
|
||||||
3. spawn_agent with ccw-loop-executor role
|
3. spawn_agent with ccw-loop-executor role
|
||||||
4. Main loop:
|
4. Main loop:
|
||||||
a. wait() for agent output
|
a. wait() for agent output
|
||||||
@@ -84,7 +84,7 @@ Files are in `.codex/skills/ccw-loop/`:
|
|||||||
## Session Files
|
## Session Files
|
||||||
|
|
||||||
```
|
```
|
||||||
.loop/
|
.workflow/.loop/
|
||||||
+-- {loopId}.json # Master state (API + Skill)
|
+-- {loopId}.json # Master state (API + Skill)
|
||||||
+-- {loopId}.progress/
|
+-- {loopId}.progress/
|
||||||
+-- develop.md # Development timeline
|
+-- develop.md # Development timeline
|
||||||
@@ -157,7 +157,7 @@ spawn_agent({
|
|||||||
Works with CCW Dashboard Loop Monitor:
|
Works with CCW Dashboard Loop Monitor:
|
||||||
- Dashboard creates loop via API
|
- Dashboard creates loop via API
|
||||||
- API triggers this skill with `--loop-id`
|
- API triggers this skill with `--loop-id`
|
||||||
- Skill reads/writes `.loop/{loopId}.json`
|
- Skill reads/writes `.workflow/.loop/{loopId}.json`
|
||||||
- Dashboard polls state for real-time updates
|
- Dashboard polls state for real-time updates
|
||||||
|
|
||||||
### Control Signals
|
### Control Signals
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ Stateless iterative development loop using Codex subagent pattern. Supports deve
|
|||||||
+-------------------------------------------------------------+
|
+-------------------------------------------------------------+
|
||||||
| loop-v2-routes.ts (Control Plane) |
|
| loop-v2-routes.ts (Control Plane) |
|
||||||
| |
|
| |
|
||||||
| State: .loop/{loopId}.json (MASTER) |
|
| State: .workflow/.loop/{loopId}.json (MASTER) |
|
||||||
| Tasks: .loop/{loopId}.tasks.jsonl |
|
| Tasks: .workflow/.loop/{loopId}.tasks.jsonl |
|
||||||
| |
|
| |
|
||||||
| /start -> Trigger ccw-loop skill with --loop-id |
|
| /start -> Trigger ccw-loop skill with --loop-id |
|
||||||
| /pause -> Set status='paused' (skill checks before action) |
|
| /pause -> Set status='paused' (skill checks before action) |
|
||||||
@@ -42,8 +42,8 @@ Stateless iterative development loop using Codex subagent pattern. Supports deve
|
|||||||
| |
|
| |
|
||||||
| Codex Pattern: spawn_agent -> wait -> send_input -> close |
|
| Codex Pattern: spawn_agent -> wait -> send_input -> close |
|
||||||
| |
|
| |
|
||||||
| Reads/Writes: .loop/{loopId}.json (unified state) |
|
| Reads/Writes: .workflow/.loop/{loopId}.json (unified state) |
|
||||||
| Writes: .loop/{loopId}.progress/* (progress files) |
|
| Writes: .workflow/.loop/{loopId}.progress/* (progress files) |
|
||||||
| |
|
| |
|
||||||
| BEFORE each action: |
|
| BEFORE each action: |
|
||||||
| -> Check status: paused/stopped -> exit gracefully |
|
| -> Check status: paused/stopped -> exit gracefully |
|
||||||
@@ -55,9 +55,9 @@ Stateless iterative development loop using Codex subagent pattern. Supports deve
|
|||||||
|
|
||||||
## Key Design Principles (Codex Adaptation)
|
## Key Design Principles (Codex Adaptation)
|
||||||
|
|
||||||
1. **Unified State**: API and Skill share `.loop/{loopId}.json` state file
|
1. **Unified State**: API and Skill share `.workflow/.loop/{loopId}.json` state file
|
||||||
2. **Control Signals**: Skill checks status field before each action (paused/stopped)
|
2. **Control Signals**: Skill checks status field before each action (paused/stopped)
|
||||||
3. **File-Driven**: All progress documented in `.loop/{loopId}.progress/`
|
3. **File-Driven**: All progress documented in `.workflow/.loop/{loopId}.progress/`
|
||||||
4. **Resumable**: Continue any loop with `--loop-id`
|
4. **Resumable**: Continue any loop with `--loop-id`
|
||||||
5. **Dual Trigger**: Supports API trigger (`--loop-id`) and direct call (task description)
|
5. **Dual Trigger**: Supports API trigger (`--loop-id`) and direct call (task description)
|
||||||
6. **Single Agent Deep Interaction**: Use send_input for multi-phase execution instead of multiple agents
|
6. **Single Agent Deep Interaction**: Use send_input for multi-phase execution instead of multiple agents
|
||||||
@@ -100,7 +100,7 @@ Develop -> Debug -> Validate -> (if issues) -> Develop -> ...
|
|||||||
## Session Structure (Unified Location)
|
## Session Structure (Unified Location)
|
||||||
|
|
||||||
```
|
```
|
||||||
.loop/
|
.workflow/.loop/
|
||||||
+-- {loopId}.json # Master state file (API + Skill shared)
|
+-- {loopId}.json # Master state file (API + Skill shared)
|
||||||
+-- {loopId}.tasks.jsonl # Task list (API managed)
|
+-- {loopId}.tasks.jsonl # Task list (API managed)
|
||||||
+-- {loopId}.progress/ # Skill progress files
|
+-- {loopId}.progress/ # Skill progress files
|
||||||
@@ -129,8 +129,8 @@ const loopId = args['--loop-id'] || (() => {
|
|||||||
return `loop-v2-${timestamp}-${random}`
|
return `loop-v2-${timestamp}-${random}`
|
||||||
})()
|
})()
|
||||||
|
|
||||||
const loopFile = `.loop/${loopId}.json`
|
const loopFile = `.workflow/.loop/${loopId}.json`
|
||||||
const progressDir = `.loop/${loopId}.progress`
|
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||||
|
|
||||||
// Create progress directory
|
// Create progress directory
|
||||||
mkdir -p "${progressDir}"
|
mkdir -p "${progressDir}"
|
||||||
@@ -144,14 +144,14 @@ mkdir -p "${progressDir}"
|
|||||||
// Step 1: Read or create initial state
|
// Step 1: Read or create initial state
|
||||||
let state = null
|
let state = null
|
||||||
if (existingLoopId) {
|
if (existingLoopId) {
|
||||||
state = JSON.parse(Read(`.loop/${loopId}.json`))
|
state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
if (!state) {
|
if (!state) {
|
||||||
console.error(`Loop not found: ${loopId}`)
|
console.error(`Loop not found: ${loopId}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state = createInitialState(loopId, taskDescription)
|
state = createInitialState(loopId, taskDescription)
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Create orchestrator agent (single agent handles all phases)
|
// Step 2: Create orchestrator agent (single agent handles all phases)
|
||||||
@@ -169,7 +169,7 @@ const agent = spawn_agent({
|
|||||||
## LOOP CONTEXT
|
## LOOP CONTEXT
|
||||||
|
|
||||||
- **Loop ID**: ${loopId}
|
- **Loop ID**: ${loopId}
|
||||||
- **State File**: .loop/${loopId}.json
|
- **State File**: .workflow/.loop/${loopId}.json
|
||||||
- **Progress Dir**: ${progressDir}
|
- **Progress Dir**: ${progressDir}
|
||||||
- **Mode**: ${mode} // 'interactive' or 'auto'
|
- **Mode**: ${mode} // 'interactive' or 'auto'
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ ${taskDescription}
|
|||||||
You are executing CCW Loop orchestrator. Your job:
|
You are executing CCW Loop orchestrator. Your job:
|
||||||
|
|
||||||
1. **Check Control Signals**
|
1. **Check Control Signals**
|
||||||
- Read .loop/${loopId}.json
|
- Read .workflow/.loop/${loopId}.json
|
||||||
- If status === 'paused' -> Output "PAUSED" and stop
|
- If status === 'paused' -> Output "PAUSED" and stop
|
||||||
- If status === 'failed' -> Output "STOPPED" and stop
|
- If status === 'failed' -> Output "STOPPED" and stop
|
||||||
- If status === 'running' -> Continue
|
- If status === 'running' -> Continue
|
||||||
@@ -200,7 +200,7 @@ You are executing CCW Loop orchestrator. Your job:
|
|||||||
3. **Execute Action**
|
3. **Execute Action**
|
||||||
- Follow action instructions from ~/.codex/skills/ccw-loop/phases/actions/
|
- Follow action instructions from ~/.codex/skills/ccw-loop/phases/actions/
|
||||||
- Update progress files in ${progressDir}/
|
- Update progress files in ${progressDir}/
|
||||||
- Update state in .loop/${loopId}.json
|
- Update state in .workflow/.loop/${loopId}.json
|
||||||
|
|
||||||
4. **Output Format**
|
4. **Output Format**
|
||||||
\`\`\`
|
\`\`\`
|
||||||
@@ -283,10 +283,10 @@ Continue with: ${actionResult.next_action}
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update iteration count in state
|
// Update iteration count in state
|
||||||
const currentState = JSON.parse(Read(`.loop/${loopId}.json`))
|
const currentState = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
currentState.current_iteration = iteration
|
currentState.current_iteration = iteration
|
||||||
currentState.updated_at = getUtc8ISOString()
|
currentState.updated_at = getUtc8ISOString()
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(currentState, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(currentState, null, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: Cleanup
|
// Step 4: Cleanup
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Complete CCW Loop session and generate summary report.
|
|||||||
### Step 1: Verify Control Signals
|
### Step 1: Verify Control Signals
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const state = JSON.parse(Read(`.loop/${loopId}.json`))
|
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
|
|
||||||
if (state.status !== 'running') {
|
if (state.status !== 'running') {
|
||||||
return {
|
return {
|
||||||
@@ -174,7 +174,7 @@ state.updated_at = timestamp
|
|||||||
state.skill_state.last_action = 'COMPLETE'
|
state.skill_state.last_action = 'COMPLETE'
|
||||||
state.skill_state.summary = stats
|
state.skill_state.summary = stats
|
||||||
|
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output Format
|
## Output Format
|
||||||
@@ -190,8 +190,8 @@ ACTION_RESULT:
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILES_UPDATED:
|
FILES_UPDATED:
|
||||||
- .loop/{loopId}.json: Status set to completed
|
- .workflow/.loop/{loopId}.json: Status set to completed
|
||||||
- .loop/{loopId}.progress/summary.md: Summary report generated
|
- .workflow/.loop/{loopId}.progress/summary.md: Summary report generated
|
||||||
|
|
||||||
NEXT_ACTION_NEEDED: COMPLETED
|
NEXT_ACTION_NEEDED: COMPLETED
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ if (confirmedHypothesis) {
|
|||||||
|
|
||||||
state.skill_state.last_action = 'DEBUG'
|
state.skill_state.last_action = 'DEBUG'
|
||||||
state.updated_at = timestamp
|
state.updated_at = timestamp
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output Format
|
## Output Format
|
||||||
@@ -249,8 +249,8 @@ ACTION_RESULT:
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILES_UPDATED:
|
FILES_UPDATED:
|
||||||
- .loop/{loopId}.progress/debug.md: Understanding updated
|
- .workflow/.loop/{loopId}.progress/debug.md: Understanding updated
|
||||||
- .loop/{loopId}.progress/hypotheses.json: Hypotheses updated
|
- .workflow/.loop/{loopId}.progress/hypotheses.json: Hypotheses updated
|
||||||
- [Source files]: Instrumentation added
|
- [Source files]: Instrumentation added
|
||||||
|
|
||||||
NEXT_ACTION_NEEDED: {DEBUG | VALIDATE | DEVELOP | MENU}
|
NEXT_ACTION_NEEDED: {DEBUG | VALIDATE | DEVELOP | MENU}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Execute development task and record progress to develop.md.
|
|||||||
### Step 1: Verify Control Signals
|
### Step 1: Verify Control Signals
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const state = JSON.parse(Read(`.loop/${loopId}.json`))
|
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
|
|
||||||
if (state.status !== 'running') {
|
if (state.status !== 'running') {
|
||||||
return {
|
return {
|
||||||
@@ -133,7 +133,7 @@ state.skill_state.last_action = 'DEVELOP'
|
|||||||
state.skill_state.completed_actions.push('DEVELOP')
|
state.skill_state.completed_actions.push('DEVELOP')
|
||||||
state.updated_at = timestamp
|
state.updated_at = timestamp
|
||||||
|
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output Format
|
## Output Format
|
||||||
@@ -149,9 +149,9 @@ ACTION_RESULT:
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILES_UPDATED:
|
FILES_UPDATED:
|
||||||
- .loop/{loopId}.json: Task status updated
|
- .workflow/.loop/{loopId}.json: Task status updated
|
||||||
- .loop/{loopId}.progress/develop.md: Progress entry added
|
- .workflow/.loop/{loopId}.progress/develop.md: Progress entry added
|
||||||
- .loop/{loopId}.progress/changes.log: Change entry added
|
- .workflow/.loop/{loopId}.progress/changes.log: Change entry added
|
||||||
|
|
||||||
NEXT_ACTION_NEEDED: {DEVELOP | DEBUG | VALIDATE | MENU}
|
NEXT_ACTION_NEEDED: {DEVELOP | DEBUG | VALIDATE | MENU}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ Initialize CCW Loop session, create directory structure and initial state.
|
|||||||
### Step 1: Verify Control Signals
|
### Step 1: Verify Control Signals
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const state = JSON.parse(Read(`.loop/${loopId}.json`))
|
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
|
|
||||||
if (state.status !== 'running') {
|
if (state.status !== 'running') {
|
||||||
return {
|
return {
|
||||||
@@ -34,7 +34,7 @@ if (state.status !== 'running') {
|
|||||||
### Step 2: Create Directory Structure
|
### Step 2: Create Directory Structure
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const progressDir = `.loop/${loopId}.progress`
|
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||||
|
|
||||||
// Directories created by orchestrator, verify they exist
|
// Directories created by orchestrator, verify they exist
|
||||||
// mkdir -p ${progressDir}
|
// mkdir -p ${progressDir}
|
||||||
@@ -131,7 +131,7 @@ const skillState = {
|
|||||||
|
|
||||||
state.skill_state = skillState
|
state.skill_state = skillState
|
||||||
state.updated_at = getUtc8ISOString()
|
state.updated_at = getUtc8ISOString()
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output Format
|
## Output Format
|
||||||
@@ -143,8 +143,8 @@ ACTION_RESULT:
|
|||||||
- message: Session initialized with {N} development tasks
|
- message: Session initialized with {N} development tasks
|
||||||
|
|
||||||
FILES_UPDATED:
|
FILES_UPDATED:
|
||||||
- .loop/{loopId}.json: skill_state initialized
|
- .workflow/.loop/{loopId}.json: skill_state initialized
|
||||||
- .loop/{loopId}.progress/develop.md: Progress document created
|
- .workflow/.loop/{loopId}.progress/develop.md: Progress document created
|
||||||
|
|
||||||
NEXT_ACTION_NEEDED: {DEVELOP (auto) | MENU (interactive)}
|
NEXT_ACTION_NEEDED: {DEVELOP (auto) | MENU (interactive)}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Display interactive action menu for user selection.
|
|||||||
### Step 1: Verify Control Signals
|
### Step 1: Verify Control Signals
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const state = JSON.parse(Read(`.loop/${loopId}.json`))
|
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
|
|
||||||
if (state.status !== 'running') {
|
if (state.status !== 'running') {
|
||||||
return {
|
return {
|
||||||
@@ -172,7 +172,7 @@ If user selects "exit":
|
|||||||
// Save current state
|
// Save current state
|
||||||
state.status = 'user_exit'
|
state.status = 'user_exit'
|
||||||
state.updated_at = getUtc8ISOString()
|
state.updated_at = getUtc8ISOString()
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
action: 'MENU',
|
action: 'MENU',
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Run tests and verify implementation, record results to validate.md.
|
|||||||
### Step 1: Verify Control Signals
|
### Step 1: Verify Control Signals
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const state = JSON.parse(Read(`.loop/${loopId}.json`))
|
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
|
|
||||||
if (state.status !== 'running') {
|
if (state.status !== 'running') {
|
||||||
return {
|
return {
|
||||||
@@ -174,7 +174,7 @@ state.skill_state.validate.last_run_at = timestamp
|
|||||||
|
|
||||||
state.skill_state.last_action = 'VALIDATE'
|
state.skill_state.last_action = 'VALIDATE'
|
||||||
state.updated_at = timestamp
|
state.updated_at = timestamp
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output Format
|
## Output Format
|
||||||
@@ -191,9 +191,9 @@ ACTION_RESULT:
|
|||||||
}
|
}
|
||||||
|
|
||||||
FILES_UPDATED:
|
FILES_UPDATED:
|
||||||
- .loop/{loopId}.progress/validate.md: Validation report created
|
- .workflow/.loop/{loopId}.progress/validate.md: Validation report created
|
||||||
- .loop/{loopId}.progress/test-results.json: Test results saved
|
- .workflow/.loop/{loopId}.progress/test-results.json: Test results saved
|
||||||
- .loop/{loopId}.progress/coverage.json: Coverage data saved (if available)
|
- .workflow/.loop/{loopId}.progress/coverage.json: Coverage data saved (if available)
|
||||||
|
|
||||||
NEXT_ACTION_NEEDED: {COMPLETE | DEBUG | DEVELOP | MENU}
|
NEXT_ACTION_NEEDED: {COMPLETE | DEBUG | DEVELOP | MENU}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOSt
|
|||||||
* @param loopId - Loop ID (e.g., "loop-v2-20260122-abc123")
|
* @param loopId - Loop ID (e.g., "loop-v2-20260122-abc123")
|
||||||
*/
|
*/
|
||||||
function readLoopState(loopId) {
|
function readLoopState(loopId) {
|
||||||
const stateFile = `.loop/${loopId}.json`
|
const stateFile = `.workflow/.loop/${loopId}.json`
|
||||||
|
|
||||||
if (!fs.existsSync(stateFile)) {
|
if (!fs.existsSync(stateFile)) {
|
||||||
return null
|
return null
|
||||||
@@ -63,7 +63,7 @@ function readLoopState(loopId) {
|
|||||||
* Create new loop state (only for direct calls, API triggers have existing state)
|
* Create new loop state (only for direct calls, API triggers have existing state)
|
||||||
*/
|
*/
|
||||||
function createLoopState(loopId, taskDescription) {
|
function createLoopState(loopId, taskDescription) {
|
||||||
const stateFile = `.loop/${loopId}.json`
|
const stateFile = `.workflow/.loop/${loopId}.json`
|
||||||
const now = getUtc8ISOString()
|
const now = getUtc8ISOString()
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
@@ -83,7 +83,7 @@ function createLoopState(loopId, taskDescription) {
|
|||||||
|
|
||||||
// Ensure directories exist
|
// Ensure directories exist
|
||||||
mkdir -p ".loop"
|
mkdir -p ".loop"
|
||||||
mkdir -p ".loop/${loopId}.progress"
|
mkdir -p ".workflow/.loop/${loopId}.progress"
|
||||||
|
|
||||||
Write(stateFile, JSON.stringify(state, null, 2))
|
Write(stateFile, JSON.stringify(state, null, 2))
|
||||||
return state
|
return state
|
||||||
@@ -137,7 +137,7 @@ async function runOrchestrator(options = {}) {
|
|||||||
return { status: 'error', message: 'Missing loopId or task' }
|
return { status: 'error', message: 'Missing loopId or task' }
|
||||||
}
|
}
|
||||||
|
|
||||||
const progressDir = `.loop/${loopId}.progress`
|
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||||
|
|
||||||
// 2. Create executor agent (single agent for entire loop)
|
// 2. Create executor agent (single agent for entire loop)
|
||||||
const agent = spawn_agent({
|
const agent = spawn_agent({
|
||||||
@@ -154,7 +154,7 @@ async function runOrchestrator(options = {}) {
|
|||||||
## LOOP CONTEXT
|
## LOOP CONTEXT
|
||||||
|
|
||||||
- **Loop ID**: ${loopId}
|
- **Loop ID**: ${loopId}
|
||||||
- **State File**: .loop/${loopId}.json
|
- **State File**: .workflow/.loop/${loopId}.json
|
||||||
- **Progress Dir**: ${progressDir}
|
- **Progress Dir**: ${progressDir}
|
||||||
- **Mode**: ${mode}
|
- **Mode**: ${mode}
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ Execution timeout reached. Please:
|
|||||||
state = readLoopState(loopId)
|
state = readLoopState(loopId)
|
||||||
state.current_iteration = iteration
|
state.current_iteration = iteration
|
||||||
state.updated_at = getUtc8ISOString()
|
state.updated_at = getUtc8ISOString()
|
||||||
Write(`.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
Write(`.workflow/.loop/${loopId}.json`, JSON.stringify(state, null, 2))
|
||||||
|
|
||||||
// Handle different outcomes
|
// Handle different outcomes
|
||||||
switch (actionResult.next_action) {
|
switch (actionResult.next_action) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ CCW Loop state structure definition for Codex subagent pattern.
|
|||||||
|
|
||||||
## State File
|
## State File
|
||||||
|
|
||||||
**Location**: `.loop/{loopId}.json` (unified location, API + Skill shared)
|
**Location**: `.workflow/.loop/{loopId}.json` (unified location, API + Skill shared)
|
||||||
|
|
||||||
## Structure Definition
|
## Structure Definition
|
||||||
|
|
||||||
@@ -208,7 +208,7 @@ Agent checks control signals at start of every action:
|
|||||||
* @returns { continue: boolean, action: 'pause_exit' | 'stop_exit' | 'continue' }
|
* @returns { continue: boolean, action: 'pause_exit' | 'stop_exit' | 'continue' }
|
||||||
*/
|
*/
|
||||||
function checkControlSignals(loopId) {
|
function checkControlSignals(loopId) {
|
||||||
const state = JSON.parse(Read(`.loop/${loopId}.json`))
|
const state = JSON.parse(Read(`.workflow/.loop/${loopId}.json`))
|
||||||
|
|
||||||
switch (state.status) {
|
switch (state.status) {
|
||||||
case 'paused':
|
case 'paused':
|
||||||
@@ -338,17 +338,17 @@ State-to-file mapping:
|
|||||||
|
|
||||||
| State Field | Sync File | Sync Timing |
|
| State Field | Sync File | Sync Timing |
|
||||||
|-------------|-----------|-------------|
|
|-------------|-----------|-------------|
|
||||||
| Entire LoopState | `.loop/{loopId}.json` | Every state change (master) |
|
| Entire LoopState | `.workflow/.loop/{loopId}.json` | Every state change (master) |
|
||||||
| `skill_state.develop` | `.loop/{loopId}.progress/develop.md` | After each dev operation |
|
| `skill_state.develop` | `.workflow/.loop/{loopId}.progress/develop.md` | After each dev operation |
|
||||||
| `skill_state.debug` | `.loop/{loopId}.progress/debug.md` | After each debug operation |
|
| `skill_state.debug` | `.workflow/.loop/{loopId}.progress/debug.md` | After each debug operation |
|
||||||
| `skill_state.validate` | `.loop/{loopId}.progress/validate.md` | After each validation |
|
| `skill_state.validate` | `.workflow/.loop/{loopId}.progress/validate.md` | After each validation |
|
||||||
| Code changes log | `.loop/{loopId}.progress/changes.log` | Each file modification (NDJSON) |
|
| Code changes log | `.workflow/.loop/{loopId}.progress/changes.log` | Each file modification (NDJSON) |
|
||||||
| Debug log | `.loop/{loopId}.progress/debug.log` | Each debug log (NDJSON) |
|
| Debug log | `.workflow/.loop/{loopId}.progress/debug.log` | Each debug log (NDJSON) |
|
||||||
|
|
||||||
### File Structure
|
### File Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
.loop/
|
.workflow/.loop/
|
||||||
+-- loop-v2-20260122-abc123.json # Master state file (API + Skill)
|
+-- loop-v2-20260122-abc123.json # Master state file (API + Skill)
|
||||||
+-- loop-v2-20260122-abc123.tasks.jsonl # Task list (API managed)
|
+-- loop-v2-20260122-abc123.tasks.jsonl # Task list (API managed)
|
||||||
+-- loop-v2-20260122-abc123.progress/ # Skill progress files
|
+-- loop-v2-20260122-abc123.progress/ # Skill progress files
|
||||||
@@ -366,7 +366,7 @@ If master state file corrupted, rebuild skill_state from progress files:
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
function rebuildSkillStateFromProgress(loopId) {
|
function rebuildSkillStateFromProgress(loopId) {
|
||||||
const progressDir = `.loop/${loopId}.progress`
|
const progressDir = `.workflow/.loop/${loopId}.progress`
|
||||||
|
|
||||||
// Parse progress files to rebuild state
|
// Parse progress files to rebuild state
|
||||||
const skill_state = {
|
const skill_state = {
|
||||||
@@ -381,7 +381,7 @@ function rebuildSkillStateFromProgress(loopId) {
|
|||||||
|
|
||||||
## Codex Pattern Notes
|
## Codex Pattern Notes
|
||||||
|
|
||||||
1. **Agent reads state**: Agent reads `.loop/{loopId}.json` at action start
|
1. **Agent reads state**: Agent reads `.workflow/.loop/{loopId}.json` at action start
|
||||||
2. **Agent writes state**: Agent updates state after action completion
|
2. **Agent writes state**: Agent updates state after action completion
|
||||||
3. **Orchestrator tracks iterations**: Main loop tracks `current_iteration`
|
3. **Orchestrator tracks iterations**: Main loop tracks `current_iteration`
|
||||||
4. **Single agent context**: All state updates in same agent conversation via send_input
|
4. **Single agent context**: All state updates in same agent conversation via send_input
|
||||||
|
|||||||
@@ -439,9 +439,9 @@ export function loadClaudeCliTools(projectDir: string): ClaudeCliToolsConfig & {
|
|||||||
const migrated = migrateConfig(parsed, projectDir);
|
const migrated = migrateConfig(parsed, projectDir);
|
||||||
const needsSave = migrated.version !== parsed.version;
|
const needsSave = migrated.version !== parsed.version;
|
||||||
|
|
||||||
// Merge tools with defaults and ensure required fields exist
|
// Load user-configured tools only (defaults NOT merged)
|
||||||
const mergedTools: Record<string, ClaudeCliTool> = {};
|
const mergedTools: Record<string, ClaudeCliTool> = {};
|
||||||
for (const [key, tool] of Object.entries({ ...DEFAULT_TOOLS_CONFIG.tools, ...(migrated.tools || {}) })) {
|
for (const [key, tool] of Object.entries(migrated.tools || {})) {
|
||||||
mergedTools[key] = {
|
mergedTools[key] = {
|
||||||
...ensureToolTags(tool),
|
...ensureToolTags(tool),
|
||||||
type: tool.type ?? 'builtin',
|
type: tool.type ?? 'builtin',
|
||||||
|
|||||||
Reference in New Issue
Block a user