Skip to content

02 - Resource Model

The orchestrator manages eleven core resource kinds, plus extensible Custom Resource Definitions (CRDs). All resources follow a Kubernetes-style manifest format.

Manifest Structure

Every resource uses the same envelope:

yaml
apiVersion: orchestrator.dev/v2
kind: <ResourceKind>
metadata:
  name: <unique-name>
  description: "optional description"   # optional
  labels:                               # optional
    key: value
  annotations:                          # optional
    key: value
spec:
  # kind-specific fields

Multiple resources can be defined in a single YAML file, separated by ---.

1. Workspace

A Workspace defines the execution and file-system context for a task. code_repo is the backward-compatible default; task is for non-code processes such as Slack operations, research, document work, and support triage.

yaml
apiVersion: orchestrator.dev/v2
kind: Workspace
metadata:
  name: my-project
spec:
  kind: code_repo                   # default
  work_dir: "."                    # project root directory
  qa_targets:                       # directories to scan for QA files (task items)
    - docs/qa
  ticket_dir: docs/ticket           # where failure tickets are written
  self_referential: false           # true = orchestrator modifies its own code (see chapter 06)
FieldRequiredDescription
kindNocode_repo (default) or task
work_dirConditionalRequired for code_repo; optional for task. root_path is accepted as a legacy input alias
qa_targetsConditionalRequired for code_repo; forbidden for task
ticket_dirConditionalRequired for code_repo; forbidden for task
self_referentialNoEnables survival mechanisms when true (default: false)

A non-code workspace may use a persistent shared directory:

yaml
apiVersion: orchestrator.dev/v2
kind: Workspace
metadata:
  name: warehouse-ops
spec:
  kind: task
  work_dir: ~/warehouse-data

If work_dir is omitted, the daemon creates a private 0700 HOME/cwd for each task and removes it when the task reaches a terminal state. Task workspaces always have one implicit __TASK__ item and do not scan QA files. Any host path used by a task workspace or its ExecutionProfile must be below the operator's fileSharing.shareableRoots ceiling. See Non-code Workspaces and Global Skills.

2. Agent

An Agent is an execution unit with declared capabilities and an explicit provider driver. Historical command-only manifests are accepted only at the runtime compatibility ingress, where Apply emits [legacy_agent_command_deprecated] and persists an explicit shell/cli driver.

yaml
apiVersion: orchestrator.dev/v2
kind: Agent
metadata:
  name: coder
  description: "Code generation agent"
spec:
  capabilities:          # list of capabilities this agent provides
    - implement
    - ticket_fix
    - align_tests
  driver:
    provider: claude
    transport: cli
    options:
      model: sonnet
      maxTurns: 8
      permissionMode: governed
  metadata:              # optional metadata for selection scoring
    cost: 100
    description: "Primary code generation agent"
  selection:             # optional selection strategy override
    strategy: CapabilityAware    # default
  env:                   # optional environment variables
    - name: LOG_LEVEL
      value: "debug"
    - fromRef: shared-config     # import all keys from an EnvStore
    - name: MY_API_KEY
      refValue:                  # import a single key from a SecretStore
        name: api-keys
        key: OPENAI_API_KEY
FieldRequiredDescription
capabilitiesYesWhat this agent can do (matched against step required_capability)
commandConditionalShell command template; required for an explicit shell/cli driver and omitted for Claude/Codex drivers. Command-only input is compatibility-only and is promoted with a warning
driverYes for new manifestsTyped provider/transport adapter (shell, claude, or codex; CLI transport is executable)
metadata.costNoUsed by agent selection strategy for cost-aware routing
metadata.descriptionNoHuman-readable description of the agent
selectionNoAgent selection strategy override (see below)
envNoEnvironment variables: direct values, fromRef (import all from store), or refValue (single key from store)
promptDeliveryNoHow the rendered prompt reaches an explicit shell driver: stdin, file, env, or arg (default: arg)

Agent Drivers

Explicit drivers keep provider flags out of manifests and emit normalized tool, permission, usage, and terminal events. Workflow steps declare their needs under behavior.driverRequirements; incompatible candidate Agents fail during apply. See the bilingual Agent Driver Model for complete fields, security boundaries, migration, and examples.

