Skip to content

feat(linear): support custom workflow statuses#1364

Open
maksymilian-majer wants to merge 12 commits into
mongrel-intelligence:devfrom
maksymilian-majer:dev
Open

feat(linear): support custom workflow statuses#1364
maksymilian-majer wants to merge 12 commits into
mongrel-intelligence:devfrom
maksymilian-majer:dev

Conversation

@maksymilian-majer
Copy link
Copy Markdown
Contributor

@maksymilian-majer maksymilian-majer commented May 12, 2026

Summary

Adds database-backed workflow status definitions and wires them through Linear project setup, custom agent dispatch, dashboard stats filters, prompt loading, and CLI management. This lets Linear statuses map to custom Cascade workflow stages and custom agents while preserving the built-in statuses as immutable defaults.

Also routes manual/retry runs through the normal execution lifecycle so successful implementation retries still create/link PRs and advance the work item lifecycle.

Screenshots

Custom statuses

Screenshot 2026-05-12 at 20 48 03

Status mapping to agent

Screenshot 2026-05-12 at 20 48 52

Custom agent triggers

Screenshot 2026-05-12 at 20 49 29

Test Plan

  • Unit tests pass (npm test)
  • Linter passes (npm run lint)
  • Type check passes (npm run typecheck)
  • Tested manually: configured Linear custom statuses/agents locally, exercised PRD/story/phased-plan/implementation flow, verified retry/manual implementation lifecycle behavior

Additional verification run locally:

  • npm run build
  • npm run verify
  • pre-push npm run test:fast

Checklist

  • My code follows the project's code style
  • I have added tests for new functionality
  • I have updated documentation if needed
  • My commits follow Conventional Commits

@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

@zbigniewsobiecki zbigniewsobiecki requested a review from aaight May 13, 2026 10:34
Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Requesting changes: the Linear wizard no longer exposes the existing friction status slot once workflow statuses load, which regresses friction reporting setup.

Code Issues

Should Fix

  • web/src/components/projects/pm-providers/linear/wizard.ts:184 — Switching the Linear mapping UI to workflowStatuses.list drops the friction slot because BUILTIN_WORKFLOW_STATUSES does not include it. statuses.friction is still part of the Linear config contract and is required by friction materialization, so new Linear projects can no longer configure friction reports through the wizard.

🕵️ codex · gpt-5.5 · run details

Comment thread web/src/components/projects/pm-providers/linear/wizard.ts
Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Requesting changes because custom Linear statuses can dispatch but do not participate in lifecycle moves, and Linear setup can auto-enable backlog-manager unexpectedly.

Code Issues

Should Fix

  • src/pm/linear/integration.ts:92 - Custom workflow statuses saved in linearConfig.statuses are not included in the normalized lifecycle config. A custom agent can declare lifecycle.moveOnSuccess: story because the schema accepts arbitrary strings, but PMLifecycleManager.handleSuccess() resolves moves through pmConfig.statuses[moveOnSuccess]; for story that lookup is undefined, so safeMove skips the transition. Any PRD/story/phased-plan style flow that relies on the normal lifecycle will dispatch when a user manually moves into the custom state, but it will not advance to the next custom Linear state on success. Include custom status mappings in resolveLifecycleConfig and widen ProjectPMConfig.statuses accordingly.
  • web/src/components/projects/pm-providers/save-trigger-configs.ts:30 - Linear setup now builds trigger configs for every mapped workflow status with an agent type. Since BUILTIN_WORKFLOW_STATUSES gives backlog agentType: 'backlog-manager', a project that maps Backlog during Linear setup gets a DB override enabling backlog-manager for pm:status-changed, even though that trigger's YAML default is false and the Trello/JIRA setup paths still only enable implementation/splitting/planning. After that, moving any Linear issue into Backlog can fire backlog-manager and pull work forward unexpectedly. Filter default-disabled built-ins such as backlog-manager out of the auto-created configs, or make the allowlist explicit.

🕵️ codex · gpt-5.5 · run details

Comment thread web/src/components/projects/pm-providers/save-trigger-configs.ts
@maksymilian-majer
Copy link
Copy Markdown
Contributor Author

Updated the PR after the latest review pass.

Changes pushed in 5dc43e73:

  • Linear lifecycle config now preserves all configured status mappings, including custom workflow status keys, so lifecycle moves can target custom statuses like prd, story, or phased-plan.
  • The PM wizard trigger setup now auto-enables only the default built-in status triggers that should start runs (splitting, planning, todo). Built-in slots such as backlog remain opt-in, while custom mapped statuses with agent definitions still get trigger configs.
  • Added regression coverage for custom Linear mappings, lifecycle prepare/success moves to custom keys, built-in friction/no-agent status metadata, and trigger auto-enable behavior.

