OxagenDocs
Specs & Plans

Playbook Designer

Archived spec & plan — status: not started (audited 2026-07-03).

Status: Not started — verified against the codebase on 2026-07-03 by an automated audit.

The Playbook Designer spec is a comprehensive product document outlining a visual workflow editor with YAML export/import, ontology integration, and marketplace features. While the foundational playbook database schema (9 tables) and Inngest execution infrastructure exist, none of the spec's core designer deliverables have been implemented. No playbook-specific capability contracts, API routes, MCP tools, UI components, YAML serialization logic, or CLI commands are present. The spec remains in draft status with no implementation work started.

Implementation evidence

  • packages/database/src/schema/workflow.ts - 9-table playbook schema (playbooks, versions, steps, edges, triggers, runs, step_runs, events, approvals) as foundational infrastructure
  • packages/inngest-functions/src/functions/playbook.run.execute.ts - Inngest execution engine for running playbooks
  • packages/inngest-functions/src/functions/playbook.trigger.match.ts - Trigger matching logic
  • docs/specs/playbook-designer/SPEC.md - Complete spec document (draft status, created 2026-06-16)
  • apps/docs/content/docs/specs-and-plans/playbook-designer.mdx - Archived spec in docs (marked unverified 2026-07-03)

Known gaps at time of archive

  • Playbook capability contracts (playbook.list, playbook.get, playbook.create, playbook.update, playbook.delete, version, step, edge, run, approval operations)
  • API routes for /v1/playbooks/* endpoints
  • MCP tools for playbook operations
  • Visual designer UI components (PlaybookDesignerPage, React Flow canvas, StepPalette, PropertyPanel, VersionTimeline, TriggerConfigPanel, Minimap)
  • YAML schema validation and serialization code (PlaybookYamlSchema, type definitions, serializers)
  • Zustand designer store and state management
  • Database tables: playbook_parameters, playbook_canvas_state, playbook_marketplace_listings
  • Additional database columns (display_config, notes, yaml_source_path, last_synced_at, sync_direction)
  • Seed playbooks directory (.oxagen/playbooks/)
  • CLI commands (oxagen playbook push/pull)
  • React Flow dependency and canvas rendering infrastructure

Source documents (archived verbatim below)

  • docs/specs/playbook-designer/SPEC.md

Spec — SPEC.md

Playbook Designer — Product & Engineering Spec

Status: Draft
Author: Product & Engineering
Created: 2026-06-16
Target Release: v0.5.0
Inspired by: cc-wf-studio visual workflow editor


1. Executive Summary

The Playbook Designer is a visual, web-native workflow editor embedded in the Oxagen application that allows users to author, version, test, and deploy automation playbooks. Unlike the inspiration project (cc-wf-studio, a VSCode extension that exports Markdown for AI coding agents), our designer is a server-rendered, multi-tenant, enterprise-grade workflow builder that:

  1. Stores playbooks as portable YAML files (trackable in git, shippable as seed content)
  2. Persists the canonical graph in Postgres (immutable versions, RLS-scoped)
  3. Leverages the Ontology Knowledge Graph (Neo4j) to inject entity context into steps
  4. Provides SOC 2-compliant audit via hash-chained event spine
  5. Supports a Marketplace for sharing playbooks across organizations

This document covers the product vision, data model enhancements, YAML format specification, API surface, UI architecture, and phased delivery plan.


2. Problem Statement

Current State

  • 9-table Drizzle schema exists (workflow pgSchema) with steps, edges, triggers, runs, events
  • Inngest execution engine handles tool/agent/prompt/condition/webhook step types
  • Hash-chained audit event spine (SOC 2 ready)
  • No API routes wired to the playbook tables
  • No visual builder — UI page says "coming soon"
  • No YAML portability — playbooks are database-only, not trackable in source control
  • No ontology integration — steps cannot query the knowledge graph for context

User Pain Points

PersonaPain
Platform EngineerCannot version playbooks in git alongside IaC
SOC 2 AuditorNo visual diff of playbook changes between versions
Solutions ArchitectCannot share proven playbooks across customer deployments
AI OperatorCannot inject knowledge graph context (entity properties) into step prompts
Security LeadNo approval-gate visibility before playbook goes live

Success Criteria

  • Users can visually design playbooks with drag-and-drop in the web app
  • Playbooks export to / import from a well-specified YAML format
  • Seed playbooks ship in the repository and auto-provision on workspace creation
  • Every published version is immutable with a SHA-256 graph hash
  • Steps can reference ontology entities and inject their properties at runtime
  • Approval workflows pause execution and notify designated reviewers

3. Architecture Overview

flowchart TD
    subgraph "Web App (apps/app)"
        UI["Playbook Designer UI\nReact Flow + Property Panel"]
        API_CLIENT["tRPC / Server Actions"]
    end

    subgraph "API Layer (apps/api)"
        ROUTES["Hono Routes\n/v1/playbooks/*"]
        KERNEL["kernel.invoke()"]
    end

    subgraph "Kernel Capabilities"
        PB_CAPS["playbook.* contracts\n(CRUD, publish, run, export)"]
    end

    subgraph "Storage"
        PG["PostgreSQL\nworkflow schema\n9 tables"]
        NEO["Neo4j\nOntology graph\n(context injection)"]
        CH["ClickHouse\nAudit events\n(hash chain stream)"]
    end

    subgraph "Execution"
        INN["Inngest\nplaybook.run.execute\nplaybook.trigger.match"]
    end

    subgraph "Portability"
        YAML["YAML Files\n.oxagen/playbooks/*.yaml\n(git-tracked seeds)"]
    end

    UI --> API_CLIENT
    API_CLIENT --> ROUTES
    ROUTES --> KERNEL
    KERNEL --> PB_CAPS
    PB_CAPS --> PG
    PB_CAPS --> NEO
    PB_CAPS --> CH
    PB_CAPS --> INN
    PB_CAPS <--> YAML

4. YAML Playbook Format Specification

4.1 Design Principles

PrincipleRationale
Human-readable YAMLEngineers can review playbooks in PRs without specialized tooling
Single-file self-containedOne .yaml = one playbook (no cross-file references for portability)
Deterministic serializationCanonical key order enables meaningful git diffs
Schema-versionedschemaVersion field allows non-breaking evolution
Position-optionalCanvas positions are metadata; execution semantics are edge-based

4.2 File Location Convention

.oxagen/
  playbooks/
    monthly-kg-audit.yaml        # seed playbook (shipped to customers)
    new-source-onboarding.yaml
    billing-anomaly-check.yaml
  playbooks.lock                 # SHA-256 manifest of deployed versions

4.3 YAML Schema (v1.0.0)

# .oxagen/playbooks/monthly-kg-audit.yaml
schemaVersion: "1.0.0"

metadata:
  name: Monthly Knowledge Graph Audit
  slug: monthly-kg-audit
  description: >
    Validates entity freshness, removes stale nodes older than 90 days,
    and generates a reconciliation report.
  version: "1.2.0"
  tags: [knowledge-graph, maintenance]
  visibility: workspace          # private | workspace | organization | marketplace
  author: platform-team
  requiresApproval: true

parameters:
  staleness_days:
    type: integer
    default: 90
    description: Days after which an entity is considered stale
    validation:
      minimum: 7
      maximum: 365
  report_channel:
    type: string
    default: "#kg-alerts"
    description: Slack channel for the reconciliation report

triggers:
  - type: schedule
    config:
      cron: "0 9 1 * *"        # First of month, 09:00 UTC
  - type: event
    config:
      entityType: knowledge_node
      eventType: node.stale_detected
      propertyConditions:
        - property: days_since_update
          operator: gt
          toValue: "{{staleness_days}}"

steps:
  - key: validate_freshness
    name: Validate Entity Freshness
    type: tool
    config:
      capability: ontology.entity.audit
      input:
        staleness_threshold: "{{staleness_days}}"
        workspace_id: "{{context.workspaceId}}"
    position: { x: 100, y: 100 }

  - key: check_stale_count
    name: Check Stale Count
    type: condition
    config:
      propertyConditions:
        - property: stale_count
          operator: gt
          toValue: 0
    position: { x: 300, y: 100 }

  - key: remove_stale_nodes
    name: Remove Stale Nodes
    type: tool
    config:
      capability: ontology.entity.bulk_archive
      input:
        entity_ids: "{{steps.validate_freshness.output.stale_entity_ids}}"
    exitOnError: true
    requiresApproval: true
    position: { x: 500, y: 50 }

  - key: generate_report
    name: Generate Reconciliation Report
    type: agent
    config:
      prompt: >
        Summarize the knowledge graph audit results.
        {{steps.validate_freshness.output.summary}}
        Stale nodes archived: {{steps.remove_stale_nodes.output.archived_count}}
      model: sonnet
    position: { x: 500, y: 200 }

  - key: notify_channel
    name: Notify Slack Channel
    type: webhook
    config:
      url: "{{secrets.SLACK_WEBHOOK_URL}}"
      method: POST
      headers:
        Content-Type: application/json
      body: |
        {
          "channel": "{{report_channel}}",
          "text": "{{steps.generate_report.output}}"
        }
    position: { x: 700, y: 100 }

edges:
  - from: validate_freshness
    to: check_stale_count
    type: default

  - from: check_stale_count
    to: remove_stale_nodes
    type: default
    condition: { passed: true }

  - from: check_stale_count
    to: generate_report
    type: conditional
    condition: { passed: false }

  - from: remove_stale_nodes
    to: generate_report
    type: default

  - from: generate_report
    to: notify_channel
    type: default

4.4 Step Types Reference

Step TypeDescriptionConfig Shape
toolInvokes a capability via the kernel{ capability, input }
agentSingle-shot LLM completion{ prompt, model?, agentSlug? }
promptTemplate interpolation + LLM{ prompt, model?, variables? }
conditionBoolean gate on properties{ propertyConditions[] }
webhookHTTPS outbound call{ url, method, headers?, body? }
approvalHuman approval gate{ assignee?, role?, expiresIn? }
human_inputPause for user data entry{ formSchema, assignee? }
transformJQ/JSONata data transformation{ expression, inputPath }
loopIterate over array output{ over, stepKeys[], maxIterations }
parallelFan-out concurrent execution{ stepKeys[], joinStrategy }
delayTime-based pause{ duration, unit }
sub_playbookInvoke another playbook{ playbookSlug, input }
knowledge_searchQuery ontology graph{ query, entityType?, limit? }
code_executionSandboxed script{ runtime, code, timeout? }

4.5 Template Interpolation

Playbook YAML supports Mustache-style {{...}} interpolation:

ExpressionResolves To
{{paramName}}Playbook parameter value
{{context.orgId}}Runtime context field
{{context.workspaceId}}Runtime context field
{{context.userId}}Triggering user (null for event triggers)
{{steps.<key>.output}}Output of a previously executed step
{{steps.<key>.output.<field>}}Specific field from step output
{{secrets.<KEY>}}Workspace secret (resolved at runtime, never persisted)
{{ontology.<entityType>.<property>}}Ontology node property (v2)
{{trigger.payload.<field>}}Trigger event payload field

4.6 Portability Contract

The YAML format is the interchange format. It supports:

  1. Export: playbook.export capability serializes a DB playbook version to YAML
  2. Import: playbook.import capability parses YAML, validates, and creates a draft version
  3. Seed: On workspace creation, seed-playbooks Inngest job reads .oxagen/playbooks/*.yaml
  4. CLI: oxagen playbook push/pull syncs between filesystem and workspace
  5. MCP: playbook.export / playbook.import exposed as MCP tools

5. Data Model Enhancements

5.1 Existing Schema (No Changes Required)

The current 9-table schema in packages/database/src/schema/workflow.ts is well-designed and requires no structural changes for the designer. Key points:

  • playbook_steps.positionX / positionY already support canvas layout
  • playbook_steps.config JSONB holds typed step configuration
  • playbook_edges with edgeType and condition support branching
  • playbook_versions are immutable with graphHash for integrity
  • playbook_events provides hash-chained audit spine

5.2 New Table: playbook_parameters

-- Formal parameter declarations (runtime inputs to the playbook)
CREATE TABLE workflow.playbook_parameters (
  id              UUID PRIMARY KEY DEFAULT uuidv7(),
  playbook_version_id UUID NOT NULL REFERENCES workflow.playbook_versions(id),
  param_key       CITEXT NOT NULL,
  param_type      TEXT NOT NULL CHECK (param_type IN (
    'string','integer','number','boolean','array','object','secret'
  )),
  description     TEXT,
  default_value   JSONB,
  validation      JSONB,         -- { minimum, maximum, pattern, enum, ... }
  is_required     BOOLEAN NOT NULL DEFAULT true,
  display_order   INTEGER NOT NULL DEFAULT 0,
  created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  UNIQUE (playbook_version_id, param_key)
);

5.3 New Table: playbook_canvas_state

-- Ephemeral designer state (viewport, selection, draft edits)
-- This is NOT versioned — it's per-user working state
CREATE TABLE workflow.playbook_canvas_state (
  id              UUID PRIMARY KEY DEFAULT uuidv7(),
  org_id          UUID NOT NULL,
  workspace_id    UUID NOT NULL,
  playbook_id     UUID NOT NULL REFERENCES workflow.playbooks(id),
  user_id         UUID NOT NULL,
  viewport        JSONB NOT NULL DEFAULT '{"x":0,"y":0,"zoom":1}',
  selected_nodes  JSONB NOT NULL DEFAULT '[]',
  panel_state     JSONB NOT NULL DEFAULT '{}',
  updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),

  UNIQUE (playbook_id, user_id)
);

5.4 New Table: playbook_marketplace_listings

-- Published playbooks available for cross-org installation
CREATE TABLE workflow.playbook_marketplace_listings (
  id              UUID PRIMARY KEY DEFAULT uuidv7(),
  org_id          UUID NOT NULL,
  playbook_id     UUID NOT NULL REFERENCES workflow.playbooks(id),
  version_id      UUID NOT NULL REFERENCES workflow.playbook_versions(id),
  title           TEXT NOT NULL,
  description     TEXT,
  category        TEXT NOT NULL,
  tags            JSONB NOT NULL DEFAULT '[]',
  install_count   INTEGER NOT NULL DEFAULT 0,
  is_verified     BOOLEAN NOT NULL DEFAULT false,
  is_featured     BOOLEAN NOT NULL DEFAULT false,
  published_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  unpublished_at  TIMESTAMPTZ,

  UNIQUE (playbook_id, version_id)
);
CREATE INDEX idx_marketplace_category ON workflow.playbook_marketplace_listings(category)
  WHERE unpublished_at IS NULL;

5.5 New Column Additions

-- Add to playbook_steps for enhanced designer support
ALTER TABLE workflow.playbook_steps
  ADD COLUMN display_config JSONB DEFAULT '{}',  -- { color, icon, width, collapsed }
  ADD COLUMN notes TEXT;                         -- Designer-only annotation

-- Add to playbooks for YAML sync tracking
ALTER TABLE workflow.playbooks
  ADD COLUMN yaml_source_path TEXT,              -- e.g. ".oxagen/playbooks/monthly-kg-audit.yaml"
  ADD COLUMN last_synced_at TIMESTAMPTZ,
  ADD COLUMN sync_direction TEXT CHECK (sync_direction IN ('push', 'pull', 'bidirectional'));

6. Capability Contracts (API Surface)

All playbook operations are kernel capabilities — exposed identically across API, MCP, App, and CLI surfaces.

6.1 CRUD Capabilities

CapabilitySurfaceDescription
playbook.listallList playbooks (paginated, filterable)
playbook.getallGet playbook with active version details
playbook.createallCreate new playbook (draft status)
playbook.updateallUpdate playbook metadata
playbook.deleteallSoft-delete playbook
playbook.archiveallMove to archived status

6.2 Version & Graph Capabilities

CapabilitySurfaceDescription
playbook.version.createallCreate new draft version (copies graph from active)
playbook.version.getallGet version with full graph (steps + edges)
playbook.version.publishallPublish draft → computes graphHash, immutable
playbook.version.diffallDiff two versions (added/removed/modified steps)
playbook.version.rollbackallSet active version to a previous published version

6.3 Graph Editing Capabilities (Designer)

CapabilitySurfaceDescription
playbook.step.createapp, apiAdd step to draft version
playbook.step.updateapp, apiUpdate step config/position
playbook.step.deleteapp, apiRemove step and connected edges
playbook.step.reorderapp, apiBulk update positions
playbook.edge.createapp, apiConnect two steps
playbook.edge.deleteapp, apiRemove edge
playbook.edge.updateapp, apiUpdate edge condition

6.4 Execution Capabilities

CapabilitySurfaceDescription
playbook.run.startallManually trigger a playbook run
playbook.run.getallGet run status + step run details
playbook.run.listallList runs (filterable by status)
playbook.run.cancelallCancel a running/paused run
playbook.run.resumeallResume after approval granted
playbook.approval.resolveallApprove or deny a pending approval

6.5 Portability Capabilities

CapabilitySurfaceDescription
playbook.exportallExport playbook version as YAML string
playbook.importallImport YAML → create playbook + draft version
playbook.validateallValidate YAML without persisting
playbook.seedapiBulk-import from .oxagen/playbooks/ directory

6.6 Ontology Integration Capabilities

CapabilitySurfaceDescription
playbook.context.resolverunnerResolve {{ontology.*}} templates at runtime
playbook.context.previewapp, apiPreview resolved context for a step (dry-run)

7. UI Architecture — Playbook Designer

7.1 Component Hierarchy

graph TD
    PAGE["PlaybookDesignerPage"]
    TOOLBAR["DesignerToolbar\n(save, publish, run, export, undo/redo)"]
    CANVAS["DesignerCanvas\n(React Flow)"]
    PALETTE["StepPalette\n(draggable step types)"]
    PROPS["PropertyPanel\n(selected node config)"]
    MINIMAP["Minimap"]
    RUNS["RunHistoryPanel"]
    VERSIONS["VersionTimeline"]
    TRIGGERS["TriggerConfigPanel"]

    PAGE --> TOOLBAR
    PAGE --> CANVAS
    PAGE --> PALETTE
    PAGE --> PROPS
    CANVAS --> MINIMAP
    PAGE --> RUNS
    PAGE --> VERSIONS
    PAGE --> TRIGGERS

7.2 Technology Choices

ConcernChoiceRationale
CanvasReact Flow v12Same as cc-wf-studio; proven for workflow UIs
State ManagementZustandLightweight, works with React Flow's node/edge state
Undo/RedoCustom command stackPlaybook-specific operations (add step, move, connect)
Property FormsReact Hook Form + ZodMatches existing oxagen patterns
Drag & DropReact Flow's built-in + dnd-kit for paletteNative feel
Layout AlgorithmDagre (auto-layout)For initial import / "tidy" operation
SerializationYAML via yaml npm packageRound-trip fidelity for playbook files
Real-time SyncOptimistic updates + server confirmNo WebSocket needed for single-user editing

7.3 Node Types (Visual)

Each step type renders as a distinct node on the canvas:

Node TypeShapeColorIcon
ToolRectangleBlueWrench
AgentRectanglePurpleBot
PromptRectangleAmberMessageSquare
ConditionDiamondGrayGitBranch
WebhookRectangleGreenGlobe
ApprovalHexagonOrangeShieldCheck
Human InputHexagonTealUserCheck
TransformRectangleSlateCode
LoopRounded rectIndigoRepeat
ParallelRounded rectCyanGitFork
DelayPillGrayClock
Sub-playbookDouble-border rectPinkBookCopy
Knowledge SearchRectangleEmeraldSearch
Code ExecutionRectangleDarkTerminal

7.4 Property Panel

The property panel renders contextually based on selected node type:

┌──────────────────────────────────┐
│ Step: Remove Stale Nodes         │
│ Type: Tool                       │
├──────────────────────────────────┤
│ Capability: ontology.entity.*    │ ← Autocomplete from registry
│ Input Mapping:                   │
│   entity_ids: {{steps.validate   │ ← Expression editor with
│     _freshness.output.stale_...}}│   autocomplete for step refs
├──────────────────────────────────┤
│ ☑ Exit on Error                  │
│ ☑ Requires Approval              │
│ Timeout: 30s                     │
│ Retry: { maxAttempts: 3 }        │
├──────────────────────────────────┤
│ Notes: This step archives nodes  │ ← Designer annotation
│ that haven't been updated...     │
└──────────────────────────────────┘

7.5 Designer Features Matrix

FeaturePhase 1Phase 2Phase 3
Drag-and-drop step creation
Edge drawing (click-to-connect)
Property panel editing
Undo / Redo
Auto-layout (Dagre)
Step palette with search
Version timeline sidebar
YAML export / import
Run playbook from designer
Live run visualization (step highlighting)
Version diff (side-by-side)
Approval gate configuration
Ontology context picker
Template expression autocomplete
Collaborative editing (presence)
AI-assisted playbook generation
Marketplace publish / install
Playbook testing / dry-run mode
Custom step type plugins

8. Ontology Knowledge Graph Integration

8.1 Context Injection Model

The killer differentiator: playbooks can query the knowledge graph at runtime to inject entity context into step configurations. This is what made v1 a hit.

sequenceDiagram
    participant Runner as Inngest Runner
    participant PG as PostgreSQL
    participant Neo as Neo4j
    participant Step as Step Executor

    Runner->>PG: Load step config
    Runner->>Runner: Detect {{ontology.*}} templates
    Runner->>Neo: MATCH (n:EntityType) WHERE n.property = value RETURN n
    Neo-->>Runner: Entity properties
    Runner->>Runner: Interpolate templates
    Runner->>Step: Execute with resolved config

8.2 Ontology Template Syntax

# Query a specific entity by natural key
input:
  customer_name: "{{ontology.customer[natural_key='acme-corp'].name}}"
  contract_value: "{{ontology.contract[customer='acme-corp'].annual_value}}"

# Query entities matching conditions (returns array)
input:
  stale_entities: "{{ontology.knowledge_node[days_since_update > staleness_days]}}"

# Traverse relationships
input:
  owner_email: "{{ontology.service[name='auth-api'].owned_by.email}}"

8.3 Knowledge Search Step Type

A dedicated step type for querying the ontology:

- key: find_related_services
  name: Find Related Services
  type: knowledge_search
  config:
    query: |
      MATCH (s:Service)-[:DEPENDS_ON]->(d:Service)
      WHERE s.name = $service_name
      RETURN d.name, d.health_status
    parameters:
      service_name: "{{trigger.payload.service_name}}"
    limit: 50
    outputMapping:
      dependencies: result.rows
      unhealthy_count: "result.rows | filter(.health_status != 'healthy') | length"

8.4 Designer Integration

The property panel provides an Ontology Context Picker:

  1. User clicks "Insert Ontology Reference" in the expression editor
  2. Picker shows available entity types from the workspace's ontology schema
  3. User selects entity type → sees available properties
  4. User can add filter conditions (property + operator + value)
  5. Expression is inserted as {{ontology.<type>[<filter>].<property>}}

This is backed by the ontology.schema.describe capability (existing) which returns the node types and property keys available in the workspace's graph.


9. Enterprise & SOC 2 Controls

9.1 Audit Trail

Every playbook mutation is recorded in the hash-chained event spine:

Event TypeTrigger
playbook.createdNew playbook created
playbook.version.publishedVersion published (includes graphHash)
playbook.version.rolled_backActive version changed
playbook.run.startedRun initiated (manual/event/schedule)
playbook.step.approval_requestedApproval gate reached
playbook.step.approval_resolvedApproval granted/denied
playbook.run.completedRun finished successfully
playbook.run.failedRun failed with error
playbook.exportedPlaybook exported as YAML
playbook.importedPlaybook imported from YAML
playbook.marketplace.publishedListed on marketplace

9.2 Version Integrity

graphHash = SHA-256(
  canonical_json_sort(steps[].{stepKey, stepType, config}) +
  canonical_json_sort(edges[].{sourceStepKey, targetStepKey, edgeType, condition})
)
  • Computed at publish time, stored on playbook_versions.graph_hash
  • Verified before every run execution (detect tampering)
  • Included in ClickHouse audit events for external verification

9.3 Approval Workflows

stateDiagram-v2
    [*] --> Running: playbook.run.start
    Running --> WaitingApproval: step.requiresApproval = true
    WaitingApproval --> Running: approval.resolve(approved)
    WaitingApproval --> Cancelled: approval.resolve(denied)
    WaitingApproval --> Expired: approval.expiresAt reached
    Running --> Completed: all steps done
    Running --> Failed: step error + exitOnError
    Expired --> Cancelled: auto-cancel
  • Approval requests are routable to specific users or IAM roles
  • Configurable expiry (default 7 days, minimum 1 hour)
  • Denial triggers a run_cancelled event with reason
  • Emergency override requires playbook.approval.override permission

9.4 Access Control (IAM)

PermissionGrants
playbook.readView playbooks and run history
playbook.editCreate/modify draft versions
playbook.publishPublish versions (separate from edit)
playbook.runManually trigger runs
playbook.run.cancelCancel running playbooks
playbook.approval.resolveApprove/deny approval requests
playbook.approval.overrideBypass approval gates (emergency)
playbook.deleteSoft-delete playbooks
playbook.exportExport as YAML
playbook.importImport from YAML
playbook.marketplace.publishPublish to marketplace

9.5 Secrets Handling

  • {{secrets.*}} references are resolved at runtime from the workspace secret store
  • Secret values are never stored in playbook YAML or database config
  • Secret references in YAML use the key name only: {{secrets.SLACK_WEBHOOK_URL}}
  • The designer's property panel shows secret references as masked values
  • Audit events log that a secret was accessed but never the value

10. Seed Playbooks & Marketplace

10.1 Seed Strategy

New workspaces receive a curated set of playbooks from .oxagen/playbooks/:

.oxagen/playbooks/
  monthly-kg-audit.yaml
  new-source-onboarding.yaml
  stale-entity-cleanup.yaml
  billing-reconciliation.yaml
  competitor-monitoring.yaml
  security-posture-check.yaml
  data-quality-report.yaml
  connector-health-check.yaml

These are imported during workspace provisioning via the playbook.seed capability triggered by the workspace.created Inngest event.

10.2 Seed Lifecycle

  1. Seed playbooks are committed to the repository (reviewed like code)
  2. On deploy, a migration job detects new/updated seeds by comparing SHA-256
  3. Updated seeds create new draft versions (never auto-publish to avoid breaking running automations)
  4. Platform team reviews and publishes via the designer
  5. playbooks.lock tracks deployed seed versions for drift detection

10.3 Marketplace (Phase 3)

FeatureDescription
PublishOrg publishes a verified playbook version to the marketplace
BrowseUsers browse by category, tags, install count
InstallOne-click install creates a copy in the target workspace
ForkInstalled playbooks are independent copies (no upstream sync)
VerifyOxagen team reviews and badges verified playbooks
RevenueFuture: paid marketplace listings with rev-share

11. Improvements Over cc-wf-studio

cc-wf-studioOxagen Playbook DesignerWhy Better
VSCode-only (webview)Web-native (any browser)No IDE dependency; accessible to non-engineers
JSON workflow filesYAML with formal schemaHuman-readable, git-diff friendly, PR reviewable
Exports to Markdown for AI agentsExecutes directly via InngestReal execution engine with retries, approval, audit
No persistence layerMulti-tenant Postgres + RLSEnterprise-grade, versioned, access-controlled
No audit trailSHA-256 hash-chained eventsSOC 2 compliant, tamper-evident
No knowledge contextOntology graph integrationSteps can query entity relationships at runtime
Single-userMulti-user with IAMRole-based access, approval routing
No marketplaceMarketplace + seed playbooksShare proven automation across organizations
File-based samplesDatabase seeds with lock trackingDeterministic provisioning, drift detection
Manual parameter config onlyTemplate expressions + autocomplete{{steps.*.output}} references with validation
No execution visibilityLive run visualizationWatch step-by-step execution on the canvas
No testing modeDry-run with mocked contextValidate playbooks before publishing
No version diffingVisual graph diffSee exactly what changed between versions
No triggers built-inEvent, schedule, and API triggersNative trigger configuration in the designer
Prompt node only14 step typesRich step vocabulary for enterprise automation
No secrets management{{secrets.*}} with vault integrationNever expose credentials in config
No sub-workflow nestingsub_playbook step typeCompose complex automations from primitives
No conditional branching at runtimeCondition steps with property evaluationData-driven flow control

12. TypeScript Interfaces

12.1 YAML Parse Target

// packages/oxagen/src/contracts/playbook/yaml-schema.ts

import { z } from "zod";

export const PlaybookParameterSchema = z.object({
  type: z.enum(["string", "integer", "number", "boolean", "array", "object", "secret"]),
  default: z.unknown().optional(),
  description: z.string().optional(),
  validation: z.object({
    minimum: z.number().optional(),
    maximum: z.number().optional(),
    minLength: z.number().optional(),
    maxLength: z.number().optional(),
    pattern: z.string().optional(),
    enum: z.array(z.union([z.string(), z.number()])).optional(),
  }).optional(),
});

export const TriggerConfigSchema = z.discriminatedUnion("type", [
  z.object({
    type: z.literal("schedule"),
    config: z.object({ cron: z.string() }),
  }),
  z.object({
    type: z.literal("event"),
    config: z.object({
      entityType: z.string(),
      eventType: z.string().optional(),
      propertyConditions: z.array(z.object({
        property: z.string(),
        operator: z.enum(["eq", "gt", "lt", "changed"]),
        toValue: z.union([z.string(), z.number()]).optional(),
      })).optional(),
    }),
  }),
  z.object({
    type: z.literal("api"),
    config: z.object({
      rateLimit: z.object({ maxPerHour: z.number() }).optional(),
    }).optional(),
  }),
]);

export const StepSchema = z.object({
  key: z.string().regex(/^[a-z][a-z0-9_]*$/),
  name: z.string().min(1).max(100),
  type: z.enum([
    "tool", "agent", "prompt", "condition", "webhook", "approval",
    "human_input", "transform", "loop", "parallel", "delay",
    "sub_playbook", "knowledge_search", "code_execution",
  ]),
  config: z.record(z.unknown()),
  position: z.object({ x: z.number(), y: z.number() }).optional(),
  isAsync: z.boolean().optional().default(false),
  exitOnError: z.boolean().optional().default(true),
  timeoutSeconds: z.number().optional(),
  retryPolicy: z.object({
    maxAttempts: z.number().min(1).max(10),
    backoffMs: z.number().optional(),
  }).optional(),
  requiresApproval: z.boolean().optional().default(false),
  notes: z.string().optional(),
});

export const EdgeSchema = z.object({
  from: z.string(),
  to: z.string(),
  type: z.enum(["default", "conditional", "on_error", "loop_back", "parallel"]),
  condition: z.record(z.unknown()).optional(),
  priority: z.number().optional().default(0),
});

export const PlaybookYamlSchema = z.object({
  schemaVersion: z.string().regex(/^\d+\.\d+\.\d+$/),
  metadata: z.object({
    name: z.string().min(1).max(100),
    slug: z.string().regex(/^[a-z0-9]+(-[a-z0-9]+)*$/),
    description: z.string().optional(),
    version: z.string().regex(/^\d+\.\d+\.\d+$/),
    tags: z.array(z.string()).optional().default([]),
    visibility: z.enum(["private", "workspace", "organization", "marketplace"]).default("workspace"),
    author: z.string().optional(),
    requiresApproval: z.boolean().optional().default(false),
  }),
  parameters: z.record(PlaybookParameterSchema).optional().default({}),
  triggers: z.array(TriggerConfigSchema).optional().default([]),
  steps: z.array(StepSchema).min(1),
  edges: z.array(EdgeSchema).optional().default([]),
});

export type PlaybookYaml = z.infer<typeof PlaybookYamlSchema>;
export type PlaybookStep = z.infer<typeof StepSchema>;
export type PlaybookEdge = z.infer<typeof EdgeSchema>;
export type PlaybookParameter = z.infer<typeof PlaybookParameterSchema>;

12.2 Designer Canvas State

// packages/oxagen/src/contracts/playbook/designer-types.ts

import type { Node, Edge } from "reactflow";

/** Step node data rendered on the canvas */
export interface StepNodeData {
  stepKey: string;
  name: string;
  stepType: PlaybookStepType;
  config: Record<string, unknown>;
  isAsync: boolean;
  exitOnError: boolean;
  requiresApproval: boolean;
  timeoutSeconds?: number;
  retryPolicy?: { maxAttempts: number; backoffMs?: number };
  notes?: string;
  displayConfig?: {
    color?: string;
    icon?: string;
    width?: number;
    collapsed?: boolean;
  };
  // Runtime state (during live run visualization)
  runStatus?: "pending" | "running" | "completed" | "failed" | "skipped" | "waiting_approval";
}

