Skip to content

feat(run-links): add per-project run links in agent comments#790

Merged
aaight merged 2 commits intodevfrom
feature/run-links
Mar 14, 2026
Merged

feat(run-links): add per-project run links in agent comments#790
aaight merged 2 commits intodevfrom
feature/run-links

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 14, 2026

Summary

Adds an optional per-project feature (run_links_enabled) that appends subtle dashboard links to all agent comments — progress updates, ack messages, PR bodies, PR reviews, and PM/GitHub comments — making it easy to navigate directly to the relevant run for debugging.

Card: https://trello.com/c/uWTDE4mD/312-lets-add-an-optional-flag-on-per-project-basis-off-by-default-that-will-make-all-out-agent-comments-in-both-scm-and-pm-tools-cod

What was implemented

  • DB schema — Added run_links_enabled BOOLEAN DEFAULT false to projects table (migration 0037_add_run_links.sql)
  • Config layerrunLinksEnabled surfaces through configMapper, Zod ProjectConfigSchema, projectsRepository, and API router (create/update endpoints)
  • Run link utility — New src/utils/runLink.ts with buildRunLink(), buildWorkItemRunsLink(), shortenModelName(), and getDashboardUrl() (reads CASCADE_DASHBOARD_URL env var)
  • Progress monitorProgressMonitorConfig gets a runLink optional field; monitor appends footer on each tick; setRunId() method lets adapter inject the run ID once it's created
  • AdapterbuildProgressMonitorConfig passes runLink config when enabled; injects CASCADE_RUN_LINKS_ENABLED, CASCADE_DASHBOARD_URL, CASCADE_ENGINE_LABEL, CASCADE_MODEL, CASCADE_PROJECT_ID, CASCADE_WORK_ITEM_ID, CASCADE_RUN_ID env vars into subprocess secrets for native-tool backends
  • Router ack messages — All three platform adapters (Trello, GitHub, JIRA) append buildWorkItemRunsLink() footer to ack comments when runLinksEnabled is true
  • Agent gadgetspostComment, postPRComment, createPR, createPRReview read env vars and append run link footer when CASCADE_RUN_LINKS_ENABLED=true
  • Dashboard UI — Added "Enable run links" checkbox to project general settings form
  • CLI — Added --run-links-enabled / --no-run-links-enabled flag to cascade projects update
  • Tests — 20 unit tests for src/utils/runLink.ts covering all exported functions

Link format