yaml
spec:
  capabilities: [implement]
  driver:
    provider: claude
    transport: cli
    options:
      model: sonnet
      permissionMode: ask
      allowedTools: [mcp__orch]

Agent Selection

When a step requires a capability (e.g., required_capability: implement), the orchestrator selects an agent that declares that capability. If multiple agents match, selection considers:

  • Capability match (required)
  • Selection strategy scoring (configurable per agent)
  • Cost metadata (lower is preferred)
  • Project-scoped agents (applied with --project) are used exclusively — no fallback to global agents

Selection Strategies

StrategyDescription
CostBasedStatic cost-based sorting
SuccessRateWeightedWeighted by historical success rate
PerformanceFirstLatency-focused selection
AdaptiveConfigurable weights across cost, success rate, performance, and load
LoadBalancedFavors agents with lower current load
CapabilityAwareAdaptive scoring with health-aware capability tracking (default)

3. StepTemplate

A StepTemplate decouples prompt content from agent definitions. The workflow step references a template by name; at runtime the template's prompt is injected into the agent's {prompt} placeholder.

yaml
apiVersion: orchestrator.dev/v2
kind: StepTemplate
metadata:
  name: plan
spec:
  description: "Architecture-guided implementation planning"
  prompt: >-
    You are working on the project at {source_tree}.
    Create a detailed implementation plan for: {goal}.
    Current diff: {diff}
FieldRequiredDescription
descriptionNoHuman-readable description
promptYesPrompt template with pipeline variable placeholders

Pipeline Variables

Templates can reference pipeline variables using {variable_name} syntax:

VariableDescription
{goal}Task goal string
{source_tree}Workspace root path
{workspace_root}Absolute path to workspace
{diff}Current git diff in the workspace
{rel_path}Relative path of the current item (item-scoped steps)
{qa_file_path}Path to QA file for current item
{plan_output_path}Path to the plan step's output file
{ticket_paths}Paths to active tickets for the current item
{ticket_dir}Ticket directory path
{task_id}Current task ID
{task_item_id}Current task item ID
{cycle}Current cycle number
{workspace}Workspace ID
{project}Project ID
{workflow}Workflow ID
{prev_stdout}Raw stdout from previous step
{prev_stderr}Raw stderr from previous step
{<step_id>_output}Output from step with given ID
{prompt}Resolved prompt (used in Agent command templates)

Spill to disk: Values exceeding 4096 bytes are automatically saved to a file, and the variable becomes {<key>_path} pointing to the file path instead.

4. Workflow

A Workflow defines a process flow: an ordered list of steps, a loop policy, and optional finalize rules.

yaml
apiVersion: orchestrator.dev/v2
kind: Workflow
metadata:
  name: qa_fix_retest
spec:
  steps:
    - id: qa
      type: qa
      enabled: true
    - id: ticket_scan
      type: ticket_scan
      enabled: true
    - id: fix
      type: fix
      enabled: true
    - id: retest
      type: retest
      enabled: true
  loop:
    mode: once

Workflow configuration is detailed in Chapter 03.

5. Project

A Project provides an isolation domain for resources. All resource commands accept --project to scope operations.

yaml
apiVersion: orchestrator.dev/v2
kind: Project
metadata:
  name: my-project
spec:
  description: "Frontend rewrite project"

6. RuntimePolicy

A RuntimePolicy configures runner behavior, resume strategy, and observability.

yaml
apiVersion: orchestrator.dev/v2
kind: RuntimePolicy
metadata:
  name: default
spec:
  runner:
    shell: /bin/bash
    policy_mode: strict
    # … allowed_shells, env_allowlist, redaction_patterns
  resume: { ... }
  observability: { ... }

Do not set runner.executor in new manifests. It is a parse-only compatibility field: shell is accepted solely for historical round-trip compatibility, while streaming is rejected during Apply with [legacy_runner_executor_removed]. Provider execution belongs to each Agent's spec.driver; use shell/cli, claude/cli, or codex/cli.

7. ExecutionProfile

An ExecutionProfile defines the sandbox/host execution boundary for agent steps. Defaults: mode: host, fs_mode: inherit, network_mode: inherit.

yaml
apiVersion: orchestrator.dev/v2
kind: ExecutionProfile
metadata:
  name: sandbox_write
