Skip to content

feat: skill follow-up suggestions to improve dbt experience#546

Merged
anandgupta42 merged 9 commits intomainfrom
feat/skill-followup-suggestions
Mar 29, 2026
Merged

feat: skill follow-up suggestions to improve dbt experience#546
anandgupta42 merged 9 commits intomainfrom
feat/skill-followup-suggestions

Conversation

@anandgupta42
Copy link
Copy Markdown
Contributor

@anandgupta42 anandgupta42 commented Mar 28, 2026

What does this PR do?

Adds contextual "What's Next?" follow-up suggestions after skill execution to turn one-shot skill runs into conversational sessions. Also consolidates altimate-dbt build-project into altimate-dbt build (no args = project build).

Changes:

  • New: packages/opencode/src/skill/followups.tsSkillFollowups module mapping 12 skills to contextual next steps
  • Modified: packages/opencode/src/tool/skill.ts — Prepends follow-up suggestions before <skill_content> (truncation-safe)
  • Modified: packages/dbt-tools/src/commands/build.tsbuild without --model now builds entire project
  • Telemetry: Added has_followups and followup_count to skill_used event
  • Tests: 21 new tests (unit + integration + e2e)

Type of change

  • New feature (non-breaking change which adds functionality)
  • Bug fix
  • Breaking change
  • Documentation
  • Refactoring

Issue for this PR

Closes #552

How did you verify your code works?

  • All 38 skill tests pass (bun test test/skill/)
  • All 45 skill-related tests pass (unit + integration + e2e)
  • 5367/5367 tests pass, 0 failures across 276 files
  • TypeScript typecheck passes (turbo typecheck — 5/5 packages)
  • Prettier formatting passes
  • Marker guard passes for this PR's changes
  • Follow-ups placed before <skill_content> — survives output truncation
  • Unknown/custom skills get no follow-ups (empty string)
  • No skill suggests itself as a follow-up (validated in tests)

Checklist

  • I have performed a self-review of my own code
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have run the linters and fixed any issues
  • I have run the marker check for upstream-shared files

mdesmet and others added 6 commits March 25, 2026 15:29
`altimate-dbt build` without arguments now builds the whole project via
`unsafeBuildProjectImmediately`, replacing the need for the separate
`build-project` command. Updated all dbt skill references accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers: no-model → project build, --model → single model, --downstream flag.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p text, add stderr test

- Remove `build-project` from command map and switch case in `index.ts`
  (now redundant since `build` without `--model` does the same thing)
- Update `build` help text to reflect optional `--model`
- Remove unused `project` import from `build.test.ts`
- Add test for `format()` stderr error path
- Fix comment alignment in all 5 `altimate-dbt-commands.md` reference files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… type

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…t-run churn

Telemetry analysis showed 78% of users churn after a single 2.4-minute session,
mostly dbt developers who run one skill and leave. Users who reach warehouse/schema
tools retain at 24.8% vs 3.3% for those who don't.

This adds contextual "What's Next?" suggestions after skill execution:
- Maps each skill to relevant follow-up skills (e.g., `dbt-develop` → `dbt-test`, `dbt-docs`)
- Includes a warehouse discovery nudge to bridge non-warehouse users
- Appended after `</skill_content>` so it doesn't interfere with skill parsing
- Covers all dbt skills, SQL skills, and data quality skills (12 skills total)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

This PR unifies CLI build semantics by replacing build-project with a context-aware build (project or model based on --model), adds a SkillFollowups system for suggested next steps, wires followups into skill output and telemetry, and adds tests for build and followups.

Changes