---
🕵️ claude-code · claude-haiku-4.5 · [run details](https://dashboard.example.com/runs/<runId>)

At ack time (before runId exists), links point to the work-item-runs page instead.

Configuration

  1. Set CASCADE_DASHBOARD_URL=https://your-dashboard.com in the deployment environment
  2. Enable per project: cascade projects update <id> --run-links-enabled
  3. Or via the Dashboard UI: Project Settings → General → Enable run links checkbox

Key decisions

  • Off by defaultrun_links_enabled must be explicitly enabled per project
  • Graceful no-op — if CASCADE_DASHBOARD_URL is unset or run_links_enabled is false, no links are generated and no errors occur
  • Work-item-runs link at ack time — ack messages use the work-item-runs page since the run ID doesn't exist yet at router time
  • Env-var bridge — native-tool subprocess agents (claude-code/codex/opencode) receive run link context via injected env vars (CASCADE_RUN_LINKS_ENABLED etc.)

Test plan

  • Unit tests for buildRunLink, buildWorkItemRunsLink, shortenModelName, getDashboardUrl — all 20 passing
  • All 4619 existing tests pass
  • TypeScript type check passes (zero errors)
  • Lint passes (zero errors)
  • Manual: Set CASCADE_DASHBOARD_URL, enable on project, trigger a run, verify links in ack/progress/PR comments

🤖 Generated with Claude Code

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

Well-structured feature with clean layering from DB through config to runtime. One correctness issue in the GitHub ack path and a maintainability note on duplicated code.

Code Issues

Should Fix

  1. src/router/adapters/github.ts:279-300 — Run link missing from actual GitHub PR ack comment

    The GitHub PR ack comment is posted without the run link (via postGitHubPRAckpostGitHubAck on line 279-288), then the returned message field is updated with the run link after the comment is already on GitHub (lines 289-300). The actual comment the user sees on the PR will not contain the run link — only the internal metadata is updated.

    Compare with:

    • The PM-focused path in the same file (lines 274-276) which correctly appends the link before calling postPMAck
    • The Trello adapter which appends the link before calling postTrelloAck
    • The JIRA adapter which appends the link before calling postJiraAck

    Fix: Pass the run link config into postGitHubPRAck so it can include the footer in the message before posting, or generate the message with the footer before calling postGitHubPRAck.

  2. Gadget files — buildRunLinkFooter() duplicated 4 times

    The buildRunLinkFooter() function is copy-pasted in:

    • src/gadgets/github/core/createPR.ts
    • src/gadgets/github/core/createPRReview.ts
    • src/gadgets/github/core/postPRComment.ts
    • src/gadgets/pm/core/postComment.ts (with minor workItemId param variation)

    All 4 copies read the same set of env vars and call the same buildRunLink/buildWorkItemRunsLink functions. Consider extracting a shared buildRunLinkFooterFromEnv(workItemId?: string) in src/utils/runLink.ts to keep the env-var-reading logic in one place and prevent drift during future changes.

Everything Else Looks Good

  • DB migration, schema, Drizzle model, and journal entry are all consistent
  • Config mapper, projects repository, and Zod schema are properly extended
  • Progress monitor's setRunId() and footer-building logic are correct
  • Env-var bridge for subprocess agents (claude-code/codex) is well-designed
  • CLI flag uses allowNo: true for clean --run-links-enabled/--no-run-links-enabled UX
  • Dashboard checkbox is properly wired
  • Unit tests cover all exported functions with good edge cases
  • All CI checks pass

…cate buildRunLinkFooter

- Fix correctness bug where GitHub PR ack comment was posted without the
  run link footer. Previously the link was appended to the internal
  AckResult.message *after* the comment was already on GitHub, so users
  never saw it. Now the message is built with the run link before calling
  postGitHubPRAck, matching the Trello/JIRA/PM-focused paths.

- Extract shared buildRunLinkFooterFromEnv(workItemId?) to src/utils/runLink.ts
  and replace the 4 identical copies in createPR.ts, createPRReview.ts,
  postPRComment.ts, and postComment.ts, preventing future drift.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 14, 2026

Thanks for the detailed review @nhopeatall! Both issues are addressed in the latest commit.

Issue 1 (GitHub PR ack missing run link): Fixed the correctness bug. The message is now built with the run link footer before calling postGitHubPRAck, so the actual GitHub comment includes the link. Added a messageOverride parameter to postGitHubPRAck — when the caller provides a pre-built message, it's used directly; otherwise the function generates one as before. This matches how Trello, JIRA, and the PM-focused path in the same file work.

Issue 2 (duplicated buildRunLinkFooter): Extracted buildRunLinkFooterFromEnv(workItemId?: string) to src/utils/runLink.ts and replaced all 4 copies. The optional workItemId parameter covers the PM gadget's variation (which needed to pass a specific work item ID rather than reading CASCADE_WORK_ITEM_ID from the env). All env-var-reading logic is now in one place.

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

Clean, well-structured feature addition. The run links implementation follows existing patterns consistently across all layers (DB schema → config mapper → Zod schema → API → CLI → Dashboard UI → adapter/gadget runtime). The feature is properly gated (off by default, graceful no-op when CASCADE_DASHBOARD_URL is unset), and the env-var bridge for subprocess agents is well thought out.

All 5 CI checks pass. No blocking or should-fix issues found.

Minor Observations (non-blocking)

  • Test coverage gap for buildRunLinkFooterFromEnv: This is the primary integration function used by all 4 gadgets (createPR, createPRReview, postPRComment, postComment), but the test file only covers the pure utility functions it delegates to. Adding tests for the env-var-driven orchestration logic would improve confidence in the subprocess integration path.

  • Redundant extractGitHubContext call in GitHub adapter: When runLinksEnabled && event.workItemId is true, postAck calls extractGitHubContext + generateAckMessage to build githubAckMessage, then passes it as messageOverride to postGitHubPRAck — which also calls extractGitHubContext (though the result is discarded since messageOverride takes precedence). Not a bug, just a minor inefficiency.

@aaight aaight merged commit e65c909 into dev Mar 14, 2026
6 checks passed
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