Verification:

  • npm test -- tests/unit/pm/linear-integration.test.ts tests/unit/pm/linear/integration.test.ts tests/unit/pm/lifecycle.test.ts tests/unit/pm/lifecycle-config-shape.test.ts tests/unit/web/pm-wizard-hooks.test.ts tests/unit/pm/workflow-statusDefinitions.test.ts
  • npm run typecheck
  • pre-push npm run test:fast -- --changed origin/dev ... passed: 316 files, 6084 tests, 23 skipped.

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Requesting changes: manual/retry runs now always use PM lifecycle defaults, which regresses PR-based agent retries by mutating linked PM work items.

Code Issues

Should Fix

  • src/triggers/shared/manual-runner.ts:152 — PR-based manual/retry runs now enter runAgentExecutionPipeline without the GitHub execution config. The normal GitHub path explicitly sets skipPrepareForAgent, skipHandleFailure, and handleSuccessOnlyForAgentType so review/respond-to-ci/respond-to-review runs do not add/remove PM lifecycle labels or post PM failure comments. A retry of a linked review run can now resolve the work item from the PR, call prepareForAgent, then handleSuccess, and mark the PM item processing/processed even though no implementation lifecycle occurred. Preserve the GitHub execution config for PR-based manual/retry runs, or scope this new lifecycle behavior to the PM/implementation retry case.

🕵️ codex · gpt-5.5 · run details

Comment thread src/triggers/shared/manual-runner.ts Outdated
@maksymilian-majer
Copy link
Copy Markdown
Contributor Author

Fixed the latest manual/retry lifecycle review issue in 00d95a99.

Changes:

  • PR-based manual/retry runs for non-PM agents now preserve the GitHub execution config: skipPrepareForAgent, skipHandleFailure, and handleSuccessOnlyForAgentType: 'implementation'.
  • PM-focused PR-based agents keep the default PM lifecycle, so implementation-style retries can still advance the work item correctly.
  • Deleting a custom DB-backed agent now clears matching workflow_status_definitions.agent_type references to avoid stale dispatch mappings. No FK and no migration were added, because YAML-only agents remain valid references.
  • Added regression coverage for both areas.

Verification:

  • npm run typecheck
  • npm test -- tests/unit/triggers/manual-runner.test.ts tests/unit/triggers/github-integration.test.ts tests/unit/triggers/agent-execution.test.ts tests/unit/api/routers/agentDefinitions.test.ts tests/unit/db/repositories/workflowStatusDefinitionsRepository.test.ts
  • TEST_DATABASE_URL=postgresql://cascade_test:cascade_test@127.0.0.1:5433/cascade_test npx vitest run --project integration tests/integration/db/workflowStatusDefinitionsRepository.test.ts

Note: pre-push npm run test:fast -- --changed origin/dev was run and reached 315/316 passed files, but stopped on an unrelated timeout in tests/unit/agents/definitions/async-resolver.test.ts seed idempotency. Re-running that specific seed test with a larger timeout passes locally; the test spends about 11.7s in the seed path and exceeded its hard 15s timeout under full-suite load.

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Requesting changes because a custom workflow status can be mapped to an agent that the trigger resolver will never enable, making the core Linear custom-status dispatch path silently no-op.

Code Issues

Should Fix

  • src/api/routers/workflowStatuses.ts:54validateAgentType only checks that the agent definition exists. A valid custom definition can still have no pm:status-changed trigger; when a Linear issue enters the mapped state, LinearStatusChangedTrigger resolves that agent but checkTriggerEnabledWithParams() delegates to getResolvedTriggerConfig(), which returns null if the definition does not declare the event, even if the wizard inserted an agent_trigger_configs row. The webhook is then skipped. Reject these mappings with a clear error, or make workflow-status dispatch explicitly synthesize/honor status-trigger configs for mapped agents.

🕵️ codex · gpt-5.5 · run details

async function validateAgentType(agentType: string | null | undefined) {
if (!agentType) return;
try {
await resolveAgentDefinition(agentType);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This accepts any existing agent as a workflow-status dispatch target, but the status trigger later goes through checkTriggerEnabledWithParams()/getResolvedTriggerConfig(), which returns null unless that agent definition declares pm:status-changed. A custom agent with triggers: [] is valid and passes this check, so the UI/CLI can save the mapping and even upsert a trigger config, but Linear status changes will silently skip it. Please either validate that the mapped agent supports pm:status-changed here or make the workflow-status dispatch path honor these mappings without requiring a declared trigger.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants