Skip to content

feat(claude): install sdd slash commands#352

Merged
Alan-TheGentleman merged 5 commits intomainfrom
feat/claude-slash-commands
Apr 21, 2026
Merged

feat(claude): install sdd slash commands#352
Alan-TheGentleman merged 5 commits intomainfrom
feat/claude-slash-commands

Conversation

@Alan-TheGentleman
Copy link
Copy Markdown
Contributor

🔗 Linked Issue

Closes #337


🏷️ PR Type

What kind of change does this PR introduce?

  • type:bug — Bug fix (non-breaking change that fixes an issue)
  • type:feature — New feature (non-breaking change that adds functionality)
  • type:docs — Documentation only
  • type:refactor — Code refactoring (no functional changes)
  • type:chore — Build, CI, or tooling changes
  • type:breaking-change — Breaking change (fix or feature that changes existing behavior)

📝 Summary

  • Enables Claude support for managed SDD slash commands under ~/.claude/commands.
  • Adds Claude-specific command assets for the full SDD command set.
  • Makes command asset resolution agent-aware across install/uninstall and regression tests.

📂 Changes

File / Area What Changed
internal/agents/claude/adapter.go Enabled slash-command support and defined the Claude commands directory
internal/assets/claude/commands/* Added Claude-compatible SDD command assets
internal/assets/commands.go Centralized agent-aware command asset lookup
internal/components/sdd/* Updated install/listing behavior and full command enumeration
internal/components/uninstall/* Verified managed Claude command cleanup preserves user commands
testdata/golden/sdd-claude-cmd-*.golden Added golden coverage for the Claude command set

🧪 Test Plan

Unit Tests

go test ./internal/components/sdd ./internal/components/uninstall ./internal/components ./internal/assets ./internal/agents/claude

E2E Tests (Docker required)

Not run
  • Unit tests pass (go test ./...)
  • E2E tests pass (cd e2e && ./docker-test.sh)
  • Manually tested locally

🤖 Automated Checks

The following checks run automatically on this PR:

Check Status Description
Check Issue Reference PR body must contain Closes/Fixes/Resolves #N
Check Issue Has status:approved Linked issue must have been approved before work began
Check PR Has type:* Label Exactly one type:* label must be applied
Unit Tests CI will validate the change
E2E Tests CI will validate the change

✅ Contributor Checklist

  • PR is linked to an issue with status:approved
  • I have added the appropriate type:* label to this PR
  • Unit tests pass (go test ./...)
  • E2E tests pass (cd e2e && ./docker-test.sh)
  • I have updated documentation if necessary
  • My commits follow Conventional Commits format
  • My commits do not include Co-Authored-By trailers

💬 Notes for Reviewers

  • This keeps command asset selection agent-aware so Claude does not implicitly depend on OpenCode-only assets.

Copilot AI review requested due to automatic review settings April 21, 2026 14:39
@Alan-TheGentleman Alan-TheGentleman added the type:feature New feature label Apr 21, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enables managed SDD slash-command installation for the Claude agent by adding Claude-specific command assets and making command asset lookup agent-aware across install/uninstall and golden tests.

Changes:

  • Enabled slash-command support for the Claude adapter and defined ~/.claude/commands as its commands directory.
  • Added Claude-formatted SDD command assets (internal/assets/claude/commands/sdd-*.md) and golden fixtures for them.
  • Centralized agent-aware embedded command asset selection via assets.SDDCommandsAssetDir() and updated SDD inject/uninstall to use it.

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
internal/agents/claude/adapter.go Turns on slash-command support and returns Claude commands dir path.
internal/agents/claude/adapter_test.go Adds coverage asserting slash-command support and commands dir.
internal/assets/commands.go Adds agent-aware command asset directory resolver (Claude vs default).
internal/assets/claude/commands/sdd-*.md New Claude-native SDD slash commands.
internal/assets/assets_test.go Extends embedded-asset layout/readability checks to include Claude commands.
internal/components/sdd/inject.go Loads slash-command assets from agent-specific embedded directory.
internal/components/sdd/inject_test.go Verifies Claude command files are written and contain Claude frontmatter.
internal/components/uninstall/service.go Removes managed command files using agent-specific embedded directory.
internal/components/uninstall/service_test.go Ensures Claude uninstall removes only managed commands and preserves user commands.
internal/components/sdd/commands.go Updates OpenCode command enumeration to include sdd-explore.
internal/components/sdd/commands_test.go Tightens command-set expectations to the full 9-command SDD set.
internal/components/golden_test.go Adds Claude command golden assertions; ensures OpenCode expected command set includes sdd-onboard.
testdata/golden/sdd-claude-cmd-*.golden New golden fixtures for the Claude command set.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The shell substitution uses basename $(pwd) without quoting the pwd output. If the working directory path contains spaces, basename will receive multiple arguments and the project name extraction can fail. Prefer quoting (e.g., basename "$(pwd)" or basename "$PWD") inside the substitution.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$(pwd)")"`

Copilot uses AI. Check for mistakes.

CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The Current project shell substitution uses basename $(pwd) without quoting; this breaks when the path contains spaces. Quote the pwd result (or use $PWD) so command rendering is robust.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$PWD")"`

Copilot uses AI. Check for mistakes.

CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The Current project line uses basename $(pwd) without quoting, which can fail for working directories containing spaces. Quote the pwd output (or use $PWD) inside the substitution.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$PWD")"`

Copilot uses AI. Check for mistakes.

CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The shell substitution uses basename $(pwd) without quoting. In directories with spaces this can produce the wrong project name or error. Quote the pwd output (or use $PWD) inside the basename call.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$PWD")"`

Copilot uses AI. Check for mistakes.

CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The Current project shell substitution uses basename $(pwd) without quoting; this breaks for paths with spaces. Quote the pwd output (or use $PWD) in the basename call.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$(pwd)")"`

Copilot uses AI. Check for mistakes.

CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The Current project shell substitution uses basename $(pwd) without quoting; if the path contains spaces, basename can mis-handle arguments. Quote the pwd output (or use $PWD) inside the basename call.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$(pwd)")"`

Copilot uses AI. Check for mistakes.

CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The Current project shell substitution uses basename $(pwd) without quoting; paths with spaces will break. Quote the pwd output (or use $PWD) in the basename call.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$PWD")"`

Copilot uses AI. Check for mistakes.

CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The Current project shell substitution uses basename $(pwd) without quoting. This can fail when the working directory contains spaces; quote the pwd output (or use $PWD) inside the basename call.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$PWD")"`

Copilot uses AI. Check for mistakes.

CONTEXT:
- Working directory: !`echo -n "$(pwd)"`
- Current project: !`echo -n "$(basename $(pwd))"`
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The Current project shell substitution uses basename $(pwd) without quoting; directories with spaces can cause incorrect parsing. Quote the pwd output (or use $PWD) inside the basename call.

Suggested change
- Current project: !`echo -n "$(basename $(pwd))"`
- Current project: !`echo -n "$(basename "$PWD")"`

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings April 21, 2026 15:15
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings April 21, 2026 15:47
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 35 out of 35 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +86 to +98
// GitHub Actions injects a repository-scoped GITHUB_TOKEN into CI. When that
// token is forwarded into our Linux E2E containers, the public engram releases
// endpoint can respond 401/403 for a different repository. Retry anonymously
// before failing because the release metadata is public.
if token != "" && (status == http.StatusUnauthorized || status == http.StatusForbidden) {
version, _, retryErr := fetchLatestEngramVersionRequest("")
if retryErr == nil {
return version, nil
}
}

return "", err
}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

In fetchLatestEngramVersion(), if the token-authenticated request returns 401/403 and the anonymous retry fails for a different reason, the function currently returns the original error from the first attempt. That can be misleading and make troubleshooting harder. Consider returning the retry error (or wrapping both errors) when the retry is attempted and fails.

Copilot uses AI. Check for mistakes.
Comment on lines 79 to +98
func fetchLatestEngramVersion() (string, error) {
token := githubToken()
version, status, err := fetchLatestEngramVersionRequest(token)
if err == nil {
return version, nil
}

// GitHub Actions injects a repository-scoped GITHUB_TOKEN into CI. When that
// token is forwarded into our Linux E2E containers, the public engram releases
// endpoint can respond 401/403 for a different repository. Retry anonymously
// before failing because the release metadata is public.
if token != "" && (status == http.StatusUnauthorized || status == http.StatusForbidden) {
version, _, retryErr := fetchLatestEngramVersionRequest("")
if retryErr == nil {
return version, nil
}
}

return "", err
}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The PR title/description are focused on Claude SDD slash commands, but this change also modifies engram download behavior (GitHub API retry logic) and introduces new Qwen setup semantics. Consider splitting these engram-related changes into a separate PR (or update the PR description/linked issue to explicitly cover them) so the review scope matches the stated intent and risk surface.

Copilot uses AI. Check for mistakes.
@Alan-TheGentleman Alan-TheGentleman merged commit 8875a9c into main Apr 21, 2026
9 checks passed
@Alan-TheGentleman Alan-TheGentleman deleted the feat/claude-slash-commands branch April 21, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(agents/claude): enable slash commands and install SDD command set under ~/.claude/commands

2 participants