Action Workflow System¶
The FCC framework defines a 6-action system that describes what each persona can do, orthogonal to the graph-based workflow that describes when they act. Every persona can perform six action types: scaffold, refactor, debug, test, compare, and document. The system comprises 312 action definitions across 102 core personas.
The Six Action Types¶
Each action type has a specific purpose and preamble that guides the persona's behavior:
| Action Type | Purpose | Preamble |
|---|---|---|
scaffold |
Generate new artifacts from scratch | Following best practices and governance requirements |
refactor |
Improve and modernize existing artifacts | Preserving correctness and meeting governance standards |
debug |
Diagnose and fix issues | Identifying root causes with prevention recommendations |
test |
Validate quality against constraints | Generating comprehensive test suites with edge-case coverage |
compare |
Evaluate alternatives | Analyzing trade-offs across performance, cost, and compliance |
document |
Generate comprehensive documentation | Including purpose, usage, architecture, and operational guidance |
The action types are defined in the WorkflowActionType enum:
from fcc.workflow.actions import WorkflowActionType
# All six types in canonical order
all_types = WorkflowActionType.all_types()
# [SCAFFOLD, REFACTOR, DEBUG, TEST, COMPARE, DOCUMENT]
WorkflowAction¶
A WorkflowAction is a frozen dataclass describing what a specific persona does when performing a particular action type. It includes execution steps, constraints, inputs, outputs, and examples.
| Field | Type | Description |
|---|---|---|
persona_id |
str |
ID of the persona this action belongs to |
action_type |
WorkflowActionType |
One of the six action types |
description |
str |
What the persona does for this action |
execution_steps |
tuple[str, ...] |
Ordered steps to execute the action |
inputs |
tuple[str, ...] |
Required inputs for this action |
outputs |
tuple[str, ...] |
Expected outputs from this action |
constraints |
tuple[str, ...] |
Rules and limitations for this action |
examples |
tuple[str, ...] |
Example usage scenarios |
Actions are serializable to and from dictionaries and YAML:
from fcc.workflow.actions import WorkflowAction, WorkflowActionType
action = WorkflowAction(
persona_id="SQC",
action_type=WorkflowActionType.SCAFFOLD,
description="Generate a new SQL query from requirements.",
execution_steps=("Parse requirements", "Design schema", "Write query"),
inputs=("Database schema", "Business requirements"),
outputs=("SQL query file", "Query documentation"),
constraints=("Must use parameterized queries",),
)
WorkflowActionRegistry¶
The WorkflowActionRegistry is the central store for all action definitions. It supports loading from YAML files, lookup by persona ID or action type, and schema-validated loading.
Loading Actions¶
from fcc.workflow.actions import WorkflowActionRegistry
# From a single YAML file
registry = WorkflowActionRegistry.from_yaml("actions/core.yaml")
# From a directory of YAML files
registry = WorkflowActionRegistry.from_yaml_directory("src/fcc/data/personas/actions/")
# With JSON Schema validation
registry = WorkflowActionRegistry.from_yaml_validated(
"actions/core.yaml", "schemas/action_schema.json"
)
Querying Actions¶
from fcc.workflow.actions import WorkflowActionType
# Get a specific action
action = registry.get("SQC", WorkflowActionType.SCAFFOLD)
# Get all actions for a persona
actions = registry.for_persona("SQC") # Returns list[WorkflowAction]
# Get all actions of a specific type across all personas
scaffold_actions = registry.for_type(WorkflowActionType.SCAFFOLD)
# Check if an action exists
exists = registry.has_action("SQC", WorkflowActionType.DEBUG)
# List all persona IDs with actions
persona_ids = registry.persona_ids # sorted list of IDs
# List all registered action types
types = registry.action_types # sorted list of WorkflowActionType
Mutating the Registry¶
# Add a single action
registry.add(new_action)
# Merge two registries into a new one
combined = registry1.merge(registry2)
# Export to YAML
registry.to_yaml("output/actions.yaml")
ActionEngine¶
The ActionEngine orchestrates execution of persona actions. It loads action definitions from the registry, builds persona-aware prompts incorporating R.I.S.C.E.A.R. specifications and constitution rules, and invokes an AI client for execution.
Initialization¶
from fcc.workflow.action_engine import ActionEngine
engine = ActionEngine(
persona_registry=persona_registry,
action_registry=action_registry,
ai_client=ai_client, # Optional; None = deterministic mock mode
event_bus=event_bus, # Optional; publishes action.started/completed/failed
)
Running an Action¶
from fcc.workflow.actions import WorkflowActionType
result = engine.run(
persona_id="SQC",
action_type=WorkflowActionType.SCAFFOLD,
inputs={"query": "Find all active users", "database": "postgres"},
)
print(result.content) # The generated output
print(result.success) # True/False
print(result.error) # Error message if failed
print(result.metadata) # {"mode": "mock"} or {"mode": "ai", "model": "..."}
Mock vs. AI-Powered Mode¶
When no AI client is configured, the engine operates in deterministic mock mode, returning structured placeholder content. This is useful for testing workflows without incurring API costs.
When an AI client is provided, the engine builds two prompts:
- System prompt: Persona identity (name, role, archetype, style), action context (preamble, description), R.I.S.C.E.A.R. constraints, expected outputs, and constitution rules (hard-stop and mandatory patterns).
- User prompt: Execution steps, required inputs, expected outputs, and any user-provided inputs.
Prompt Generation¶
The get_action_prompt() function constructs persona-aware prompts by combining the persona's R.I.S.C.E.A.R. specification with the action definition:
from fcc.workflow.action_engine import get_action_prompt
prompts = get_action_prompt(persona, action)
# prompts["system"] — full persona identity + constraints + constitution
# prompts["user"] — execution steps + inputs + outputs
The system prompt includes:
- Persona identity (name, ID, role title)
- R.I.S.C.E.A.R. role description
- Archetype and style
- Action type preamble and description
- R.I.S.C.E.A.R. constraints
- Action-specific constraints
- Expected outputs
- Constitution hard-stop and mandatory rules from
doc_context
ActionResult¶
Every action execution returns an ActionResult dataclass:
| Field | Type | Description |
|---|---|---|
persona_id |
str |
The persona that performed the action |
action_type |
WorkflowActionType |
The type of action performed |
content |
str |
The generated output content |
success |
bool |
Whether the action succeeded |
error |
str | None |
Error message if the action failed |
metadata |
dict[str, Any] |
Additional metadata (mode, model, tokens) |
Event Bus Integration¶
When an EventBus is provided, the ActionEngine publishes events at key lifecycle points:
| Event Type | When Published |
|---|---|
action.started |
Before action execution begins |
action.completed |
After successful execution |
action.failed |
When an error occurs during execution |
Each event payload includes persona_id and action_type, plus mode-specific metadata.
YAML Action File Format¶
Action definitions are stored in YAML files under src/fcc/data/personas/actions/:
actions:
- persona_id: SQC
action_type: scaffold
description: "Generate a new SQL query from requirements."
execution_steps:
- "Parse the business requirements"
- "Identify required tables and relationships"
- "Write the SQL query with parameterized inputs"
inputs:
- "Database schema documentation"
- "Business requirements specification"
outputs:
- "SQL query file"
- "Query documentation with usage examples"
constraints:
- "Must use parameterized queries to prevent SQL injection"
examples:
- "Generate a customer activity report query"