Skip to content

Custom Pipeline

The specdacular pipeline is fully configurable. Nothing is hardcoded. This guide covers the three customization mechanisms: hooks, workflow swaps, and full pipeline replacement.


The default pipeline is defined in pipeline.json. The brain reads it on every continue invocation and dispatches accordingly:

{
"schema_version": "1.0",
"pipelines": {
"main": [
{ "name": "discuss", "workflow": "discuss.md" },
{ "name": "research", "workflow": "research.md" },
{ "name": "plan", "workflow": "plan.md" },
{ "name": "phase-execution", "pipeline": "phase-execution" }
],
"phase-execution": [
{ "name": "plan", "workflow": "phase-plan.md" },
{ "name": "execute", "workflow": "execute.md", "pause": true },
{ "name": "review", "workflow": "review.md", "pause": true },
{ "name": "revise", "workflow": "revise.md", "pause": true }
]
},
"hooks": { "pre-step": null, "post-step": null }
}

To override this, place .specd/pipeline.json in your project. This is a full replace — not a merge. The entire default pipeline is replaced by your file.


Hooks are markdown workflow files that run before or after pipeline steps. They’re the lightest customization — you don’t change the pipeline structure, just add behavior around existing steps.

The easiest way to add a hook: create a file at the right path. The brain automatically checks for:

.specd/hooks/pre-{step-name}.md
.specd/hooks/post-{step-name}.md

For example, to run something before every execution phase:

.specd/hooks/pre-execute.md

The brain finds it automatically — no configuration needed.

For explicit control over hook behavior, configure hooks in your .specd/pipeline.json:

{
"name": "execute",
"workflow": "execute.md",
"hooks": {
"pre": {
"workflow": ".specd/hooks/pre-execute.md",
"mode": "inline",
"optional": false
},
"post": {
"workflow": ".specd/hooks/post-execute.md",
"mode": "subagent",
"optional": true
}
}
}
ModeBehavior
inlineRuns in the brain’s context. Can read all state, task files, and pipeline configuration.
subagentSpawns a separate agent with fresh context. Isolated — ideal for side effects like notifications or external API calls.
SettingBehavior on failure
optional: falseStops the pipeline. State is saved.
optional: trueLogs a warning. Pipeline continues.
Global pre-step hook (hooks.pre-step in pipeline.json)
Step pre-hook (hooks.pre in step config, or convention fallback)
Step runs
Step post-hook (hooks.post in step config, or convention fallback)
Global post-step hook (hooks.post-step in pipeline.json)

Example: Notify a Slack channel after review

Section titled “Example: Notify a Slack channel after review”

Create .specd/hooks/post-review.md:

# Hook: Post-Review Notification
Read the review outcome from config.json.
If the review was approved:
- Post to the #deployments Slack channel:
"Feature {task-name} phase {N} approved and ready for deploy."
If the review requested changes:
- Post to #code-review:
"Feature {task-name} phase {N} needs revisions."

This runs automatically after every review step. No pipeline configuration needed.


If you want to change what a specific step does — without altering the pipeline structure — point its workflow field to your own markdown file.

Example: replace the default research step with one that searches your internal knowledge base:

{
"schema_version": "1.0",
"pipelines": {
"main": [
{ "name": "discuss", "workflow": "discuss.md" },
{ "name": "research", "workflow": ".specd/workflows/custom-research.md" },
{ "name": "plan", "workflow": "plan.md" },
{ "name": "phase-execution", "pipeline": "phase-execution" }
],
"phase-execution": [
{ "name": "plan", "workflow": "phase-plan.md" },
{ "name": "execute", "workflow": "execute.md", "pause": true },
{ "name": "review", "workflow": "review.md", "pause": true },
{ "name": "revise", "workflow": "revise.md", "pause": true }
]
},
"hooks": { "pre-step": null, "post-step": null }
}

Custom workflow files use the same markdown format as the built-in ones. They receive $TASK_NAME as context.


For teams with fundamentally different workflows, replace the entire pipeline. Create .specd/pipeline.json with whatever structure makes sense:

{
"schema_version": "1.0",
"pipelines": {
"main": [
{ "name": "spec", "workflow": ".specd/workflows/spec.md" },
{ "name": "approve", "workflow": ".specd/workflows/approve.md", "pause": true },
{ "name": "implement", "pipeline": "implementation" }
],
"implementation": [
{ "name": "build", "workflow": ".specd/workflows/build.md", "pause": true },
{ "name": "test", "workflow": ".specd/workflows/test.md", "pause": true },
{ "name": "ship", "workflow": ".specd/workflows/ship.md", "pause": true }
]
},
"hooks": { "pre-step": null, "post-step": null }
}

Any step can be configured to pause before execution:

{ "name": "execute", "workflow": "execute.md", "pause": true }

In default mode, the brain pauses here and asks: “Execute, Review plan, or Stop for now?” In --auto mode, pause is ignored and execution continues without prompting. In --interactive mode, the brain prompts at every step regardless of the pause field.


Pattern: Require tests before review passes

Section titled “Pattern: Require tests before review passes”

Add a post-execute hook that runs your test suite and fails if tests don’t pass. Since optional: false, a test failure stops the pipeline before review.

Add a post-review hook that deploys to a staging environment when review is approved.

Add a post-step global hook that updates a Jira/Linear ticket when each stage completes.