Skip to content

Commit 4bbf288

Browse files
Merge pull request #5 from technicalpickles/claudeconfig-stacks-refactor
Restructure claude config into roles/ + stacks/
2 parents 1e04472 + 9f31c90 commit 4bbf288

44 files changed

Lines changed: 2099 additions & 792 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

claude/README.md

Lines changed: 142 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,149 @@
11
# Claude Code Configuration
22

3-
This directory contains the configuration templates for Claude Code settings and permissions. The configuration uses a **layered merging system** that combines base settings with role-specific and ecosystem-specific permissions.
3+
This directory contains the configuration templates for Claude Code settings and permissions. The configuration uses a **layered merging system** that combines roles (base settings + safety rules) with stacks (per-topic permissions and sandbox config).
44

55
## Architecture
66

77
```
88
claude/
9-
├── settings.base.json # Core settings (all roles)
10-
├── settings.personal.json # Personal role overrides
11-
├── settings.work.json # Work role overrides
12-
├── permissions.json # Base permissions (deny rules)
13-
├── permissions.personal.json # Personal-specific permissions
14-
├── permissions.work.json # Work-specific permissions
15-
├── permissions.skills.json # Skill permissions (cross-project)
16-
├── permissions.node.json # Node.js ecosystem (npm, yarn, npx)
17-
├── permissions.ruby.json # Ruby ecosystem (bundle, rake, rspec)
18-
├── permissions.python.json # Python ecosystem (pip, pytest, uv)
19-
├── permissions.go.json # Go ecosystem (go build, go test)
20-
├── permissions.rust.json # Rust ecosystem (cargo)
21-
├── permissions.shell.json # Shell utilities (jq, fd, rg, etc.)
22-
├── permissions.github.json # GitHub CLI (gh pr, gh issue, etc.)
23-
├── permissions.docker.json # Docker/container commands
24-
├── permissions.git.jsonc # Git commands
25-
├── permissions.mise.json # mise version manager
26-
├── permissions.mcp.json # MCP-related permissions
27-
└── permissions.web.json # Web fetching domains
9+
├── roles/
10+
│ ├── base.jsonc # Core settings, base permissions, sandbox scalars
11+
│ ├── personal.jsonc # Personal role overrides (empty placeholder)
12+
│ └── work.jsonc # Work role: AWS/Bedrock env, work permissions
13+
├── stacks/
14+
│ ├── beans.jsonc # Beans issue tracker
15+
│ ├── buildkite.jsonc # Buildkite CI
16+
│ ├── colima.jsonc # Colima container runtime
17+
│ ├── docker.jsonc # Docker container management
18+
│ ├── docs.jsonc # Reference documentation sites
19+
│ ├── git.jsonc # Git operations
20+
│ ├── github.jsonc # GitHub CLI
21+
│ ├── go.jsonc # Go ecosystem
22+
│ ├── mcp.jsonc # MCP proxy tools
23+
│ ├── mise.jsonc # mise version manager
24+
│ ├── node.jsonc # Node.js ecosystem (npm, yarn, pnpm)
25+
│ ├── python.jsonc # Python ecosystem (pip, uv, pytest)
26+
│ ├── ruby.jsonc # Ruby ecosystem (bundle, rake, rspec)
27+
│ ├── rust.jsonc # Rust ecosystem (cargo, rustup)
28+
│ ├── shell.jsonc # Shell utilities (jq, fd, grep, etc.)
29+
│ └── skills.jsonc # Skill permissions
30+
├── CLAUDE.md # Claude Code instructions (symlinked to ~/.claude/)
31+
└── README.md # This file
2832
```
2933

30-
## How Merging Works
31-
32-
When you run `./claudeconfig.sh`:
34+
## Schema
3335

34-
1. **Settings**: `settings.base.json` + `settings.$ROLE.json` are deep-merged
35-
2. **Permissions**: All `permissions.*.json` files are concatenated:
36-
- `permissions.json` (base deny rules)
37-
- `permissions.$ROLE.json` (role-specific)
38-
- All ecosystem files (`permissions.node.json`, `permissions.ruby.json`, etc.)
39-
3. **Deduplication**: Allow/deny lists are sorted and deduplicated
40-
4. **Local preservation**: Keys like `awsAuthRefresh` and `env` are preserved from existing `~/.claude/settings.json`
41-
42-
## Common Tasks
36+
All files use JSONC (`.jsonc`), allowing `//` and `/* */` comments. Use comments to document provenance (e.g. `// source: agent-safehouse`).
4337

