Customizing the Workflow
/.trellis/workflow.md defines how Trellis runs development. Phase definitions, skill routing, per-turn reminders, and the task.py command catalog all live in this one file. Forking the workflow means editing one markdown file — no Python, no hook code, no re-releasing Trellis.
Before 0.5, workflow behavior was scattered across three places: hook Python scripts, configurator TypeScript, and command markdown. Keeping them in sync while forking was painful. 0.5 collapses the three into workflow.md.
What workflow.md controls
All injection paths read
workflow.md at runtime — you don’t need to rebuild anything after editing.
Changing the per-turn breadcrumbs
The per-turn<workflow-state> block is what nudges the AI at each message based on the current task’s status field. The blocks live colocated with each phase under ## Phase Index in workflow.md — edit them in place. The hook script is parser-only; it never embeds fallback content of its own.
- Tag
STATUSmatchestask.json.status. Defaults:planning/in_progress/completed, plusno_taskwhen no task is active. - Hyphens and underscores are both allowed in the tag (
blocked/in-review/needs_qaetc.). - If a status has no matching tag block, the hook emits the generic line
Refer to workflow.md for current step.and the AI falls back to reading the workflow contract directly. Delete blocks you don’t need. task.py createsets the active-task pointer alongside writingstatus=planning, so the[workflow-state:planning]block fires from the very next turn — during brainstorm and planning artifact work, not just aftertask.py start.- Keep each block short (~200 bytes). This is injected every turn; bloat means the AI pays attention cost on every message.
Adding a custom workflow state
Want ablocked state that nudges the AI to escalate instead of guessing?
task.json directly:
blocked breadcrumb injected per turn. Switch it back to in_progress the same way to resume the normal flow.
Built-in task.py subcommands only transition between the default statuses (start → in_progress, archive → completed). Custom statuses are plain strings in task.json.status — the breadcrumb system doesn’t require pre-registering them, and task.py list --status <name> can filter by any string.
Changing the skill routing table
The table under### Skill Routing is what the AI consults when deciding whether to load an auto-trigger skill.
Adding or reshaping a Phase
The Phase sections inworkflow.md are plain markdown. You can:
- Add a Phase 4: Review — define steps (4.1, 4.2, …) and their how-to text. Reference it from breadcrumbs (
[workflow-state:in_review]). - Split Plan into two branches (A/B) — replace step numbering with 1A.1 / 1B.1 naming; the AI follows what’s in the text.
- Shorten Finish — delete steps you don’t care about (e.g. drop 3.2 debug retrospective).
get_context.py --mode phase --step X.Y parses ## Phase X headings + #### X.Y step headings
to extract the step body. If you rename or reshape sections, make sure the step anchors still
parse (heading depth is significant).What NOT to edit
A handful of conventions are consumed by scripts and shouldn’t drift:
Everything else — phrasing, ordering, adding sections, rewriting how-to text — is fair game.
When your change takes effect
Forks don’t need to republish anything. Commit your edited
workflow.md to the repo and your team picks up the change on the next session start.