spec:
  mode: sandbox                    # host | sandbox
  fs_mode: workspace_rw_scoped     # inherit | workspace_rw_scoped
  writable_paths: [src, docs]
  network_mode: deny               # inherit | deny | allowlist

8. EnvStore

An EnvStore holds reusable environment variable sets that agents can reference via env.fromRef.

yaml
apiVersion: orchestrator.dev/v2
kind: EnvStore
metadata:
  name: shared-config
spec:
  data:
    DATABASE_URL: "postgres://localhost/mydb"
    LOG_LEVEL: "debug"

9. SecretStore

A SecretStore has the same structure as EnvStore but is intended for sensitive values. The kind field distinguishes them at the resource level.

yaml
apiVersion: orchestrator.dev/v2
kind: SecretStore
metadata:
  name: api-keys
spec:
  data:
    OPENAI_API_KEY: "sk-..."

Agents reference stores via env entries (see Agent spec above).

10. Trigger

A Trigger enables automatic task creation on a cron schedule or in response to task lifecycle events (e.g., task_completed). It follows the Kubernetes CronJob mental model.

yaml
apiVersion: orchestrator.dev/v2
kind: Trigger
metadata:
  name: nightly-qa
spec:
  cron:
    schedule: "0 2 * * *"             # 5-field cron: min hour dom month dow
    timezone: "Asia/Shanghai"          # IANA timezone (optional, default UTC)
  action:
    workflow: full-qa                  # workflow to run
    workspace: main-workspace          # workspace for the task
  concurrencyPolicy: Forbid            # Allow | Forbid | Replace
  suspend: false
  historyLimit:
    successful: 5
    failed: 3
FieldRequiredDescription
cronOne of cron/eventCron schedule with optional timezone
eventOne of cron/eventEvent-driven trigger (source + filter)
action.workflowYesWorkflow to run when triggered
action.workspaceYesWorkspace for the created task
concurrencyPolicyNoAllow (default), Forbid (skip if active task), Replace (cancel active + create new)
suspendNoPause the trigger without deleting (default: false)
historyLimit.successfulNoCompleted tasks to keep for this trigger. No default — omit historyLimit and nothing is ever pruned
historyLimit.failedNoFailed tasks to keep for this trigger, counted separately from successful

historyLimit prunes each trigger's own tasks by name and project, deleting the task with its items, command runs, events and log files. A task that is still referenced by handoff, resume or source-ingest records is left untouched and reported in the daemon log (history limit skipped a task still referenced elsewhere, naming the table); those records are not deleted by a retention limit. Every sweep also logs one trigger history cleanup line with how many tasks it selected, deleted and skipped.

Event Trigger

An event trigger fires when a matching task lifecycle event occurs:

yaml
spec:
  event:
    source: task_completed             # task_completed | task_failed
    filter:
      workflow: build-pipeline         # only match tasks from this workflow
  action:
    workflow: deploy
    workspace: prod

Trigger Lifecycle

bash
orchestrator trigger suspend <name>    # pause trigger
orchestrator trigger resume <name>     # resume trigger
orchestrator trigger fire <name>       # manually fire (create task immediately)
orchestrator get triggers              # list all triggers
orchestrator delete trigger/<name>     # remove trigger

11. SourceTaskTemplate

A SourceTaskTemplate is a project-scoped recipe for turning verified source evidence into a future task goal and action. It is separate from StepTemplate: SourceTaskTemplate describes task creation, while StepTemplate describes an agent prompt inside a workflow step.

yaml
apiVersion: orchestrator.dev/v2
kind: SourceTaskTemplate
metadata:
  name: docs-from-slack
spec:
  skill:
    name: docs
    invocation: "$docs"
    args: ["--concise"]
  action:
    workflow: slack-documentation
    workspace: main
    start: true
    initial_vars:
      origin: slack
  goalTemplate: >-
    {skill_invocation}: use {source_message_url} as the source request
  allowedVariables: [skill_invocation, source_message_url]

The renderer accepts only exact allowlisted variables, evaluates once, and requires Slack sample URLs to be HTTPS slack.com permalinks under /archives/. Preview uses the same daemon renderer as future live routing and does not create a task or source record:

bash
orchestrator source template preview docs-from-slack \
  --project my-project --provider slack --installation primary \
  --message-url https://example.slack.com/archives/C123/p1234567890000100 \
  -o json

