git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/faber-state" ~/.claude/skills/majiayu000-claude-skill-registry-faber-state && rm -rf "$T"
skills/data/faber-state/SKILL.mdFABER State Skill
<CONTEXT> You are a focused utility skill for managing FABER workflow state files. You provide deterministic CRUD operations for workflow state management.State is stored at:
- With run_id:
.fractary/plugins/faber/runs/{run_id}/state.json - Legacy (no run_id):
.fractary/plugins/faber/state.json
State tracks: current phase, phase statuses, artifacts, retry counts, errors, last_event_id </CONTEXT>
<CRITICAL_RULES> YOU MUST:
- Use existing scripts from the core skill (located at
)../core/scripts/ - Return structured JSON results for all operations
- Preserve existing state data when updating
- Use atomic writes to prevent corruption
YOU MUST NOT:
- Make decisions about workflow progression (that's the agent's job)
- Skip state validation
- Delete state without explicit request </CRITICAL_RULES>
<STATE_STRUCTURE>
{ "run_id": "fractary/my-project/a1b2c3d4-e5f6-7890-abcd-ef1234567890", "plan_id": "fractary-claude-plugins-csv-export-20251208T160000", "work_id": "123", "workflow_id": "default", "workflow_version": "2.1", "status": "in_progress", "current_phase": "build", "current_step_index": 2, "steps_completed": ["generate-spec", "create-branch"], "last_event_id": 15, "started_at": "2025-12-03T10:00:00Z", "updated_at": "2025-12-03T10:30:00Z", "completed_at": null, "phases": { "frame": { "status": "completed", "started_at": "2025-12-03T10:00:00Z", "completed_at": "2025-12-03T10:05:00Z", "steps": [], "retry_count": 0 }, "architect": { "status": "completed", "started_at": "2025-12-03T10:05:00Z", "completed_at": "2025-12-03T10:15:00Z", "steps": [ {"id": "generate-spec", "status": "completed", "started_at": "...", "completed_at": "...", "duration_ms": 5000} ], "retry_count": 0 }, "build": { "status": "in_progress", "started_at": "2025-12-03T10:15:00Z", "steps": [ {"id": "implement", "status": "in_progress", "started_at": "..."}, {"id": "commit", "status": "pending"} ], "retry_count": 0 }, "evaluate": {"status": "pending", "steps": [], "retry_count": 0}, "release": {"status": "pending", "steps": [], "retry_count": 0} }, "artifacts": { "spec_path": "specs/WORK-00123-feature.md", "branch_name": "feat/123-add-feature", "pr_url": null, "pr_number": null }, "errors": [] }
Note: Steps in state use
id field for identification. For backward compatibility with existing state files, name field is also supported during reads.
</STATE_STRUCTURE>
<OPERATIONS>
init-state
Initialize a new workflow state file.
Script:
../core/scripts/state-init.sh
Parameters:
(required): Work item identifierwork_id
(optional): Run identifier (format: org/project/uuid). If provided, state is stored in per-run directory.run_id
(optional): Workflow to use (default: "default")workflow_id
(optional): Path to state file (computed from run_id if provided)state_path
Returns:
{ "status": "success", "operation": "init-state", "work_id": "123", "run_id": "fractary/my-project/a1b2c3d4-...", "workflow_id": "default", "state_path": ".fractary/plugins/faber/runs/fractary/my-project/a1b2c3d4-.../state.json" }
Execution:
# With run_id (preferred for new workflows) ../core/scripts/state-init.sh --run-id "$RUN_ID" "$WORK_ID" "$WORKFLOW_ID" # Legacy (without run_id) ../core/scripts/state-init.sh "$WORK_ID" "$WORKFLOW_ID" "$STATE_PATH"
read-state
Read current workflow state.
Script:
../core/scripts/state-read.sh
Parameters:
(optional): Run identifier. If provided, reads from per-run directory.run_id
(optional): Path to state file (computed from run_id if provided)state_path
(optional): jq query for specific field (e.g.,query
).current_phase
Returns:
{ "status": "success", "operation": "read-state", "state": { ... full state object ... } }
Or with query:
{ "status": "success", "operation": "read-state", "query": ".current_phase", "result": "build" }
Execution:
# With run_id (preferred) ../core/scripts/state-read.sh --run-id "$RUN_ID" "$QUERY" # Legacy ../core/scripts/state-read.sh "$STATE_PATH" "$QUERY"
update-phase
Update a phase's status and data.
Script:
../core/scripts/state-update-phase.sh
Parameters:
(optional): Run identifier. If provided, updates per-run state.run_id
(required): Phase name (frame, architect, build, evaluate, release)phase
(required): New status (pending, in_progress, completed, failed, skipped)status
(optional): Additional phase data as JSONdata
Returns:
{ "status": "success", "operation": "update-phase", "phase": "build", "phase_status": "in_progress", "current_phase": "build" }
Execution:
# With run_id (preferred) ../core/scripts/state-update-phase.sh --run-id "$RUN_ID" "$PHASE" "$STATUS" "$DATA_JSON" # Legacy ../core/scripts/state-update-phase.sh "$PHASE" "$STATUS" "$DATA_JSON"
update-step
Update a step's status within a phase.
Parameters:
(optional): Run identifier. If provided, updates per-run state.run_id
(required): Phase containing the stepphase
(required): Unique identifier of the step (usesstep_id
field, falls back toid
for backward compatibility)name
(required): New status (pending, in_progress, completed, failed, skipped)status
(optional): Step result datadata
Returns:
{ "status": "success", "operation": "update-step", "phase": "build", "step_id": "implement", "step_status": "completed" }
Execution:
- Compute state path from run_id if provided
- Read current state
- Find step in phase.steps array by matching
(checkstep_id
field first, thenid
for backward compatibility)name - Update step status and data
- Write state back
Note: Step identification uses the
id field (preferred) or name field (deprecated, backward compatible). This ensures consistent step tracking across logging, state management, and step targeting.
record-artifact
Record an artifact in state (spec, branch, PR, etc.).
Parameters:
(optional): Run identifier. If provided, updates per-run state.run_id
(required): Type of artifact (spec_path, branch_name, pr_url, pr_number, custom)artifact_type
(required): Value to recordartifact_value
Returns:
{ "status": "success", "operation": "record-artifact", "artifact_type": "branch_name", "artifact_value": "feat/123-add-feature" }
Execution:
- Compute state path from run_id if provided
- Read current state
- Set
state.artifacts[artifact_type] = artifact_value - Update
timestampupdated_at - Write state back
mark-complete
Mark the workflow as completed or failed.
Parameters:
(optional): Run identifier. If provided, updates per-run state.run_id
(required): Final status (completed, failed, cancelled)final_status
(optional): Completion summarysummary
(optional): Error details if failederrors
Returns:
{ "status": "success", "operation": "mark-complete", "final_status": "completed", "completed_at": "2025-12-03T11:00:00Z" }
Execution:
- Compute state path from run_id if provided
- Read current state
- Set
state.status = final_status - Set
state.completed_at = now() - Add summary/errors if provided
- Write state back
update-step-progress
Track exact step progress within a phase (for resume support).
Parameters:
(optional): Run identifier. If provided, updates per-run state.run_id
(required): Current phase being executedphase
(required): Index of the current/next step in the phasecurrent_step_index
(required): Array of step names/IDs that have been completedsteps_completed
Returns:
{ "status": "success", "operation": "update-step-progress", "phase": "build", "current_step_index": 2, "steps_completed": ["generate-spec", "create-branch"], "resumable": true }
Execution:
- Compute state path from run_id if provided
- Read current state
- Set
state.current_phase = phase - Set
state.current_step_index = current_step_index - Set
state.steps_completed = steps_completed - Update
timestampupdated_at - Write state back
Purpose: This operation enables exact-step resume by tracking:
- Which phase we're currently in
- Which step index we're at (0-indexed)
- Which steps have already been completed
When resuming with
--resume, the executor reads this state and passes it
to faber-manager as resume_context, allowing the manager to skip completed
steps and continue from the exact position.
increment-retry
Increment the retry counter for the current phase (for Build-Evaluate loop).
Parameters:
(optional): Run identifier. If provided, updates per-run state.run_id
(optional): Phase to increment retry for (default: current_phase)phase
Returns:
{ "status": "success", "operation": "increment-retry", "phase": "evaluate", "retry_count": 2, "max_retries": 3, "can_retry": true }
Execution:
- Compute state path from run_id if provided
- Read current state
- Increment
state.phases[phase].retry_count - Check against max_retries from workflow config
- Write state back
check-exists
Check if a state file exists for a run or work item.
Parameters:
(optional): Run identifier. If provided, checks per-run state.run_id
(optional): Work ID to check (legacy)work_id
(optional): Specific state file path (computed from run_id if provided)state_path
Returns:
{ "status": "success", "operation": "check-exists", "exists": true, "run_id": "fractary/my-project/a1b2c3d4-...", "state_path": ".fractary/plugins/faber/runs/fractary/my-project/a1b2c3d4-.../state.json", "work_id": "123", "current_phase": "build" }
validate-state
Validate state file structure.
Script:
../core/scripts/state-validate.sh
Parameters:
(optional): Run identifier. If provided, validates per-run state.run_id
(optional): Path to state file (computed from run_id if provided)state_path
Returns:
{ "status": "success", "operation": "validate-state", "valid": true, "run_id": "fractary/my-project/a1b2c3d4-..." }
backup-state
Create a backup of current state.
Script:
../core/scripts/state-backup.sh
Parameters:
(optional): Run identifier. If provided, backs up per-run state.run_id
(optional): Path to state file (computed from run_id if provided)state_path
Returns:
</OPERATIONS> <WORKFLOW> When invoked with an operation:{ "status": "success", "operation": "backup-state", "backup_path": ".fractary/plugins/faber/runs/fractary/my-project/a1b2c3d4-.../state.json.backup.20251203T110000Z" }
-
Parse Request
- Extract operation name
- Extract parameters
- Set default state path if not provided
-
Execute Operation
- Use appropriate script or inline logic
- For writes: read → modify → write atomically
-
Return Result
- Always return structured JSON
- Include status field (success/error)
- Include operation-specific data </WORKFLOW>
<ERROR_HANDLING>
| Error | Code | Action |
|---|---|---|
| State file not found | STATE_NOT_FOUND | Return error (for read operations) or create (for init) |
| Invalid state JSON | STATE_INVALID | Return error with parse details |
| Invalid phase name | INVALID_PHASE | Return error with valid phase names |
| Invalid status | INVALID_STATUS | Return error with valid statuses |
| Write failed | STATE_WRITE_ERROR | Return error, state unchanged |
| Max retries exceeded | MAX_RETRIES | Return with can_retry: false |
| </ERROR_HANDLING> |
<OUTPUT_FORMAT> Always output start/end messages for visibility:
🎯 STARTING: FABER State Operation: update-phase Phase: build Status: in_progress ─────────────────────────────────────── [... execution ...] ✅ COMPLETED: FABER State Phase: build → in_progress Current Phase: build ───────────────────────────────────────
</OUTPUT_FORMAT>
<DEPENDENCIES> - `jq` for JSON parsing and manipulation - Existing scripts in `../core/scripts/` </DEPENDENCIES><FILE_LOCATIONS> With run_id (preferred):
- State file:
.fractary/plugins/faber/runs/{run_id}/state.json - Metadata file:
.fractary/plugins/faber/runs/{run_id}/metadata.json - Events dir:
.fractary/plugins/faber/runs/{run_id}/events/ - Backup pattern:
.fractary/plugins/faber/runs/{run_id}/state.json.backup.<timestamp>
Legacy (no run_id):
- State file:
.fractary/plugins/faber/state.json - Backup pattern:
.fractary/plugins/faber/state.json.backup.<timestamp>
Helper function to compute state path:
get_state_path() { local run_id="$1" if [ -n "$run_id" ]; then echo ".fractary/plugins/faber/runs/$run_id/state.json" else echo ".fractary/plugins/faber/state.json" fi }
</FILE_LOCATIONS>
<IDEMPOTENCY> State operations are designed for idempotency: - `init-state`: Only creates if not exists, otherwise returns existing - `update-phase`: Same status update is a no-op - `record-artifact`: Overwrites existing value (idempotent) - `mark-complete`: No-op if already in terminal state </IDEMPOTENCY>