export type StepNode = Node<StepNodeData>;

export interface PlaybookEdgeData {
  edgeType: "default" | "conditional" | "on_error" | "loop_back" | "parallel";
  condition?: Record<string, unknown>;
  priority: number;
  label?: string;
}

export type PlaybookEdge = Edge<PlaybookEdgeData>;

/** Designer store state (Zustand) */
export interface DesignerState {
  // Playbook metadata
  playbookId: string | null;
  versionId: string | null;
  isDraft: boolean;
  isDirty: boolean;

  // Canvas state
  nodes: StepNode[];
  edges: PlaybookEdge[];
  selectedNodeId: string | null;
  viewport: { x: number; y: number; zoom: number };

  // Parameters
  parameters: Record<string, PlaybookParameter>;

  // Triggers
  triggers: TriggerConfig[];

  // History (undo/redo)
  history: DesignerCommand[];
  historyIndex: number;

  // Actions
  addStep: (type: PlaybookStepType, position: { x: number; y: number }) => void;
  updateStep: (nodeId: string, data: Partial<StepNodeData>) => void;
  removeStep: (nodeId: string) => void;
  connectSteps: (from: string, to: string, edgeType?: string) => void;
  disconnectSteps: (edgeId: string) => void;
  undo: () => void;
  redo: () => void;
  save: () => Promise<void>;
  publish: () => Promise<void>;
  exportYaml: () => string;
  importYaml: (yaml: string) => void;
}

