Skip to content

Commit 75adc11

Browse files
javoireclaude
andauthored
feat(skill): add Claude Code skill and stack skill install command (#67)
Add a Claude plugin marketplace structure so the repo can distribute a Claude Code skill that teaches Claude how to use the stack CLI. The new `stack skill install` command shells out to the claude CLI to add the marketplace and install the plugin. Also skip git-repo validation for `skill install` and `version` so they work outside git repositories. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ab85cea commit 75adc11

9 files changed

Lines changed: 191 additions & 0 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "stackinator",
3+
"owner": {
4+
"name": "javoire"
5+
},
6+
"plugins": [
7+
{
8+
"name": "stack",
9+
"source": "./plugins/stack",
10+
"description": "Stacked branch management skill for the stack CLI"
11+
}
12+
]
13+
}

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,25 @@ Or use the interactive helper:
105105
stack config set
106106
```
107107

108+
## Claude Code Skill
109+
110+
Stackinator includes a [Claude Code](https://claude.ai/code) skill that teaches Claude how to manage stacked branches.
111+
112+
### Quick install
113+
114+
```bash
115+
stack skill install
116+
```
117+
118+
### Manual install
119+
120+
In Claude Code, run:
121+
122+
```
123+
/plugin marketplace add javoire/stackinator
124+
/plugin install stack@stackinator
125+
```
126+
108127
## Documentation
109128

110129
- [How It Works](docs/how-it-works.md) - Stack tracking and sync algorithm

cmd/root.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ The tool helps you create, navigate, and sync stacked branches with minimal over
5454
// Set color output flag
5555
ui.SetNoColor(noColor)
5656

57+
// Skip git validation for commands that don't need it
58+
if cmd.Annotations["skipGitValidation"] == "true" {
59+
return
60+
}
61+
5762
// Validate we're in a git repository
5863
gitClient := git.NewGitClient()
5964
if _, err := gitClient.GetRepoRoot(); err != nil {

cmd/skill.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"os/exec"
7+
8+
"github.com/javoire/stackinator/internal/ui"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
var skillCmd = &cobra.Command{
13+
Use: "skill",
14+
Short: "Manage Claude Code skills",
15+
Long: `Manage Claude Code skills for the stack CLI.`,
16+
Annotations: map[string]string{
17+
"skipGitValidation": "true",
18+
},
19+
}
20+
21+
var skillInstallCmd = &cobra.Command{
22+
Use: "install",
23+
Short: "Install the stack skill for Claude Code",
24+
Long: `Install the stack skill so Claude Code knows how to use the stack CLI.
25+
26+
This requires the Claude Code CLI (claude) to be installed.
27+
See https://claude.ai/code for installation instructions.`,
28+
Annotations: map[string]string{
29+
"skipGitValidation": "true",
30+
},
31+
RunE: func(cmd *cobra.Command, args []string) error {
32+
return runSkillInstall()
33+
},
34+
}
35+
36+
func init() {
37+
skillCmd.AddCommand(skillInstallCmd)
38+
rootCmd.AddCommand(skillCmd)
39+
}
40+
41+
func runSkillInstall() error {
42+
if _, err := exec.LookPath("claude"); err != nil {
43+
return fmt.Errorf("claude CLI not found in PATH. Install it from https://claude.ai/code")
44+
}
45+
46+
fmt.Println("Adding stackinator marketplace...")
47+
addCmd := exec.Command("claude", "plugin", "marketplace", "add", "javoire/stackinator")
48+
addCmd.Stdout = os.Stdout
49+
addCmd.Stderr = os.Stderr
50+
if err := addCmd.Run(); err != nil {
51+
return fmt.Errorf("failed to add marketplace: %w", err)
52+
}
53+
54+
fmt.Println("Installing stack skill...")
55+
installCmd := exec.Command("claude", "plugin", "install", "stack@stackinator")
56+
installCmd.Stdout = os.Stdout
57+
installCmd.Stderr = os.Stderr
58+
if err := installCmd.Run(); err != nil {
59+
return fmt.Errorf("failed to install skill: %w", err)
60+
}
61+
62+
fmt.Println(ui.Success("Stack skill installed! Claude Code now knows how to use the stack CLI."))
63+
return nil
64+
}

