Lifecycle Config
spec.lifecycle stage-to-tracker-state mapping.
spec.lifecycle maps the platform's abstract SDLC stage vocabulary to your tracker's native state names, binding each stage to the exact state transitions that should start and stop it. This is what makes Rensei's SDLC engine tracker-agnostic - the same workflow definition adapts to Linear, Jira, or any future issue tracker by changing only the lifecycle config.
How it works
Schema
spec:
lifecycle:
# Stage ID: either a known platform stage or a custom free-form string
research:
trigger:
event: issue.transitioned
when:
to: "Icebox" # exact tracker-native state name
exit:
transition_to: "Triage" # optional - platform drives issue to this state on success
on_fail: "Rejected" # optional - driven on stage failure
prompt: | # optional - override the platform default prompt
Research this issue thoroughly...
development:
trigger:
event: issue.transitioned
when: { to: "Backlog" }
exit:
transition_to: "In Review"
on_fail: "Rejected"
qa:
trigger:
event: issue.transitioned
when: { to: "In Review" }
exit:
transition_to: "Done"
on_fail: "Rejected"Stage entry fields
Prop
Type
Platform stages vs custom stages
The platform ships a built-in registry of known stage IDs - research, backlog-writer, development, coordination, qa, acceptance - each with a default prompt template and budget defaults.
You may use any free-form string as a stage ID. Unknown stage IDs produce a validation warning (not an error) and are dispatched with default budgets. Custom stages must provide an explicit prompt field since no platform template exists.
spec:
lifecycle:
my-custom-spike: # unknown stage - fine, but you must supply a prompt
trigger:
event: issue.transitioned
when: { to: "Spiking" }
exit:
transition_to: "Backlog"
prompt: |
Investigate the technical feasibility of...Validation rules
validateLifecycleConfig enforces:
- Structural shape - Zod validation of each stage entry.
- No duplicate trigger states - two stages cannot share the same
trigger.when.tovalue. The trigger normaliser would otherwise fan out N stage events for one transition, which is almost never intended. - Warning for unknown stage ids - the config is still accepted; the platform logs a warning and dispatches with defaults.
Native-state validity (does "Icebox" actually exist in your Linear team?) is not checked at save time. The trigger normaliser fails closed at runtime when no stage matches an inbound transition - no event is emitted, no agent is dispatched.
State names are case-sensitive and must match your tracker's canonical names exactly. Linear teams use "Started", not "In Progress". Check Settings → Teams → [team] → Workflow in Linear for the exact names. A mismatch silently no-ops - the trigger normaliser finds no matching stage and discards the event.
Prompt resolution order
When the platform prepares to dispatch a stage, it resolves the agent prompt as follows:
lifecycle[stageId].prompt- the inline override from this config- The registered TS module for the stage ID - the platform's canonical default
- Error - the author must provide a prompt or register the stage
Auto-derivation from canvas
At publish time, deriveLifecycleFromCanvas walks the workflow definition and reconstructs spec.lifecycle from agent.dispatch_stage node config fields. This means the lifecycle config is node-first - you set triggerWhen and exit directly on the dispatch node in the canvas, not in a separate lifecycle tab.
The reconstructed lifecycle is validated before publish. The editor shows the derived config in the YAML pane under spec.lifecycle.
Full example (Linear mapping)
The following maps the platform's five canonical stages to a Rensei/Linear team workflow:
spec:
lifecycle:
research:
trigger:
event: issue.transitioned
when: { to: "Icebox" }
exit:
transition_to: "Triage"
backlog-writer:
trigger:
event: issue.transitioned
when: { to: "Triage" }
exit:
transition_to: "Backlog"
development:
trigger:
event: issue.transitioned
when: { to: "Backlog" }
exit:
transition_to: "Finished"
on_fail: "Rejected"
qa:
trigger:
event: issue.transitioned
when: { to: "Finished" }
exit:
transition_to: "Delivered"
on_fail: "Rejected"
acceptance:
trigger:
event: issue.transitioned
when: { to: "Delivered" }
exit:
transition_to: "Accepted"
on_fail: "Rejected"Related pages
- State Machine - embedding a state machine vocabulary in the workflow
- SDLC Default Template - production lifecycle using these stages
- SDLC Work Types - research → backlog-writer → development pathway
- Linear Integration - connecting Linear webhook triggers