Skip to content

Commit 412c5fa

Browse files
authored
Merge pull request cli#13523 from cli/tommy/skill-claude-config-dir-fix
Support custom CLAUDE_CONFIG_DIR in install
2 parents 57b9b20 + b5fec79 commit 412c5fa

3 files changed

Lines changed: 69 additions & 0 deletions

File tree

internal/skills/registry/registry.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package registry
22

33
import (
44
"fmt"
5+
"os"
56
"path/filepath"
67
"strings"
78

@@ -30,6 +31,8 @@ const (
3031

3132
DefaultAgentID = "github-copilot"
3233

34+
claudeConfigDirEnv = "CLAUDE_CONFIG_DIR"
35+
3336
sharedProjectSkillsDir = ".agents/skills"
3437
)
3538

@@ -387,6 +390,11 @@ func (h *AgentHost) InstallDir(scope Scope, gitRoot, homeDir string) (string, er
387390
}
388391
return filepath.Join(gitRoot, h.ProjectDir), nil
389392
case ScopeUser:
393+
if h.ID == "claude-code" {
394+
if configDir := os.Getenv(claudeConfigDirEnv); configDir != "" {
395+
return filepath.Join(configDir, "skills"), nil
396+
}
397+
}
390398
if homeDir == "" {
391399
return "", fmt.Errorf("could not determine home directory")
392400
}

internal/skills/registry/registry_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ func TestFindByID(t *testing.T) {
3838
}
3939

4040
func TestInstallDir(t *testing.T) {
41+
t.Setenv(claudeConfigDirEnv, "")
42+
4143
tests := []struct {
4244
name string
45+
setup func(*testing.T)
4346
hostID string
4447
scope Scope
4548
gitRoot string
@@ -71,6 +74,25 @@ func TestInstallDir(t *testing.T) {
7174
homeDir: "/home/monalisa",
7275
wantDir: filepath.Join("/tmp/monalisa-repo", ".claude", "skills"),
7376
},
77+
{
78+
name: "claude code user scope",
79+
hostID: "claude-code",
80+
scope: ScopeUser,
81+
gitRoot: "/tmp/monalisa-repo",
82+
homeDir: "/home/monalisa",
83+
wantDir: filepath.Join("/home/monalisa", ".claude", "skills"),
84+
},
85+
{
86+
name: "claude code user scope, respect env var",
87+
setup: func(t *testing.T) {
88+
t.Setenv("CLAUDE_CONFIG_DIR", filepath.Join("/home", "monalisa", ".config", "claude"))
89+
},
90+
hostID: "claude-code",
91+
scope: ScopeUser,
92+
gitRoot: "/tmp/monalisa-repo",
93+
homeDir: "/home/monalisa",
94+
wantDir: filepath.Join("/home", "monalisa", ".config", "claude", "skills"),
95+
},
7496
{
7597
name: "cursor project scope",
7698
hostID: "cursor",
@@ -130,6 +152,10 @@ func TestInstallDir(t *testing.T) {
130152
}
131153
for _, tt := range tests {
132154
t.Run(tt.name, func(t *testing.T) {
155+
if tt.setup != nil {
156+
tt.setup(t)
157+
}
158+
133159
host, err := FindByID(tt.hostID)
134160
require.NoError(t, err)
135161

pkg/cmd/skills/install/install_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ func TestInstallRun(t *testing.T) {
311311
wantErr string
312312
wantStdout string
313313
wantStderr string
314+
assert func(t *testing.T)
314315
}{
315316
{
316317
name: "non-interactive without repo errors",
@@ -1527,6 +1528,37 @@ func TestInstallRun(t *testing.T) {
15271528
wantStdout: "Installed hidden-skill",
15281529
wantStderr: "Skills in hidden directories",
15291530
},
1531+
{
1532+
name: "respect claude code config dir env var for user scope",
1533+
setup: func(t *testing.T) {
1534+
t.Setenv("CLAUDE_CONFIG_DIR", t.TempDir())
1535+
},
1536+
stubs: func(reg *httpmock.Registry) {
1537+
stubResolveVersion(reg, "monalisa", "skills-repo", "v1.0.0", "abc123")
1538+
stubDiscoverTree(reg, "monalisa", "skills-repo", "abc123",
1539+
singleSkillTreeJSON("git-commit", "treeSHA", "blobSHA"))
1540+
stubInstallFiles(reg, "monalisa", "skills-repo", "treeSHA", "blobSHA", gitCommitContent)
1541+
},
1542+
opts: func(ios *iostreams.IOStreams, reg *httpmock.Registry) *InstallOptions {
1543+
t.Helper()
1544+
return &InstallOptions{
1545+
IO: ios,
1546+
HttpClient: func() (*http.Client, error) { return &http.Client{Transport: reg}, nil },
1547+
GitClient: &git.Client{RepoDir: t.TempDir()},
1548+
SkillSource: "monalisa/skills-repo",
1549+
SkillName: "git-commit",
1550+
Agent: "claude-code",
1551+
Scope: "user",
1552+
ScopeChanged: true,
1553+
Telemetry: &telemetry.NoOpService{},
1554+
}
1555+
},
1556+
assert: func(t *testing.T) {
1557+
assert.FileExists(t, filepath.Join(os.Getenv("CLAUDE_CONFIG_DIR"), "skills", "git-commit", "SKILL.md"))
1558+
assert.NoFileExists(t, filepath.Join(os.Getenv("HOME"), ".claude", "skills", "git-commit", "SKILL.md"))
1559+
},
1560+
wantStdout: "Installed git-commit",
1561+
},
15301562
}
15311563

15321564
for _, tt := range tests {
@@ -1572,6 +1604,9 @@ func TestInstallRun(t *testing.T) {
15721604
if tt.verify != nil {
15731605
tt.verify(t)
15741606
}
1607+
if tt.assert != nil {
1608+
tt.assert(t)
1609+
}
15751610
})
15761611
}
15771612
}

0 commit comments

Comments
 (0)