Cohort / File(s) Summary
Documentation
\.opencode/skills/dbt-analyze/SKILL.md, \.opencode/skills/dbt-analyze/references/altimate-dbt-commands.md, \.opencode/skills/dbt-develop/references/altimate-dbt-commands.md, \.opencode/skills/dbt-docs/references/altimate-dbt-commands.md, \.opencode/skills/dbt-test/references/altimate-dbt-commands.md, \.opencode/skills/dbt-troubleshoot/references/altimate-dbt-commands.md
Replaced altimate-dbt build-project with altimate-dbt build (full-project) and clarified altimate-dbt build --model <name> [--downstream] for single-model builds.
Build Command Logic
packages/dbt-tools/src/commands/build.ts
When --model is absent, build() now delegates to the project build path instead of erroring; model-specific flow unchanged.
CLI Routing & Help
packages/dbt-tools/src/index.ts
Removed build-project command branch and updated USAGE.commands.build help to cover both full-project and single-model builds.
Build Command Tests
packages/dbt-tools/test/build.test.ts
New tests covering project build (no --model), model build, --downstream handling, and error propagation from adapter.
Follow-up Suggestions Core
packages/opencode/src/skill/followups.ts
New exported SkillFollowups namespace with Suggestion interface, FOLLOWUPS mapping, and get()/format() helpers to produce static follow-up suggestions.
Skill Tool Integration
packages/opencode/src/tool/skill.ts
Prepends formatted follow-ups to skill output when present and adds has_followups / followup_count to telemetry payload.
Telemetry Schema
packages/opencode/src/altimate/telemetry/index.ts
Added has_followups: boolean and followup_count: number fields to Telemetry.Event variant type: "skill_used".
Follow-up Tests
packages/opencode/test/skill/followups.test.ts, packages/opencode/test/skill/skill-followups-integration.test.ts
Unit and integration tests validating follow-up retrieval, formatting, assembly ordering, and tool output composition.
Skill Tool E2E Tests
packages/opencode/test/tool/skill.test.ts
End-to-end tests asserting follow-up block appears before <skill_content ...> when present and is omitted when not.

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant BuildCmd as packages/dbt-tools/src/commands/build.ts
  participant Adapter as DBTProjectIntegrationAdapter
  CLI->>BuildCmd: altimate-dbt build [--model <name>] [--downstream]
  alt Without --model
    BuildCmd->>Adapter: unsafeBuildProjectImmediately()
    Adapter-->>BuildCmd: result (stdout / stderr)
  else With --model
    BuildCmd->>Adapter: unsafeBuildModelImmediately({modelName, plusOperatorRight})
    Adapter-->>BuildCmd: result (stdout / stderr)
  end
  BuildCmd-->>CLI: formatted result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • suryaiyer95
  • mdesmet

Poem

🐇 I nibble through docs and hop through code,
One build now knows the path to go.
Follow-ups line the grassy trail,
Tests cheer on each passing tale.
Hooray — small hops that help us grow!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding follow-up suggestions to skills for improved dbt experience, which is the primary feature in this PR.
Description check ✅ Passed The PR description comprehensively covers objectives, changes, testing, and verification with clear structure aligned to the template sections.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/skill-followup-suggestions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@anandgupta42 anandgupta42 changed the title feat: skill follow-up suggestions to reduce first-run churn feat: skill follow-up suggestions to improve dbt experience Mar 28, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/opencode/src/tool/skill.ts (1)

168-183: ⚠️ Potential issue | 🟠 Major

Follow-ups can be dropped by default output truncation

Because follow-ups are appended at Line 182 (tail of output), they are the first content lost when tool output is head-truncated. That makes “What’s Next?” unreliable exactly on large skills.