13. Execution & Runtime Enhancements

13.1 Template Resolution Pipeline

flowchart LR
    RAW["Raw step config\n(JSONB from DB)"] --> P1["Phase 1: Parameters\n{{paramName}} → value"]
    P1 --> P2["Phase 2: Context\n{{context.*}} → runtime ctx"]
    P2 --> P3["Phase 3: Step Refs\n{{steps.*.output}} → prior output"]
    P3 --> P4["Phase 4: Secrets\n{{secrets.*}} → vault lookup"]
    P4 --> P5["Phase 5: Ontology\n{{ontology.*}} → Neo4j query"]
    P5 --> RESOLVED["Fully resolved config\n→ Step executor"]

Executes a Cypher query against the workspace's Neo4j ontology graph:

interface KnowledgeSearchConfig {
  // Raw Cypher query with $param placeholders
  query: string;
  // Parameters to bind (supports template interpolation)
  parameters?: Record<string, unknown>;
  // Max rows returned
  limit?: number;
  // Map result columns to output fields
  outputMapping?: Record<string, string>;
}

13.3 New Step Type: code_execution

Runs sandboxed code (leverages existing packages/sandbox):

interface CodeExecutionConfig {
  runtime: "javascript" | "python" | "bash";
  code: string;
  timeout?: number;     // max seconds (default 30)
  memoryMb?: number;    // max memory (default 128)
  // Input variables available as `context` in the script
  inputMapping?: Record<string, string>;
}

