Dev-Orchestrator Routing Contract¶
The dev-orchestrator routes every normalized Development workstream to default-workflow.
This document defines the routing contract. Rust-helper enforcement runs before workstream execution: model-produced recipe fields are advisory input only and cannot override the Development routing invariant.
Contents¶
- Routing invariant
- Classification authority
- Recipe normalization
- Workstream JSON API
- Configuration
- Examples
- Security contract
- Related
Routing invariant¶
Any workstream whose normalized classification is Development must run default-workflow.
The override applies when the workstream recipe is:
- missing
- an empty string after trimming
- whitespace only
- any recipe other than
default-workflow
The invariant applies per workstream. A top-level hybrid task can contain multiple workstreams with different classifications, and each workstream must be routed from its own normalized classification.
Classification authority¶
The routing implementation uses the most specific classification available.
| Source | Authority | Routing effect |
|---|---|---|
Per-workstream classification, task_type, or type |
Highest | Used to normalize that workstream's recipe |
Top-level task_type |
Fallback | Used only when the workstream has no per-workstream classification |
Model-provided recipe |
Advisory | Preserved only when it does not violate deterministic routing |
The normalized classification is authoritative for routing. The raw model text must be normalized before routing decisions are made, so common variants such as dev, development, or mixed-case Development resolve to the same classification.
The exact fallback rule is:
- Use the workstream's own
classification,task_type, ortypewhen present. - Use the top-level
task_typeonly when the workstream has none of those fields. - Route an unclassified workstream under top-level
Developmenttodefault-workflow.
This keeps hybrid decomposition safe: investigation, Q&A, operations, and consensus workstreams inside a broader development request must not inherit Development when they carry their own non-Development classification.
Recipe normalization¶
The deterministic normalization rule is:
| Normalized workstream classification | Input recipe | Normalized recipe |
|---|---|---|
Development |
missing | default-workflow |
Development |
"" or whitespace |
default-workflow |
Development |
investigation-workflow |
default-workflow |
Development |
any non-default-workflow value |
default-workflow |
Development |
default-workflow |
default-workflow |
| Non-Development | any value | Existing route is preserved |
Non-Development classifications must not be rewritten by the Development invariant. Their existing route selection remains in force:
| Classification | Existing routing behavior |
|---|---|
Investigation |
Uses the investigation route selected by smart-orchestrator, normally investigation-workflow for recipe execution |
Q&A |
Uses the direct analyzer-answer route for top-level Q&A; workstream recipes are preserved when a plan explicitly contains Q&A workstreams |
Operations |
Uses the operations route selected by smart-orchestrator; workstream recipes are preserved when a plan explicitly contains operations workstreams. The current bundle does not define an ops-workflow recipe |
Consensus |
Uses the consensus route selected by smart-orchestrator; workstream recipes are preserved when a plan explicitly contains consensus workstreams |
Workstream JSON API¶
amplihack orch helper build-workstreams-config accepts the decomposition JSON emitted by smart-classify-route and writes a workstreams JSON file for amplihack orch run with deterministic Development routing applied.
Input shape¶
{
"task_type": "Development",
"goal": "Improve routing reliability",
"success_criteria": [
"Development workstreams always run default-workflow"
],
"workstreams": [
{
"name": "routing-normalization",
"classification": "Development",
"description": "Fix deterministic routing normalization",
"recipe": "investigation-workflow"
}
]
}
Supported per-workstream classification keys:
| Field | Purpose |
|---|---|
classification |
Preferred per-workstream classification field |
task_type |
Backward-compatible classification field |
type |
Backward-compatible classification field |
The helper normalizes whichever per-workstream classification field is present. If more than one exists, the implementation treats the first supported field in its documented precedence order as the workstream classification.
Output shape¶
[
{
"issue": "TBD",
"branch": "feat/orch-1-routing-normalization",
"task": "Fix deterministic routing normalization",
"description": "routing-normalization",
"recipe": "default-workflow"
}
]
The output uses the amplihack orch run workstreams schema. See orch run for the complete execution schema.
Configuration¶
There is no configuration flag that disables the Development routing invariant.
| Setting | Effect on routing |
|---|---|
force_single_workstream=true |
Prevents parallel decomposition, but a single Development workstream still runs default-workflow |
AMPLIHACK_MAX_DEPTH=0 |
Blocks parallel spawning and adapts to single-session execution; Development still runs default-workflow |
AMPLIHACK_AGENT_BINARY |
Chooses the agent backend; does not affect workflow recipe selection |
AMPLIHACK_HOME |
Locates recipe assets; does not affect the routing invariant |
Prompt text in dev-orchestrator, smart-classify-route, smart-execute-routing, and the routing hook should state the same rule for model guidance:
Development classification always routes to
default-workflow; model-provided recipe fields do not override that invariant.
That prompt text is supportive documentation for the model. The Rust helper is authoritative.
Examples¶
Development workstream with missing recipe¶
Input:
{
"task_type": "Development",
"workstreams": [
{
"name": "api-fix",
"classification": "Development",
"description": "Fix the user API timeout"
}
]
}
Normalized output:
[
{
"issue": "TBD",
"branch": "feat/orch-1-api-fix",
"task": "Fix the user API timeout",
"description": "api-fix",
"recipe": "default-workflow"
}
]
Development workstream with wrong recipe¶
Input:
{
"task_type": "Development",
"workstreams": [
{
"name": "test-regression",
"classification": "Development",
"description": "Add regression tests for routing",
"recipe": "investigation-workflow"
}
]
}
Normalized output:
[
{
"issue": "TBD",
"branch": "feat/orch-1-test-regression",
"task": "Add regression tests for routing",
"description": "test-regression",
"recipe": "default-workflow"
}
]
Hybrid decomposition preserves non-Development routes¶
Input:
{
"task_type": "Development",
"workstreams": [
{
"name": "trace-current-routing",
"classification": "Investigation",
"description": "Trace current workstream route selection",
"recipe": "investigation-workflow"
},
{
"name": "fix-routing",
"classification": "Development",
"description": "Enforce Development routing in Rust",
"recipe": "investigation-workflow"
}
]
}
Normalized output:
[
{
"issue": "TBD",
"branch": "feat/orch-1-trace-current-routing",
"task": "Trace current workstream route selection",
"description": "trace-current-routing",
"recipe": "investigation-workflow"
},
{
"issue": "TBD",
"branch": "feat/orch-2-fix-routing",
"task": "Enforce Development routing in Rust",
"description": "fix-routing",
"recipe": "default-workflow"
}
]
The top-level task is Development, but the investigation workstream keeps its own route because its per-workstream classification is Investigation.
Unclassified workstream under top-level Development¶
Input:
{
"task_type": "Development",
"workstreams": [
{
"name": "unclassified-fix",
"description": "Fix an unclassified development workstream",
"recipe": "investigation-workflow"
}
]
}
Normalized output:
[
{
"issue": "TBD",
"branch": "feat/orch-1-unclassified-fix",
"task": "Fix an unclassified development workstream",
"description": "unclassified-fix",
"recipe": "default-workflow"
}
]
The workstream has no own classification, so the helper falls back to the top-level Development classification.
Security contract¶
Decomposition JSON is model-produced and treated as untrusted input.
The routing helper must:
- trim recipe strings before checking whether they are empty
- normalize classification before comparing it to
Development - prevent raw recipe strings from choosing the workflow for Development workstreams
- avoid building shell commands from model-provided recipe values
- preserve non-Development behavior without broad fallback logic that masks malformed plans