Running Your First Workflow Action¶
The FCC framework defines a 6-action-type system that describes what any persona can do. Actions are orthogonal to the workflow graph (which describes when personas act). This tutorial walks you through loading actions, selecting a persona, and executing an action via the ActionEngine.
The Six Action Types¶
Every persona can perform up to six action types, defined by the WorkflowActionType enum:
| Action Type | Purpose |
|---|---|
scaffold |
Generate new artifacts from scratch following best practices and governance requirements |
refactor |
Improve and modernize existing artifacts while preserving correctness |
debug |
Diagnose and fix issues, identifying root causes and providing corrective actions |
test |
Validate quality by generating comprehensive test suites with edge-case coverage |
compare |
Evaluate alternatives by analyzing trade-offs across performance, cost, and compliance |
document |
Generate comprehensive documentation including purpose, usage, and architecture |
Actions vs. Workflows
Actions describe capabilities -- what a persona can do. Workflows describe sequences -- the order in which personas are activated. A persona might be activated at a workflow node and then execute a scaffold action to produce its deliverable.
Loading Actions from YAML¶
Actions are defined in YAML files under data/personas/actions/. Each file contains action definitions for one or more personas.
from fcc.workflow.actions import WorkflowActionRegistry, WorkflowActionType
# Load actions from a single YAML file
registry = WorkflowActionRegistry.from_yaml("src/fcc/data/personas/actions/core.yaml")
# Or load all actions from a directory
registry = WorkflowActionRegistry.from_yaml_directory("src/fcc/data/personas/actions/")
# Inspect what was loaded
print(f"Total actions: {len(registry)}")
print(f"Personas with actions: {registry.persona_ids}")
print(f"Action types available: {[t.value for t in registry.action_types]}")
Expected output:
Total actions: 204
Personas with actions: ['AMS', 'BC', 'BCHM', 'BV', 'CIA', ...]
Action types available: ['compare', 'debug', 'document', 'refactor', 'scaffold', 'test']
Querying Actions¶
The WorkflowActionRegistry supports lookup by persona, by action type, or by a specific combination:
# Get all actions for the Research Crafter
rc_actions = registry.for_persona("RC")
for action in rc_actions:
print(f" {action.action_type.value}: {action.description[:60]}...")
# Get all scaffold actions across all personas
scaffold_actions = registry.for_type(WorkflowActionType.SCAFFOLD)
print(f"\nScaffold actions: {len(scaffold_actions)} personas")
# Get a specific action
action = registry.get("RC", WorkflowActionType.SCAFFOLD)
print(f"\nRC scaffold: {action.description}")
print(f" Steps: {len(action.execution_steps)}")
print(f" Inputs: {list(action.inputs)}")
print(f" Outputs: {list(action.outputs)}")
Setting Up the ActionEngine¶
The ActionEngine connects personas, actions, and (optionally) an AI client. In mock mode, it produces deterministic results without calling any external API:
from fcc.personas.registry import PersonaRegistry
from fcc.workflow.actions import WorkflowActionRegistry, WorkflowActionType
from fcc.workflow.action_engine import ActionEngine
# Load personas and actions
personas = PersonaRegistry.from_data_dir("src/fcc/data/personas")
actions = WorkflowActionRegistry.from_yaml_directory(
"src/fcc/data/personas/actions/"
)
# Create the engine in mock mode (no AI client)
engine = ActionEngine(
persona_registry=personas,
action_registry=actions,
ai_client=None, # Mock mode
)
# List which personas have actions
available = engine.available_personas()
print(f"Personas with actions: {len(available)}")
Running an Action¶
Execute an action by specifying the persona ID and action type:
from fcc.workflow.actions import WorkflowActionType
result = engine.run("RC", WorkflowActionType.SCAFFOLD)
print(f"Persona: {result.persona_id}")
print(f"Action: {result.action_type.value}")
print(f"Success: {result.success}")
print(f"Mode: {result.metadata.get('mode')}")
print(f"\n{result.content}")
Expected output:
Persona: RC
Action: scaffold
Success: True
Mode: mock
[Mock scaffold result for Research Crafter]
Action: Generate new research briefs from source materials...
Persona: Research Crafter (RC)
Steps: 5
Inputs: 3
Outputs: 4
Passing Custom Inputs¶
You can supply additional context via the inputs parameter:
result = engine.run(
"BC",
WorkflowActionType.DOCUMENT,
inputs={
"project": "Payment Gateway",
"scope": "Architecture decision records",
"audience": "Senior engineers",
},
)
print(f"Success: {result.success}")
print(f"Content preview: {result.content[:200]}")
Connecting to the Event Bus¶
The ActionEngine integrates with the FCC event bus to emit lifecycle events. This enables observability and cross-system coordination:
from fcc.messaging.bus import EventBus
from fcc.messaging.events import EventType
bus = EventBus()
# Track action events
events_received = []
bus.subscribe(lambda e: events_received.append(e))
# Create engine with event bus
engine = ActionEngine(
persona_registry=personas,
action_registry=actions,
event_bus=bus,
)
result = engine.run("DE", WorkflowActionType.TEST)
print(f"Events emitted: {len(events_received)}")
for event in events_received:
print(f" {event.event_type.value}: {event.payload}")
Expected output:
Events emitted: 2
action.started: {'persona_id': 'DE', 'action_type': 'test'}
action.completed: {'persona_id': 'DE', 'action_type': 'test', 'mode': 'mock'}
Understanding Action Prompts¶
When an AI client is configured, the engine builds persona-aware prompts. You can inspect these prompts without running the action:
from fcc.workflow.action_engine import get_action_prompt
persona = personas.get("RC")
action = actions.get("RC", WorkflowActionType.SCAFFOLD)
prompts = get_action_prompt(persona, action)
print("=== System Prompt (first 300 chars) ===")
print(prompts["system"][:300])
print("\n=== User Prompt ===")
print(prompts["user"][:300])
The system prompt includes the persona's R.I.S.C.E.A.R. specification (role, archetype, style, constraints), the action preamble, and any constitution rules from the persona's doc_context. The user prompt contains the execution steps, required inputs, and expected outputs.
Next Steps¶
- Understanding the Event Bus -- Learn how actions publish events
- Adding Observability to Workflows -- Instrument actions with tracing and metrics
- Cross-Plugin Orchestration -- Coordinate actions across plugins