13.4 Live Run Visualization

During execution, the Inngest function emits step status updates that the designer UI subscribes to (via polling or SSE):

// GET /v1/playbooks/:id/runs/:runId/live
interface LiveRunUpdate {
  runId: string;
  status: "running" | "paused" | "completed" | "failed";
  currentStepId: string | null;
  stepStatuses: Record<string, {
    status: "pending" | "running" | "completed" | "failed" | "waiting_approval";
    startedAt?: string;
    completedAt?: string;
    output?: unknown;
    error?: string;
  }>;
  eventCount: number;
  lastEventHash: string;
}

The canvas highlights the currently executing step and shows status badges on completed steps (green check, red X, orange clock for approval).


14. Delivery Phases

Phase 1: Foundation (4 weeks)

Goal: Functional visual editor with CRUD, versioning, and YAML export.

TaskEffortOwner
Capability contracts (CRUD, version, graph editing)1 weekBackend
Hono API routes for all playbook capabilities1 weekBackend
YAML schema Zod validator + serializer/deserializer3 daysBackend
React Flow canvas with 6 core step types (tool, agent, prompt, condition, webhook, sub_playbook)1.5 weeksFrontend
Property panel with step config forms1 weekFrontend
Step palette (drag-to-canvas)2 daysFrontend
Version create/publish flow3 daysFull-stack
YAML export/import UI2 daysFull-stack
Seed playbook provisioning (Inngest job)2 daysBackend
Database migrations (parameters, canvas_state)1 dayBackend

