Workflow Features
Spectral workflows define state machines with transitions, making it easy to model business processes, application flows, and complex state management.
Basic Workflow Syntax
A workflow consists of states and transitions between those states:
workflow OrderFlow {
Pending -> Processing
Processing -> Shipped
Shipped -> Delivered
}
✨ Edit in StudioInitial State Keyword
Use the initial keyword to explicitly define which state a workflow should start in. This is optional—if not specified, the workflow will default to the first state.
Setting Initial State
workflow TaskFlow {
initial Todo // Explicitly set initial state
Todo -> InProgress
InProgress -> Done
Done -> Archived
}
✨ Edit in StudioWithout Initial State
If you don't specify an initial state, the workflow uses the first state mentioned:
workflow TaskFlow {
Todo -> InProgress // Todo becomes the initial state
InProgress -> Done
Done -> Archived
}
✨ Edit in StudioWorkflow States
Simple States
workflow ContentFlow {
initial Draft
Draft -> Review
Review -> Published
Published -> Archived
}
✨ Edit in StudioMultiple Transitions from a State
workflow OrderFlow {
initial Pending
Pending -> Processing
Pending -> Cancelled // Multiple transitions from Pending
Processing -> Shipped
Processing -> Cancelled // Can cancel from Processing too
Shipped -> Delivered
}
✨ Edit in StudioBidirectional Transitions
Model workflows where states can move back and forth:
workflow DocumentFlow {
initial Draft
Draft -> Review
Review -> Draft // Can return to draft
Review -> Approved
Approved -> Published
Published -> Archived
Archived -> Draft // Can revive from archive
}
✨ Edit in StudioComplex Workflows
Multi-Path Workflows
workflow PaymentFlow {
initial Pending
// Success path
Pending -> Authorized
Authorized -> Captured
Captured -> Completed
// Alternative paths
Pending -> Failed
Authorized -> Voided
Captured -> Refunded
// All paths can reach Completed
Refunded -> Completed
Failed -> Completed
}
✨ Edit in StudioApproval Workflows
workflow ApprovalFlow {
initial Submitted
Submitted -> UnderReview
UnderReview -> Approved
UnderReview -> Rejected
UnderReview -> NeedsChanges
NeedsChanges -> Submitted // Loop back
Rejected -> Closed
Approved -> Closed
}
✨ Edit in StudioContent Management
workflow ContentLifecycle {
initial Draft
// Creation phase
Draft -> Review
// Review phase
Review -> InRevision
Review -> Approved
InRevision -> Review // Loop back
// Publication phase
Approved -> Scheduled
Scheduled -> Published
// Maintenance phase
Published -> Unpublished
Unpublished -> Archived
Archived -> Draft // Can revive content
}
✨ Edit in StudioCode Generation
TypeScript Output
Workflows generate TypeScript enums and state machine classes:
// Generated from workflow TaskFlow
export enum TaskFlowState {
Todo = "Todo",
InProgress = "InProgress",
Done = "Done",
Archived = "Archived"
}
export class TaskFlowWorkflow {
private currentState: TaskFlowState;
constructor(initialState?: TaskFlowState, context?: SpectralContext) {
// Uses the initial state from the workflow definition
this.currentState = initialState ?? TaskFlowState.Todo;
this.context = context || new SpectralContext();
}
canTransitionTo(state: TaskFlowState): boolean {
const validTransitions = this.getValidTransitions();
return validTransitions.includes(state);
}
transitionTo(state: TaskFlowState): boolean {
if (this.canTransitionTo(state)) {
const oldState = this.currentState;
this.currentState = state;
this.context.addEvent({
type: "state-transition",
workflow: "TaskFlow",
from: oldState,
to: state,
timestamp: new Date()
});
return true;
}
return false;
}
getCurrentState(): TaskFlowState {
return this.currentState;
}
private getValidTransitions(): TaskFlowState[] {
switch (this.currentState) {
case TaskFlowState.Todo:
return [TaskFlowState.InProgress];
case TaskFlowState.InProgress:
return [TaskFlowState.Done];
case TaskFlowState.Done:
return [TaskFlowState.Archived];
default:
return [];
}
}
}
Python Output
from enum import Enum
from typing import List, Optional
from datetime import datetime
class TaskFlowState(Enum):
TODO = "Todo"
IN_PROGRESS = "InProgress"
DONE = "Done"
ARCHIVED = "Archived"
class TaskFlowWorkflow:
def __init__(
self,
initial_state: Optional[TaskFlowState] = None,
context: Optional[SpectralContext] = None
):
# Uses the initial state from the workflow definition
self.current_state = initial_state or TaskFlowState.TODO
self.context = context or SpectralContext()
def can_transition_to(self, state: TaskFlowState) -> bool:
valid_transitions = self._get_valid_transitions()
return state in valid_transitions
def transition_to(self, state: TaskFlowState) -> bool:
if self.can_transition_to(state):
old_state = self.current_state
self.current_state = state
self.context.add_event({
"type": "state-transition",
"workflow": "TaskFlow",
"from": old_state.value,
"to": state.value,
"timestamp": datetime.now()
})
return True
return False
def get_current_state(self) -> TaskFlowState:
return self.current_state
def _get_valid_transitions(self) -> List[TaskFlowState]:
transitions = {
TaskFlowState.TODO: [TaskFlowState.IN_PROGRESS],
TaskFlowState.IN_PROGRESS: [TaskFlowState.DONE],
TaskFlowState.DONE: [TaskFlowState.ARCHIVED]
}
return transitions.get(self.current_state, [])
Workflow with Types
Combine workflows with type definitions for complete business logic:
enum OrderStatus {
Pending
Processing
Shipped
Delivered
Cancelled
}
type Order {
id: string
customerId: string
status: OrderStatus
items: OrderItem[]
total: number
}
type OrderItem {
productId: string
quantity: number
price: number
}
workflow OrderFlow {
initial Pending
Pending -> Processing
Pending -> Cancelled
Processing -> Shipped
Processing -> Cancelled
Shipped -> Delivered
}
visitor OrderManager {
can create_order {
created_order {
can view_order
can cancel_order {
cancelled_order {
can view_order
}
}
}
}
can process_order {
processing_order {
can ship_order
can cancel_order
}
}
}
✨ Edit in StudioBest Practices
1. Use Descriptive State Names
workflow PaymentFlow {
initial AwaitingPayment // ✓ Good: Clear what this state means
AwaitingPayment -> Processing
}
// Avoid:
workflow PaymentFlow {
initial State1 // ✗ Bad: Not descriptive
State1 -> State2
}
✨ Edit in Studio2. Set Initial States Explicitly
workflow TaskFlow {
initial Todo // ✓ Good: Explicit initial state
Todo -> InProgress
}
✨ Edit in Studio3. Model All Valid Transitions
workflow OrderFlow {
initial Pending
Pending -> Processing
Pending -> Cancelled // ✓ Good: All valid paths from each state
Processing -> Shipped
Processing -> Cancelled
}
✨ Edit in Studio4. Keep Workflows Focused
Break large workflows into smaller, focused workflows:
// Instead of one massive workflow:
workflow OrderAndShipping {
// 20+ states...
}
// Break it down:
workflow OrderFlow {
initial Pending
Pending -> Processing
Processing -> Ready
}
workflow ShippingFlow {
initial Preparing
Preparing -> Shipped
Shipped -> Delivered
}
✨ Edit in Studio5. Align Workflows with Enums
enum TaskStatus {
Todo
InProgress
Done
Archived
}
workflow TaskFlow {
initial Todo // ✓ Good: States match enum values
Todo -> InProgress
InProgress -> Done
Done -> Archived
}
✨ Edit in StudioExamples
Blog Publishing
enum PostStatus {
Draft
Review
Scheduled
Published
Archived
}
type Post {
id: string
title: string
content: string
status: PostStatus
author: User
publishDate: datetime
}
workflow PostFlow {
initial Draft
Draft -> Review
Review -> Draft // Send back for changes
Review -> Scheduled
Scheduled -> Published
Published -> Archived
Archived -> Draft // Revive old content
}
✨ Edit in StudioTask Management
enum Priority {
Low
Medium
High
Critical
}
enum TaskStatus {
Todo
InProgress
Blocked
Done
Cancelled
}
type Task {
id: string
title: string
status: TaskStatus
priority: Priority
assignee: User
subtasks: Task[]
}
workflow TaskFlow {
initial Todo
Todo -> InProgress
Todo -> Cancelled
InProgress -> Blocked
InProgress -> Done
InProgress -> Cancelled
Blocked -> InProgress
Blocked -> Cancelled
}
✨ Edit in StudioIncident Management
enum IncidentSeverity {
Low
Medium
High
Critical
}
type Incident {
id: string
title: string
description: string
severity: IncidentSeverity
assignee: User
reportedBy: User
}
workflow IncidentFlow {
initial Reported
Reported -> Triaged
Triaged -> Assigned
Assigned -> InProgress
InProgress -> Resolved
Resolved -> Verified
Verified -> Closed
// Can reopen
Closed -> Reopened
Reopened -> Assigned
// Can escalate
Assigned -> Escalated
Escalated -> Assigned
}
✨ Edit in StudioValidation
Spectral validates:
- ✓ Initial state exists in the workflow
- ✓ All referenced states are defined
- ✓ No duplicate transitions
- ✓ Workflow has at least one state
- ✓ State names are valid identifiers