44-
### Add a frequently-used skill permission
38+
### Role files
4539

46-
If you keep getting prompted for a skill across multiple projects:
40+
Role files hold settings, permissions, and sandbox config:
4741

48-
1. Add to `permissions.skills.json`:
49-
50-
```json
51-
{
52-
"allow": ["Skill(existing:skill)", "Skill(new-plugin:new-skill)"]
53-
}
54-
```
42+
```jsonc
43+
{
44+
// Settings (any Claude Code setting keys)
45+
"statusLine": { "..." },
46+
"includeCoAuthoredBy": true,
47+
48+
// Permissions
49+
"permissions": {
50+
"allow": [],
51+
"ask": [],
52+
"deny": []
53+
},
54+
55+
// Sandbox (scalars live in roles only)
56+
"sandbox": {
57+
"enabled": true,
58+
"autoAllowBashIfSandboxed": true,
59+
"enableWeakerNetworkIsolation": true,
60+
"network": {
61+
"allowAllUnixSockets": true,
62+
"allowedHosts": []
63+
}
64+
}
65+
}
66+
```
5567

56-
2. Regenerate global settings:
68+
### Stack files
5769

58-
```bash
59-
./claudeconfig.sh
60-
```
70+
Stack files hold per-topic permissions and sandbox arrays (no scalars):
6171

62-
3. Clean up project-local duplicates:
63-
```bash
64-
claude-permissions cleanup # Preview changes
65-
claude-permissions cleanup --force # Apply changes
66-
```
72+
```jsonc
73+
{
74+
"permissions": {
75+
"allow": [],
76+
"ask": [],
77+
"deny": []
78+
},
79+
"sandbox": {
80+
"network": {
81+
"allowedHosts": []
82+
},
83+
"filesystem": {
84+
"allowWrite": []
85+
}
86+
}
87+
}
88+
```
6789

68-
### Add a new ecosystem permission file
90+
All keys are optional. A stack can have only `permissions`, only `sandbox`, or both.
6991

70-
1. Create `claude/permissions.neweco.json`:
92+
## How Merging Works
7193

72-
```json
73-
{
74-
"allow": ["Bash(newtool:*)", "Bash(newtool build:*)"],
75-
"deny": []
76-
}
77-
```
94+
When you run `./claudeconfig.sh`:
7895

79-
2. Regenerate: `./claudeconfig.sh`
96+
1. **Base role** (`roles/base.jsonc`): settings, permissions, and sandbox extracted
97+
2. **Active role** (`roles/$ROLE.jsonc`): settings deep-merged on top of base. Permissions and sandbox arrays concatenated (not deep-merged, which would replace arrays)
98+
3. **Stacks** (`stacks/*.jsonc`, sorted alphabetically): permissions and sandbox arrays concatenated
99+
4. **Deduplication**: all arrays sorted and deduplicated
100+
5. **Local keys**: `model`, `enabledPlugins`, `extraKnownMarketplaces` preserved from existing `~/.claude/settings.json`
101+
6. **Validation and write**
80102

81-
The filename pattern `permissions.*.json` is auto-discovered (excluding base, personal, and work files).
103+
## Common Tasks
82104

83-
### Add an "always ask" rule
105+
### Add a new stack
84106

85-
Use `ask` for commands that should always prompt for confirmation (useful for destructive but sometimes-needed operations):
107+
Create `claude/stacks/foo.jsonc`:
86108

87-
```json
109+
```jsonc
88110
{
89-
"allow": ["Bash(cleanup-tool)"],
90-
"ask": ["Bash(cleanup-tool --force)"],
91-
"deny": []
111+
// Foo tool
112+
"permissions": {
113+
"allow": [
114+
"Bash(foo:*)"
115+
]
116+
},
117+
// Optional: sandbox config
118+
"sandbox": {
119+
"network": {
120+
"allowedHosts": ["foo.example.com"]
121+
},
122+
"filesystem": {
123+
"allowWrite": ["~/.foo"]
124+
}
125+
}
92126
}
93127
```
94128

95-
### Add a deny rule
129+
Then regenerate: `./claudeconfig.sh`
96130

97-
Add to `permissions.json` (applies to all roles):
131+
### Add a network host
98132

99-
```json
100-
{
101-
"allow": [],
102-
"deny": ["Bash(dangerous-command:*)"]
103-
}
133+
Find the relevant stack file and add to `sandbox.network.allowedHosts`. For example, to allow a new npm registry:
134+
135+
Edit `claude/stacks/node.jsonc` and add to `allowedHosts`, then `./claudeconfig.sh`.
136+
137+
### Add a filesystem write path
138+
139+
Same pattern: find the relevant stack and add to `sandbox.filesystem.allowWrite`.
140+
141+
### Add a skill permission
142+
143+
Edit `claude/stacks/skills.jsonc` and add to `permissions.allow`:
144+
145+
```jsonc
146+
"Skill(plugin-name:skill-name)"
104147
```
105148

106149
### Check current permissions state
@@ -121,17 +164,10 @@ claude-permissions --raw
121164

122165
### Find and clean up duplicates
123166

124-
The `claude-permissions cleanup` command removes project-local permissions that duplicate global settings:
125-
126167
```bash
127168
# Preview what would be removed
128169
claude-permissions cleanup
129170

130-
# Example output:
131-
# -12 my-project 3 left
132-
# -8 other-project empty
133-
# Would remove: 20 entries from 2 files
134-
135171
# Apply the cleanup
136172
claude-permissions cleanup --force
137173
```
@@ -140,11 +176,11 @@ claude-permissions cleanup --force
140176

141177
### Permission Lists
142178

143-
| List | Behavior |
144-
| ------- | ------------------------------------------------------------------- |
145-
| `allow` | Always permitted without prompting |
179+
| List | Behavior |
180+
| ------- | ------------------------------------------------------------------ |
181+
| `allow` | Always permitted without prompting |
146182
| `ask` | Always prompts for confirmation (useful for destructive operations) |
147-
| `deny` | Always blocked |
183+
| `deny` | Always blocked |
148184

149185
### Permission Format
150186

@@ -165,45 +201,43 @@ Wildcards:
165201

166202
When you notice you're repeatedly approving the same permission across projects:
167203

168-
1. **Audit current state**:
204+
1. **Audit**: `claude-permissions --aggregate | grep "2x\|3x\|4x"`
205+
2. **Add to appropriate stack file**
206+
3. **Regenerate**: `./claudeconfig.sh`
207+
4. **Clean up**: `claude-permissions cleanup --force`
208+
5. **Commit** to dotfiles
169209

170-
```bash
171-
claude-permissions --aggregate | grep "2x\|3x\|4x"
172-
```
210+
## Local Keys
173211

174-
2. **Identify candidates**: Permissions appearing 2+ times are good candidates
212+
These keys in `~/.claude/settings.json` are preserved across regenerations:
175213

176-
3. **Add to appropriate file**:
177-
178-
- Skills → `permissions.skills.json`
179-
- Language tools → `permissions.{lang}.json`
180-
- General tools → `permissions.shell.json`
181-
182-
4. **Regenerate and clean up**:
183-
184-
```bash
185-
./claudeconfig.sh
186-
claude-permissions cleanup --force
187-
```
188-
189-
5. **Commit changes** to dotfiles
214+
- `model`: machine-specific model preference
215+
- `enabledPlugins`: plugin activation state (tracked in gt-1bil)
216+
- `extraKnownMarketplaces`: managed by `configure_marketplaces()` in claudeconfig.sh
190217

191218
## Files NOT to Edit
192219

193-
- `~/.claude/settings.json` - Generated by `claudeconfig.sh`, will be overwritten
194-
- Exception: `awsAuthRefresh` and `env` keys are preserved across regenerations
220+
- `~/.claude/settings.json`: generated by `claudeconfig.sh`, will be overwritten
221+
- Exception: `model`, `enabledPlugins`, and `extraKnownMarketplaces` are preserved
195222

196223
## Debugging
197224

198-
If permissions aren't working as expected:
199-
200225
```bash
201226
# Check what's actually in global settings
202227
jq '.permissions' ~/.claude/settings.json
203228

204229
# Check specific permission type
205230
jq '.permissions.allow[]' ~/.claude/settings.json | grep -i skill
206231

232+
# Check sandbox config
233+
jq '.sandbox' ~/.claude/settings.json
234+
235+
# Check network hosts
236+
jq '.sandbox.network.allowedHosts' ~/.claude/settings.json
237+
238+
# Check filesystem write paths
239+
jq '.sandbox.filesystem.allowWrite' ~/.claude/settings.json
240+
207241
# Verify claudeconfig.sh output
208-
./claudeconfig.sh # Watch for "Merging X permissions" messages
242+
./claudeconfig.sh # Watch for "Loaded base role", "Merged X stack" messages
209243
```

claude/permissions.beans.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

claude/permissions.colima.json

Lines changed: 0 additions & 16 deletions
This file was deleted.

claude/permissions.docker.json

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)