Exit Criteria:

  • User can create a playbook, add steps, connect them, save, and publish
  • Playbook exports as valid YAML that re-imports identically
  • Seed playbooks auto-provision in new workspaces

Phase 2: Execution & Intelligence (4 weeks)

Goal: Run playbooks from the designer, see live execution, use ontology context.

TaskEffortOwner
playbook.run.start wired through designer UI2 daysFull-stack
Live run visualization (SSE + step highlighting)1 weekFull-stack
Approval workflow UI (request/resolve panel)1 weekFull-stack
Template expression editor with autocomplete1 weekFrontend
Ontology context picker (entity type → property)1 weekFrontend
knowledge_search step type (Cypher executor)3 daysBackend
code_execution step type (sandbox integration)3 daysBackend
Version diff view (side-by-side graph comparison)1 weekFrontend
Run history panel3 daysFrontend
Trigger configuration panel (cron editor, event picker)3 daysFrontend

Exit Criteria:

  • User can run a playbook and watch steps execute in real-time on the canvas
  • Approval gates pause execution and notify the designated reviewer
  • Steps can reference ontology entities via the picker UI
  • Version diff shows added/removed/modified steps visually

Phase 3: Enterprise & Scale (4 weeks)

Goal: Marketplace, AI assistance, advanced enterprise controls.

