---
title: "Custom Workflows"
description: "Building custom state machines and workflows for your specific needs"
---

# Custom Workflows

TraceRTM's workflow engine lets you define custom state machines tailored to your organization's processes. This guide covers creating workflows from scratch, defining states, transitions, guards, and automation hooks.

## Workflow Concepts

### Core Components

| Component | Purpose | Example |
|-----------|---------|---------|
| **States** | Possible artifact statuses | `draft`, `review`, `approved` |
| **Transitions** | Allowed state changes | `draft → review` |
| **Guards** | Conditions for transitions | "Must have tests" |
| **Actions** | Side effects on transition | Send notification |
| **Hooks** | External integrations | Webhook, agent trigger |

### State Machine Basics

```
┌─────────┐    submit    ┌─────────┐   approve   ┌──────────┐
│  DRAFT  │ ───────────► │ REVIEW  │ ──────────► │ APPROVED │
└─────────┘              └─────────┘             └──────────┘
                              │
                              │ reject
                              ▼
                         ┌─────────┐
                         │ CHANGES │
                         │REQUESTED│
                         └─────────┘
```

## Creating Custom Workflows

### Basic Workflow Definition

```yaml
# .tracertm/workflows/my_workflow.yaml
name: feature_workflow
description: "Custom workflow for feature artifacts"

# Applies to these artifact types
applies_to:
  - feature
  - enhancement

# State definitions
states:
  - name: draft
    description: "Initial state, being written"
    initial: true
    color: gray

  - name: ready
    description: "Ready for development"
    color: blue

  - name: in_progress
    description: "Being implemented"
    color: yellow

  - name: review
    description: "Code complete, in review"
    color: orange

  - name: done
    description: "Complete and verified"
    color: green
    terminal: true

  - name: blocked
    description: "Cannot proceed"
    color: red

# Transition definitions
transitions:
  - name: submit
    from: draft
    to: ready

  - name: start_work
    from: ready
    to: in_progress

  - name: submit_for_review
    from: in_progress
    to: review

  - name: approve
    from: review
    to: done

  - name: request_changes
    from: review
    to: in_progress

  - name: block
    from: [ready, in_progress]
    to: blocked

  - name: unblock
    from: blocked
    to: ready
```

### Adding Guards

Guards are conditions that must be met before a transition can occur:

```yaml
transitions:
  - name: submit
    from: draft
    to: ready
    guards:
      # Field guards
      - type: field_required
        field: description
        message: "Description is required"

      - type: field_required
        field: acceptance_criteria
        message: "Acceptance criteria required"

      - type: field_min_length
        field: description
        min: 50
        message: "Description must be at least 50 characters"

  - name: submit_for_review
    from: in_progress
    to: review
    guards:
      # Link guards
      - type: link_required
        link_type: realized_by
        target_type: code
        min_count: 1
        message: "Must have code linked"

      - type: link_required
        link_type: tested_by
        target_type: test
        min_count: 1
        message: "Must have at least one test"

      # External guards
      - type: tests_passing
        message: "All linked tests must pass"

  - name: approve
    from: review
    to: done
    guards:
      # Approval guards
      - type: approval_required
        role: tech_lead
        message: "Tech lead approval required"

      - type: approval_required
        role: qa_lead
        message: "QA lead approval required"

      # Coverage guard
      - type: coverage
        target_type: test
        min: 100
        message: "100% test coverage required"
```

### Adding Actions

Actions execute automatically when transitions occur:

```yaml
transitions:
  - name: submit
    from: draft
    to: ready
    actions:
      # Set field values
      - type: set_field
        field: submitted_at
        value: "{{ now }}"

      - type: set_field
        field: submitted_by
        value: "{{ current_user }}"

  - name: start_work
    from: ready
    to: in_progress
    actions:
      # Assign to current user
      - type: set_field
        field: assignee
        value: "{{ current_user }}"

      - type: set_field
        field: started_at
        value: "{{ now }}"

      # Create audit entry
      - type: audit_log
        message: "Work started by {{ current_user }}"

  - name: approve
    from: review
    to: done
    actions:
      # Timestamp
      - type: set_field
        field: completed_at
        value: "{{ now }}"

      # Notification
      - type: notify
        channel: slack
        message: "Feature {{ item.title }} approved!"
        recipients:
          - "{{ item.assignee }}"
          - "{{ item.created_by }}"
```