cmd/skill_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package cmd
2+
3+
import (
4+
"os"
5+
"os/exec"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestRunSkillInstall_ClaudeNotFound(t *testing.T) {
12+
// Set PATH to empty so claude can't be found
13+
originalPath := os.Getenv("PATH")
14+
t.Setenv("PATH", "")
15+
defer func() { os.Setenv("PATH", originalPath) }()
16+
17+
// Clear the exec.LookPath cache by ensuring fresh lookup
18+
err := runSkillInstall()
19+
assert.Error(t, err)
20+
assert.Contains(t, err.Error(), "claude CLI not found")
21+
}
22+
23+
func TestRunSkillInstall_ClaudeFound(t *testing.T) {
24+
// Skip if claude is not installed
25+
if _, err := exec.LookPath("claude"); err != nil {
26+
t.Skip("claude CLI not installed, skipping integration test")
27+
}
28+
29+
// This would actually run the commands, so we just verify claude is found
30+
// A full integration test would require mocking exec.Command
31+
t.Log("claude CLI found in PATH")
32+
}

cmd/version.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ var versionCmd = &cobra.Command{
1717
Use: "version",
1818
Short: "Print version information",
1919
Long: `Print the version, commit hash, and build date of this stack binary.`,
20+
Annotations: map[string]string{
21+
"skipGitValidation": "true",
22+
},
2023
Run: func(cmd *cobra.Command, args []string) {
2124
fmt.Printf("stack version %s\n", version)
2225
fmt.Printf(" commit: %s\n", commit)

docs/commands.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,16 @@ Flags:
154154

155155
- `--prune` - Remove worktrees for branches with merged PRs
156156

157+
## `stack skill install`
158+
159+
Install the Claude Code skill so Claude knows how to use the stack CLI.
160+
161+
Requires the [Claude Code CLI](https://claude.ai/code) to be installed.
162+
163+
```bash
164+
stack skill install
165+
```
166+
157167
## `stack version`
158168

159169
Print version information.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "stack",
3+
"description": "Stacked branch management skill for the stack CLI",
4+
"version": "1.0.0"
5+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
name: stack
3+
description: Manage stacked branches with the stack CLI. Covers branch creation, navigation, syncing, and PR management.
4+
---
5+
6+
The `stack` CLI manages stacked branches and syncs them to GitHub PRs. Use this for working with dependent branches.
7+
8+
## Choosing Between `stack worktree` vs `stack new`
9+
10+
- **`stack worktree <branch>`** - Creates a separate git worktree directory at `~/.stack/worktrees/<repo>/<branch>`. Use when:
11+
- Starting a new feature from master
12+
- Want to work on multiple things in parallel without stashing
13+
- The current worktree has uncommitted changes you want to keep
14+
15+
- **`stack new <branch>`** - Creates a branch in the current worktree. Use when:
16+
- Building on top of the current feature branch (stacked PRs)
17+
- Already in a worktree and want to add dependent branches
18+
19+
## Common Commands
20+
21+
- `stack new <branch>` - Create new branch in the stack (use instead of `git checkout -b`)
22+
- `stack status` - Show stack structure with PR status (fetches from GitHub)
23+
- `stack show` - Show local stack structure (fast, no network)
24+
- `stack sync` - Sync branches and update PRs on GitHub
25+
- `stack up` / `stack down` - Navigate up/down the stack
26+
- `stack prune` - Clean up merged branches
27+
- `stack reparent <parent>` - Change the parent branch
28+
- `stack rename <name>` - Rename the current branch
29+
- `stack worktree` - Create a git worktree for parallel work
30+
31+
## Workflow
32+
33+
1. Start a new feature from master: `stack worktree feature-name`
34+
- Or use `stack new feature-name` if building stacked PRs on a feature branch
35+
2. Make changes and commit
36+
3. Sync to GitHub: `stack sync` (creates/updates PR)
37+
4. Check status: `stack status`
38+
5. After merge: `stack prune` to clean up
39+
40+
Run `stack --help` for full documentation.

0 commit comments

Comments
 (0)