Normal deletion is blocked while a SourceTaskBinding references the template. Administrators can explicitly remove the template and references atomically with --force --force-references; that operation is audited.

12. SourceTaskBinding

SourceTaskBinding is a project-scoped exact policy that selects one SourceTaskTemplate from authenticated Slack reaction evidence. It references a same-project Slack webhook Trigger, which owns installation identity and the external-actor-to-role mapping.

yaml
apiVersion: orchestrator.dev/v2
kind: SourceTaskBinding
metadata:
  name: slack-code-analysis
spec:
  triggerRef: slack-main
  match:
    eventKind: reaction_added
    reaction: agent-analyze
    targetKind: message
    channels: [C01234567]
  templateRef: analyze-from-slack
  allowedActorRoles: [operator, admin]
  suspend: false

Choose exactly one channel policy: a non-empty channels list, or explicit allChannels: true. Roles are required and are resolved from Trigger actorRoles; source requests cannot supply a role. Enabled overlapping rules are rejected instead of ranked.

Trigger reaction routing is opt-in:

yaml
event:
  source: webhook
  webhook:
    provider: slack
    installationId: T012345
    actorRoles: {U012345: operator}
    reactionRouting: bindings
    secret: {fromRef: slack-signing}
    outboundCredential: {fromRef: slack-api, key: BOT_TOKEN}

reactionRouting defaults to disabled. Validate a rollout without side effects:

bash
orchestrator source binding simulate --project my-project \
  --provider slack --installation T012345 --reaction agent-analyze \
  --channel C01234567 --actor U012345 -o json
orchestrator source binding suspend slack-code-analysis --project my-project
orchestrator source binding resume slack-code-analysis --project my-project

Simulation never calls Slack, renders a template, or creates a task. When reactionRouting: bindings is active, a live signed reaction asynchronously resolves channel + message_ts through Slack chat.getPermalink, renders the selected frozen template, and creates one deterministic canonical task. Duplicate deliveries and daemon restart converge on the same message/reaction/binding route and task.

The signing secret and outboundCredential are separate same-project SecretStore references. The daemon resolves the outbound token only for the Slack API call; public source summaries, audit, timeline, and task inputs never contain it. Read-only users can inspect safe automation status/template/binding fields. Operators can explicitly retrieve the protected Slack link:

bash
orchestrator source list --project my-project -o json
orchestrator source route <source-event-id> -o json

Set reactionRouting: disabled to stop new badge routes without deleting existing tasks or evidence. Normal deletion of a referenced Trigger or SourceTaskTemplate is blocked; Admin --force --force-references removes the references atomically and records audit evidence.

Resource Lifecycle

Apply (Create / Update)

bash
# From file
orchestrator apply -f manifest.yaml

# From stdin
cat manifest.yaml | orchestrator apply -f -

# Dry-run (validate without writing)
orchestrator apply -f manifest.yaml --dry-run

Query

bash
# List resources
orchestrator get workspaces
orchestrator get agents
orchestrator get workflows

# Detail view
orchestrator describe workspace/default

# Output formats
orchestrator get agents -o json
orchestrator get agents -o yaml

# Label selector
orchestrator get workspaces -l env=dev

Export

bash
# Export all config as YAML
orchestrator manifest export

Multi-Document Manifests

A single YAML file can define all resources for a workflow. This is the recommended pattern:

yaml
# everything-in-one.yaml
apiVersion: orchestrator.dev/v2
kind: Workspace
metadata:
  name: default
spec:
  work_dir: "."
  qa_targets: [docs/qa]
  ticket_dir: docs/ticket
---
apiVersion: orchestrator.dev/v2
kind: Agent
metadata:
  name: mock_agent
spec:
  capabilities: [qa, fix, loop_guard]
  command: "echo '{\"confidence\":0.9,\"quality_score\":0.9,\"artifacts\":[]}'"
---
apiVersion: orchestrator.dev/v2
kind: Workflow
metadata:
  name: my_workflow
spec:
  steps:
    - id: qa
      type: qa
      enabled: true
    - id: fix
      type: fix
      enabled: true
  loop:
    mode: once

Then apply it all at once:

bash
orchestrator apply -f everything-in-one.yaml

Next Steps