### Adding Hooks

Hooks integrate with external systems:

```yaml
hooks:
  # On any transition
  on_transition:
    - type: webhook
      url: "https://api.example.com/traceability/events"
      method: POST
      payload:
        event: transition
        item_id: "{{ item.id }}"
        from_state: "{{ from_state }}"
        to_state: "{{ to_state }}"

  # On specific states
  on_enter:
    review:
      - type: webhook
        url: "https://api.example.com/reviews/create"
        payload:
          item_id: "{{ item.id }}"
          type: code_review

      - type: agent
        agent_id: code-review-agent
        task: "Review code for {{ item.id }}"

    done:
      - type: webhook
        url: "https://api.example.com/metrics/feature-complete"

  on_exit:
    blocked:
      - type: notify
        channel: email
        to: "{{ item.assignee }}"
        subject: "Item unblocked: {{ item.title }}"
```

## Advanced Patterns

### Parallel States

Allow artifacts to be in multiple states simultaneously:

```yaml
# Separate concerns into regions
regions:
  development:
    states: [not_started, in_progress, code_complete]
    initial: not_started

  review:
    states: [not_reviewed, in_review, approved, rejected]
    initial: not_reviewed

  testing:
    states: [not_tested, testing, passed, failed]
    initial: not_tested

# Composite terminal state
terminal_condition:
  all:
    - development: code_complete
    - review: approved
    - testing: passed
```

### Conditional Transitions

Different paths based on conditions:

```yaml
transitions:
  - name: auto_route
    from: submitted
    to:
      - state: fast_track
        condition:
          field: priority
          equals: critical

      - state: normal_queue
        condition:
          field: priority
          in: [high, medium]

      - state: backlog
        default: true  # Fallback
```

### Timed Transitions

Automatic transitions after time periods:

```yaml
transitions:
  - name: auto_escalate
    from: review
    to: escalated
    trigger:
      type: timeout
      duration: 48h
      condition:
        field: priority
        equals: critical

  - name: auto_close
    from: resolved
    to: closed
    trigger:
      type: timeout
      duration: 7d
      unless:
        field: reopened
        equals: true
```

### Sub-Workflows

Nested workflows for complex artifacts:

```yaml
# Parent workflow
name: epic_workflow
states:
  - planning
  - in_progress
  - complete

# Child items use sub-workflow
sub_workflows:
  feature:
    workflow: feature_workflow

  story:
    workflow: story_workflow

# Epic completion depends on children
transitions:
  - name: complete
    from: in_progress
    to: complete
    guards:
      - type: children_complete
        child_types: [feature, story]
        message: "All features and stories must be complete"
```

## Programmatic Workflows

### Creating Workflows via API

```python
from tracertm import TraceRTMClient
from tracertm.workflows import Workflow, State, Transition, Guard

client = TraceRTMClient()

# Define workflow programmatically
workflow = Workflow(
    name="custom_review_workflow",
    applies_to=["document", "design"]
)

# Add states
workflow.add_state(State("draft", initial=True))
workflow.add_state(State("review"))
workflow.add_state(State("approved", terminal=True))
workflow.add_state(State("rejected", terminal=True))

# Add transitions with guards
workflow.add_transition(
    Transition(
        name="submit",
        from_state="draft",
        to_state="review",
        guards=[
            Guard.field_required("content"),
            Guard.field_required("reviewer")
        ]
    )
)

workflow.add_transition(
    Transition(
        name="approve",
        from_state="review",
        to_state="approved",
        guards=[
            Guard.approval_required(role="reviewer"),
            Guard.field_equals("review_decision", "approved")
        ]
    )
)

workflow.add_transition(
    Transition(
        name="reject",
        from_state="review",
        to_state="rejected",
        guards=[
            Guard.field_equals("review_decision", "rejected")
        ]
    )
)

# Register workflow
client.register_workflow(workflow)
```

### Custom Guards