TaskEffortOwner
Marketplace data model + browse/install flow1 weekFull-stack
Marketplace publish flow (review, verify badge)1 weekFull-stack
AI-assisted playbook generation (chat → graph)1.5 weeksAI/Backend
Dry-run / testing mode (mocked context)1 weekBackend
Collaborative editing (cursor presence, lock)1 weekFull-stack
CLI oxagen playbook push/pull commands3 daysCLI
MCP surface: playbook tools2 daysBackend
Custom step type plugin system1 weekBackend
Performance: large playbook rendering (100+ steps)3 daysFrontend
Documentation & onboarding tours2 daysProduct

Exit Criteria:

  • Organizations can publish/install playbooks via marketplace
  • AI can generate a playbook graph from a natural language description
  • CLI bidirectional sync between filesystem and workspace works
  • Designer performs smoothly with 100+ node graphs

15. Open Questions & Decisions

#QuestionOptionsRecommendation
1Should YAML allow multi-file playbooks?Single-file vs split steps/edgesSingle-file for v1 (simpler portability)
2Real-time collaboration: CRDT or lock-based?Yjs CRDT vs optimistic lockLock-based for v1 (enterprise predictability)
3Should marketplace playbooks auto-update?Fork (independent) vs linked (upstream sync)Fork for v1 (security: no external mutation)
4Playbook versioning: semver or monotonic?User-managed semver vs auto-incrementMonotonic integer internally, user semver in YAML metadata
5How to handle breaking schema changes?Migration scripts vs version adaptersVersion adapters (zod discriminated union on schemaVersion)
6Should canvas layout be part of the version hash?Include positions vs excludeExclude (positions are cosmetic, not semantic)
7Rate limiting for event triggers?Per-trigger config vs globalPer-trigger with global ceiling (prevent runaway loops)
8Max playbook depth for sub_playbook?Unlimited vs fixedFixed at 5 levels (prevent infinite recursion)

