Skip to main content

Workflow Studio

The Workflow Studio is the operator-facing surface for the additive orchestration control plane introduced by the seven-phase refactor in orchestration-refactor-rollout.md. It composes the five existing graph builders, the three (then five) adapters, and the new hash-locked WorkflowSpec registry into a single replayable workflow concept.

What ships

LayerFile / Path
Spec contractalphaswarm/agents/orchestration/spec.py
Registry + persist_specalphaswarm/agents/orchestration/registry_specs.py
Runtimealphaswarm/agents/orchestration/runtime.py
Adapter ABC + metaclassalphaswarm/agents/orchestration/base.py
Adapter registryalphaswarm/agents/orchestration/registry.py
Adapters (5)alphaswarm/agents/orchestration/adapters/
ORMalphaswarm/persistence/models_workflows.py
Migrationalembic/versions/0046_workflow_versioning.py
RESTalphaswarm/api/routes/workflows.py
Celery tasksalphaswarm/tasks/orchestration_tasks.py
DataMCP toolsalphaswarm/data/mcp/tools/orchestration.py, alphaswarm/data/mcp/tools/automation.py
Cache entryworkflows category in alphaswarm/cache/keys.py
Frontend routesalphaswarm_client/src/routes/workflows/
Frontend componentsalphaswarm_client/src/components/workflows/

Spec shape

A workflow selects exactly one OrchestrationAdapter by alias and hands it adapter-specific params. The adapter dispatches internally — composite flows (Crew + Graph + Debate) belong inside their own adapter, not at the spec layer.

name: research.dialectical_with_fusion_v1
description: "Bull/Bear debate + fusion + weight-centric execution"
adapter: LangGraphAdapter
adapter_kind: graph
params:
builder: dialectical # one of build_* in alphaswarm/agents/graph/
builder_kwargs:
max_rounds: 2
schedule:
cron: "30 13 * * 1-5"
timezone: UTC
enabled: false # operator flips after the studio + schedule flags
guardrails:
cost_budget_usd: 3.0
max_calls: 60
max_duration_seconds: 900
annotations: [research, dialectical]
template_target: research

WorkflowSpec.snapshot_hash() is the SHA256 of the canonical JSON form (sorted keys, no whitespace). Re-snapshotting a spec with the same hash returns the existing workflow_spec_versions row; changing any field inserts a NEW row (parallel to agent_spec_versions, bot_versions, rl_experiment_versions, analysis_spec_versions).

Operator flow

  1. Operator flips ALPHASWARM_ORCHESTRATION_STUDIO_ENABLED=true (see the rollout doc).
  2. Frontend navigates to /workflows. List + detail render through <EntityPicker kind="workflows" /> so the dropdown shares the same cache invalidation path as every other entity picker.
  3. Operator hits Run → POST /workflows/{name}/run → enqueues alphaswarm.tasks.orchestration_tasks.run_workflow. The route returns a task_id; the studio attaches via the existing useLiveStream hook for _progress.emit frames (rule 4).
  4. Operator hits Replay on a historical run → POST /workflows/runs/{run_id}/replay re-dispatches with the captured spec_version_id for deterministic reproduction.
  5. Operator hits the topbar KillSwitch's "Halt workflows" action → POST /workflows/halt mirrors the five canonical halt endpoints (/agents/halt, /paper/stop-all, /bots/halt-all, /rl/halt-all, /quant-agents/halt).

Halt fan-out

The Phase 2 WorkflowRuntime checks should_halt(state) between every adapter transition. should_halt is the OR of:

  • has_kill_switch() — Redis-backed global flag (the existing topbar KillSwitch flips this).
  • state["halt_token"] — per-run boolean the Phase 6 /workflows/halt endpoint sets on every active WorkflowRun row inside ALPHASWARM_ORCHESTRATION_HALT_CHECK_TIMEOUT_SECONDS of the API call.

Long-running adapters (CrewProcessAdapter, LangGraphAdapter, DialecticalDebateAdapter) poll context.is_halted() between inner steps so the SLA holds even mid-debate.

Adapter catalog (Phases 2-5)

aliaskindsourcewhen registered
LangGraphAdaptergraphalphaswarmalways
CrewProcessAdaptercrewfinrobotalways (gated invoke)
DialecticalDebateAdapterdebatetradingagentsalways
AutomationScheduleAdapterscheduledaily_stock_analysisalways (gated invoke)
SignalFusionAdapterfusionvibe_tradingalways (gated invoke)
WeightCentricExecutionAdapterexecutionfinrlalways (gated invoke)
WorkflowStudioAdapter (Phase 7)studiolangflowTBD

New adapters land by subclassing OrchestrationAdapter and setting adapter_kind + adapter_alias. The metaclass auto-registers them through alphaswarm.core.registry.register and the shadow per-kind index in alphaswarm/agents/orchestration/registry.py.

Audit trail

Every run produces:

  • A workflow_runs row (one per run) with spec_version_id, inputs, final_state, breadcrumbs, experiment_id, test_id (rule 34), cost_usd, duration_ms, status, halted, error.
  • A series of _progress.emit frames the studio streams live through useLiveStream (frame shape per rule 4).
  • Per-adapter node_span OTEL spans emitted by alphaswarm/agents/observability.py.
  • Optional agent_runs_v2 rows for each inner AgentRuntime call the wrapped adapter makes.

Replay semantics

POST /workflows/runs/{run_id}/replay looks up the matching workflow_runs row, hydrates the frozen workflow_spec_versions.payload, and re-dispatches with the same inputs. Replay produces a NEW workflow_runs row tagged with the original run's id in parent_run_id so the trace lineage stays intact.

See also