```python
from tracertm.workflows import Guard

# Create custom guard function
@Guard.custom("external_approval")
def check_external_approval(item, context):
    """Check if external system has approved."""
    response = requests.get(
        f"https://approval-system.com/check/{item.id}"
    )
    data = response.json()

    if data["approved"]:
        return True, None
    else:
        return False, f"External approval pending: {data['reason']}"

# Use in workflow
transition = Transition(
    name="deploy",
    from_state="approved",
    to_state="deployed",
    guards=[
        Guard.custom("external_approval")
    ]
)
```

### Custom Actions

```python
from tracertm.workflows import Action

@Action.custom("sync_to_jira")
def sync_to_jira(item, transition, context):
    """Sync item status to Jira."""
    jira_key = item.metadata.get("jira_key")
    if jira_key:
        jira_client.transition_issue(
            jira_key,
            transition=map_state_to_jira(transition.to_state)
        )

# Use in workflow
workflow.add_action(
    on_transition="*",  # All transitions
    action=Action.custom("sync_to_jira")
)
```

## Workflow Validation

### Testing Workflows

```python
from tracertm.workflows import WorkflowTester

tester = WorkflowTester(workflow)

# Test valid paths
assert tester.can_transition("draft", "review",
    item={"content": "test", "reviewer": "alice"})

# Test guard failures
result = tester.can_transition("draft", "review",
    item={"content": ""})  # Missing required field
assert not result.allowed
assert "content is required" in result.reason

# Test complete path
path = tester.find_path("draft", "approved")
assert path == ["draft", "review", "approved"]

# Verify no dead ends
assert tester.all_states_reachable()
assert tester.all_terminal_states_reachable()
```

### Workflow Visualization

```bash
# Generate workflow diagram
tracertm workflow visualize --workflow feature_workflow --output workflow.png

# Interactive explorer
tracertm workflow explore --workflow feature_workflow
```

## Migration

### Migrating Items to New Workflow

```python
def migrate_to_new_workflow(old_workflow: str, new_workflow: str):
    """Migrate items from old workflow to new."""

    # Map old states to new states
    state_mapping = {
        "open": "draft",
        "assigned": "in_progress",
        "complete": "done",
        # ...
    }

    items = client.list_items(workflow=old_workflow)

    for item in items:
        new_state = state_mapping.get(item.status, "draft")

        client.update_item(
            item.id,
            workflow=new_workflow,
            status=new_state,
            metadata={
                **item.metadata,
                "migrated_from": old_workflow,
                "original_status": item.status
            }
        )
```

## Best Practices

### 1. Keep It Simple

```yaml
# Good: Clear, minimal states
states: [draft, review, approved]

# Bad: Too many states
states: [draft, draft_review, pending_review, in_review,
         review_complete, pending_approval, approved,
         approved_pending_deploy, deployed]
```

### 2. Document States Clearly

```yaml
states:
  - name: review
    description: |
      Code is complete and submitted for review.

      Entry criteria:
      - All tests passing
      - Code reviewed by author

      Exit criteria:
      - Peer review approved
      - QA sign-off
```

### 3. Use Meaningful Transition Names

```yaml
# Good: Action-oriented names
transitions:
  - name: submit_for_review
  - name: approve
  - name: request_changes

# Bad: State-oriented names
transitions:
  - name: draft_to_review
  - name: review_to_approved
```

### 4. Fail Gracefully

```yaml
# Provide escape hatches
transitions:
  - name: cancel
    from: [draft, ready, in_progress, review]
    to: cancelled
    guards:
      - type: role_required
        role: [admin, project_manager]

  - name: reopen
    from: [done, cancelled]
    to: draft
    guards:
      - type: approval_required
        role: admin
```

## Related Topics

- [Agile Workflows](/docs/wiki/concepts/workflows/agile) - Agile patterns
- [Waterfall Workflows](/docs/wiki/concepts/workflows/waterfall) - Phase-gate patterns
- [Workflow Automation](/docs/wiki/concepts/workflows/automation) - Automating transitions
- [Agent Coordination](/docs/wiki/concepts/agent-coordination) - Agent-driven workflows