16. Risk Assessment

RiskLikelihoodImpactMitigation
React Flow performance with 100+ nodesMediumHighVirtual rendering, collapse groups, lazy property loading
Template injection attacks in {{...}}LowCriticalSandboxed evaluation, no eval(), allowlisted functions only
Ontology query timeouts blocking executionMediumMedium5s timeout per query, fallback to empty context with warning
Version hash collisions (SHA-256)NegligibleHigh256-bit space makes collisions astronomically unlikely
YAML format breaking changes post-launchMediumHighSchema version + adapter pattern; never remove fields
Approval gates creating bottlenecksHighMediumEscalation policies, configurable auto-approve after timeout
Marketplace playbooks with malicious stepsLowCriticalVerification process, sandbox-only execution for unverified

17. Success Metrics

MetricTarget (Phase 1)Target (Phase 3)
Playbooks created per workspace per month3+10+
% of playbooks with >3 steps60%80%
Median time to create a 5-step playbook<10 min<5 min (with AI)
YAML export/import round-trip fidelity100%100%
Playbook run success rate>90%>95%
Approval gate response time (median)<4 hours<1 hour
Marketplace installs per published playbookN/A5+
Designer page load time (p95)<2s<1.5s

18. References

  • cc-wf-studio source — Visual workflow editor inspiration
  • React Flow — Canvas library
  • Inngest — Durable execution engine
  • Existing schema: packages/database/src/schema/workflow.ts
  • Existing executor: packages/inngest-functions/src/functions/playbook.run.execute.ts
  • Existing trigger matcher: packages/inngest-functions/src/functions/playbook.trigger.match.ts
  • Architecture: .agents/summary/architecture.md