Possible mitigation (keep follow-ups outside <skill_content> but place earlier)
-        output: [
-          `<skill_content name="${skill.name}">`,
+        output: [
+          ...(followups ? [followups, ""] : []),
+          `<skill_content name="${skill.name}">`,
           `# Skill: ${skill.name}`,
           "",
           skill.content.trim(),
@@
           "</skill_files>",
           "</skill_content>",
-          followups,
         ].join("\n"),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/src/tool/skill.ts` around lines 168 - 183, The followups
string is appended at the end of the assembled output array (see output array
building where skill.name, skill.content and files are joined) which makes
followups the first thing lost when the tool output is head-truncated; move
followups out of the closing "</skill_content>" tail and insert it earlier (for
example immediately after the "Note: file list is sampled." or immediately
before "<skill_files>") so followups remains near the head of the output while
still keeping the XML-like <skill_content> block intact; update the code that
constructs output (the output array that references skill.name, skill.content,
files and followups) to place followups at that earlier position.
🧹 Nitpick comments (2)
packages/dbt-tools/src/commands/build.ts (1)

39-45: Consider improving error detection for full-project builds.

The format() function treats any stderr output as an error, but the TODO notes dbt writes info/progress logs to stderr on success. This could cause false failures for project() calls which may produce more stderr output than single-model builds.

Since this is pre-existing behavior and acknowledged, no immediate action required, but worth monitoring after this change expands the use of project().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/dbt-tools/src/commands/build.ts` around lines 39 - 45, The format()
helper treating any stderr as an error is causing false failures; update format
(and associated callers like project()) to treat stderr as an error only when it
contains real error markers (e.g., lines with "ERROR" / "Error" / "Traceback")
or when an exit/return code indicates failure; specifically, adjust
format(result?: CommandProcessResult) to (1) prefer an explicit exit code check
if CommandProcessResult has been extended (use result.exitCode or result.status
to decide error vs success), and otherwise (2) scan result.stderr for
error-level keywords before returning { error: ... }, leaving benign dbt
progress lines ignored. Ensure you update any types/usages of
CommandProcessResult if you add an exitCode field.
packages/opencode/src/skill/followups.ts (1)

156-158: get() exposes mutable shared state

On Line 157, get() returns the original array/object references from FOLLOWUPS. A caller can mutate them and unintentionally alter global follow-up behavior for later calls.

Proposed hardening
-  export function get(skillName: string): Suggestion[] {
-    return FOLLOWUPS[skillName] ?? []
-  }
+  export function get(skillName: string): ReadonlyArray<Readonly<Suggestion>> {
+    return (FOLLOWUPS[skillName] ?? []).map((s) => ({ ...s }))
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/src/skill/followups.ts` around lines 156 - 158, get()
currently returns the actual array/object from FOLLOWUPS exposing mutable shared
state; change it to return a defensive copy instead of the original reference by
cloning the array and its suggestion objects (e.g., map over
FOLLOWUPS[skillName] and shallow-clone each Suggestion or use a safe deep clone
if Suggestion contains nested objects) so callers cannot mutate FOLLOWUPS;
update the get function to return the cloned array (or [] when undefined) while
keeping the function signature the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/test/skill/skill-followups-integration.test.ts`:
- Around line 8-40: The test is asserting SkillFollowups.format(...) directly
instead of verifying the integration point where follow-ups are appended to tool
output; update the test to invoke the actual SkillTool execution path (call
SkillTool.execute or the public method that runs the tool for "dbt-develop"
within the Instance.provide context) and assert the returned tool output
contains the skill content marker (e.g., "</skill_content>") followed by the
formatted follow-ups (use SkillFollowups.format("dbt-develop") as the expected
suffix), replacing direct calls to SkillFollowups.format in the assertions so
the test validates SkillTool.execute's output assembly.

---

Outside diff comments:
In `@packages/opencode/src/tool/skill.ts`:
- Around line 168-183: The followups string is appended at the end of the
assembled output array (see output array building where skill.name,
skill.content and files are joined) which makes followups the first thing lost
when the tool output is head-truncated; move followups out of the closing
"</skill_content>" tail and insert it earlier (for example immediately after the
"Note: file list is sampled." or immediately before "<skill_files>") so
followups remains near the head of the output while still keeping the XML-like
<skill_content> block intact; update the code that constructs output (the output
array that references skill.name, skill.content, files and followups) to place
followups at that earlier position.

---

Nitpick comments:
In `@packages/dbt-tools/src/commands/build.ts`:
- Around line 39-45: The format() helper treating any stderr as an error is
causing false failures; update format (and associated callers like project()) to
treat stderr as an error only when it contains real error markers (e.g., lines
with "ERROR" / "Error" / "Traceback") or when an exit/return code indicates
failure; specifically, adjust format(result?: CommandProcessResult) to (1)
prefer an explicit exit code check if CommandProcessResult has been extended
(use result.exitCode or result.status to decide error vs success), and otherwise
(2) scan result.stderr for error-level keywords before returning { error: ... },
leaving benign dbt progress lines ignored. Ensure you update any types/usages of
CommandProcessResult if you add an exitCode field.

In `@packages/opencode/src/skill/followups.ts`:
- Around line 156-158: get() currently returns the actual array/object from
FOLLOWUPS exposing mutable shared state; change it to return a defensive copy
instead of the original reference by cloning the array and its suggestion
objects (e.g., map over FOLLOWUPS[skillName] and shallow-clone each Suggestion
or use a safe deep clone if Suggestion contains nested objects) so callers
cannot mutate FOLLOWUPS; update the get function to return the cloned array (or
[] when undefined) while keeping the function signature the same.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6b0816f9-ec8e-47df-afc4-15eaf1fa6227

📥 Commits

Reviewing files that changed from the base of the PR and between 33c331b and 970b3c7.

📒 Files selected for processing (13)
  • .opencode/skills/dbt-analyze/SKILL.md
  • .opencode/skills/dbt-analyze/references/altimate-dbt-commands.md
  • .opencode/skills/dbt-develop/references/altimate-dbt-commands.md
  • .opencode/skills/dbt-docs/references/altimate-dbt-commands.md
  • .opencode/skills/dbt-test/references/altimate-dbt-commands.md
  • .opencode/skills/dbt-troubleshoot/references/altimate-dbt-commands.md
  • packages/dbt-tools/src/commands/build.ts
  • packages/dbt-tools/src/index.ts
  • packages/dbt-tools/test/build.test.ts
  • packages/opencode/src/skill/followups.ts
  • packages/opencode/src/tool/skill.ts
  • packages/opencode/test/skill/followups.test.ts
  • packages/opencode/test/skill/skill-followups-integration.test.ts

Comment on lines +8 to +40
test("skill tool output includes follow-up suggestions for skills with followups", async () => {
await using tmp = await tmpdir({
git: true,
init: async (dir) => {
const skillDir = path.join(dir, ".opencode", "skill", "dbt-develop")
await Bun.write(
path.join(skillDir, "SKILL.md"),
`---
name: dbt-develop
description: Create dbt models.
---

# dbt Model Development

Instructions here.
`,
)
},
})

await Instance.provide({
directory: tmp.path,
fn: async () => {
const skill = await Skill.get("dbt-develop")
expect(skill).toBeDefined()

// Verify followups exist for this skill
const followups = SkillFollowups.format("dbt-develop")
expect(followups).toContain("## What's Next?")
expect(followups).toContain("dbt-test")
expect(followups).toContain("dbt-docs")
},
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

These tests don’t verify the actual SkillTool integration path

At Line 35 and Line 70, assertions target SkillFollowups.format(...) directly, but the new behavior lives in SkillTool.execute output assembly (appending after </skill_content>). This misses the real integration contract and can let regressions slip.

Also applies to: 43-74

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/skill/skill-followups-integration.test.ts` around
lines 8 - 40, The test is asserting SkillFollowups.format(...) directly instead
of verifying the integration point where follow-ups are appended to tool output;
update the test to invoke the actual SkillTool execution path (call
SkillTool.execute or the public method that runs the tool for "dbt-develop"
within the Instance.provide context) and assert the returned tool output
contains the skill content marker (e.g., "</skill_content>") followed by the
formatted follow-ups (use SkillFollowups.format("dbt-develop") as the expected
suffix), replacing direct calls to SkillFollowups.format in the assertions so
the test validates SkillTool.execute's output assembly.

@gitguardian
Copy link
Copy Markdown

gitguardian bot commented Mar 29, 2026

⚠️ GitGuardian has uncovered 2 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
29254674 Triggered Generic Password ae7ecca packages/opencode/test/altimate/connections.test.ts View secret
29254673 Triggered Generic Password ae7ecca packages/opencode/test/altimate/connections.test.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secrets safely. Learn here the best practices.
  3. Revoke and rotate these secrets.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

anandgupta42 and others added 2 commits March 28, 2026 17:37
…table `get()`

- Move follow-up suggestions before `<skill_content>` so they survive output truncation
- Add `has_followups` and `followup_count` to `skill_used` telemetry event
- Return `readonly Suggestion[]` via `Object.freeze()` from `get()` to prevent shared state mutation
- Rewrite integration tests to verify followups appear before `<skill_content>` in output assembly
- Wrap custom return block in `altimate_change` markers for upstream safety

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ecute`

- Test that `dbt-develop` skill output includes follow-ups before `<skill_content>`
- Test that unmapped skills produce no follow-up section
- Both tests invoke the real `SkillTool.execute` path end-to-end

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/opencode/src/tool/skill.ts (1)

21-24: ⚠️ Potential issue | 🟡 Minor

Builtin skills can be misclassified as project in telemetry.

classifySkillSource does not recognize builtin: locations (used at Line 119), so builtin skills can be emitted with the wrong skill_source.

🔧 Proposed fix
 function classifySkillSource(location: string): "builtin" | "global" | "project" {
-  if (location.includes("node_modules") || location.includes(".altimate/builtin")) return "builtin"
+  if (
+    location.startsWith("builtin:") ||
+    location.includes("node_modules") ||
+    location.includes(".altimate/builtin") ||
+    location.includes(`${path.sep}.altimate${path.sep}builtin`)
+  ) {
+    return "builtin"
+  }
   if (location.startsWith(os.homedir())) return "global"
   return "project"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/src/tool/skill.ts` around lines 21 - 24, The
classifySkillSource function fails to treat locations prefixed with "builtin:"
as builtin, causing telemetry mislabeling; update classifySkillSource to first
check for the "builtin:" prefix (e.g., location.startsWith("builtin:")) before
the existing node_modules and .altimate/builtin checks so any
"builtin:"-prefixed paths are returned as "builtin" (keep the function signature
and return types intact).
🧹 Nitpick comments (1)
packages/opencode/src/skill/followups.ts (1)

156-158: get() is only shallowly immutable right now.

Freezing the array prevents push/pop, but Suggestion objects are still mutable and can mutate shared follow-up state.

🧱 Proposed hardening
+  const EMPTY_SUGGESTIONS: readonly Suggestion[] = Object.freeze([])
+
   export function get(skillName: string): readonly Suggestion[] {
-    return Object.freeze(FOLLOWUPS[skillName] ?? [])
+    const suggestions = FOLLOWUPS[skillName]
+    if (!suggestions) return EMPTY_SUGGESTIONS
+    return Object.freeze(suggestions.map((s) => Object.freeze({ ...s })))
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/src/skill/followups.ts` around lines 156 - 158, The get
function currently returns Object.freeze(FOLLOWUPS[skillName] ?? []) which only
shallow-freezes the array but leaves Suggestion objects mutable; change get to
return deeply immutable suggestions by either (A) deep-freezing each Suggestion
object and any nested mutable fields when FOLLOWUPS is initialized, or (B)
cloning and freezing on read (e.g., map over FOLLOWUPS[skillName] to
structuredClone each Suggestion and Object.freeze nested objects) so callers of
get(skillName) cannot mutate shared Suggestion state; update references to get,
FOLLOWUPS, and the Suggestion type to ensure nested fields are also frozen or
cloned.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/opencode/src/tool/skill.ts`:
- Around line 21-24: The classifySkillSource function fails to treat locations
prefixed with "builtin:" as builtin, causing telemetry mislabeling; update
classifySkillSource to first check for the "builtin:" prefix (e.g.,
location.startsWith("builtin:")) before the existing node_modules and
.altimate/builtin checks so any "builtin:"-prefixed paths are returned as
"builtin" (keep the function signature and return types intact).

---

Nitpick comments:
In `@packages/opencode/src/skill/followups.ts`:
- Around line 156-158: The get function currently returns
Object.freeze(FOLLOWUPS[skillName] ?? []) which only shallow-freezes the array
but leaves Suggestion objects mutable; change get to return deeply immutable
suggestions by either (A) deep-freezing each Suggestion object and any nested
mutable fields when FOLLOWUPS is initialized, or (B) cloning and freezing on
read (e.g., map over FOLLOWUPS[skillName] to structuredClone each Suggestion and
Object.freeze nested objects) so callers of get(skillName) cannot mutate shared
Suggestion state; update references to get, FOLLOWUPS, and the Suggestion type
to ensure nested fields are also frozen or cloned.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 313adf5f-f87c-4e45-a654-55e447e542ae

📥 Commits

Reviewing files that changed from the base of the PR and between 970b3c7 and 930a417.

📒 Files selected for processing (4)
  • packages/opencode/src/altimate/telemetry/index.ts
  • packages/opencode/src/skill/followups.ts
  • packages/opencode/src/tool/skill.ts
  • packages/opencode/test/skill/skill-followups-integration.test.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/opencode/test/skill/skill-followups-integration.test.ts

@anandgupta42 anandgupta42 merged commit 384335d into main Mar 29, 2026
13 of 14 checks passed
anandgupta42 added a commit that referenced this pull request Mar 29, 2026
Introduces a strategy for handling bug fixes to upstream code:

**`upstream_fix:` convention:**
- Tag in marker description distinguishes temporary bug fixes from
  permanent feature additions
- Before each upstream merge, run `--audit-fixes` to review which
  fixes we're carrying and whether upstream has shipped their own

**`--audit-fixes` flag on analyze.ts:**
- Lists all `upstream_fix:` markers with file locations and descriptions
- Prints merge review checklist

**Retagged 3 existing upstream bug fixes:**
- `locale.ts` — days/hours duration swap
- `command/index.ts` — placeholder lexicographic sort
- `home.tsx` — beginner UI race condition

**Code review fixes from #546:**
- Guard `--downstream` without `--model` (returns error instead of
  silently running full project build)
- Remove unused `condition` field from `Suggestion` interface
- Add test for `--downstream` error case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
anandgupta42 added a commit that referenced this pull request Mar 29, 2026
…un crash resilience (#555)

* feat: add `upstream_fix:` marker convention with `--audit-fixes` command

Introduces a strategy for handling bug fixes to upstream code:

**`upstream_fix:` convention:**
- Tag in marker description distinguishes temporary bug fixes from
  permanent feature additions
- Before each upstream merge, run `--audit-fixes` to review which
  fixes we're carrying and whether upstream has shipped their own

**`--audit-fixes` flag on analyze.ts:**
- Lists all `upstream_fix:` markers with file locations and descriptions
- Prints merge review checklist

**Retagged 3 existing upstream bug fixes:**
- `locale.ts` — days/hours duration swap
- `command/index.ts` — placeholder lexicographic sort
- `home.tsx` — beginner UI race condition

**Code review fixes from #546:**
- Guard `--downstream` without `--model` (returns error instead of
  silently running full project build)
- Remove unused `condition` field from `Suggestion` interface
- Add test for `--downstream` error case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: handle Bun segfault during CI test cleanup

Bun 1.3.x has a known crash (segfault/SIGTERM) during process cleanup
after all tests pass successfully. This caused flaky CI failures where
5362 tests pass but the job reports failure due to exit code 143.

The fix captures test output and checks the actual pass/fail summary
instead of relying on Bun's exit code:
- Real test failures (N fail > 0): exit 1
- No test summary at all (Bun crashed before running): exit 1
- All tests pass but Bun crashes during cleanup: emit warning, exit 0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use file redirect instead of tee for Bun crash resilience

The previous approach using `tee` failed because when Bun segfaults,
the pipe breaks and tee doesn't flush output to the file. The grep
then finds no summary and reports "crashed before producing results"
even though all tests passed.

Fix: redirect bun output to file directly (`> file 2>&1 || true`),
then `cat` it for CI log visibility. Use portable `awk` instead of
`grep -oP` for summary extraction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
anandgupta42 added a commit that referenced this pull request Mar 29, 2026
Merged origin/main which added:
- `has_followups` / `followup_count` fields to `skill_used` telemetry (#546)
- `isRealFailure` and `findings` telemetry in sql-analyze (#545)

Conflict resolution:
- telemetry/index.ts: kept both `trigger` (ours) and `has_followups`/`followup_count` (main)
- tool/skill.ts: kept followup logic (main) + trigger classification (ours)
- sql-analyze.ts: kept findings telemetry (main) + progressive suggestions (ours)
- Updated plan-skill-telemetry.test.ts to include new `has_followups`/`followup_count` fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: skill follow-up suggestions after skill execution

3 participants