End of spec.

On this page

Spec — SPEC.mdPlaybook Designer — Product & Engineering Spec1. Executive Summary2. Problem StatementCurrent StateUser Pain PointsSuccess Criteria3. Architecture Overview4. YAML Playbook Format Specification4.1 Design Principles4.2 File Location Convention4.3 YAML Schema (v1.0.0)4.4 Step Types Reference4.5 Template Interpolation4.6 Portability Contract5. Data Model Enhancements5.1 Existing Schema (No Changes Required)5.2 New Table: playbook_parameters5.3 New Table: playbook_canvas_state5.4 New Table: playbook_marketplace_listings5.5 New Column Additions6. Capability Contracts (API Surface)6.1 CRUD Capabilities6.2 Version & Graph Capabilities6.3 Graph Editing Capabilities (Designer)6.4 Execution Capabilities6.5 Portability Capabilities6.6 Ontology Integration Capabilities7. UI Architecture — Playbook Designer7.1 Component Hierarchy7.2 Technology Choices7.3 Node Types (Visual)7.4 Property Panel7.5 Designer Features Matrix8. Ontology Knowledge Graph Integration8.1 Context Injection Model8.2 Ontology Template Syntax8.3 Knowledge Search Step Type8.4 Designer Integration9. Enterprise & SOC 2 Controls9.1 Audit Trail9.2 Version Integrity9.3 Approval Workflows9.4 Access Control (IAM)9.5 Secrets Handling10. Seed Playbooks & Marketplace10.1 Seed Strategy10.2 Seed Lifecycle10.3 Marketplace (Phase 3)11. Improvements Over cc-wf-studio12. TypeScript Interfaces12.1 YAML Parse Target12.2 Designer Canvas State13. Execution & Runtime Enhancements13.1 Template Resolution Pipeline13.2 New Step Type: knowledge_search13.3 New Step Type: code_execution13.4 Live Run Visualization14. Delivery PhasesPhase 1: Foundation (4 weeks)Phase 2: Execution & Intelligence (4 weeks)Phase 3: Enterprise & Scale (4 weeks)15. Open Questions & Decisions16. Risk Assessment17. Success Metrics18. References