Skip to content

Commit 3bfe890

Browse files
fullstackjamclaude
andcommitted
docs: merge AGENTS.md into CLAUDE.md
Consolidate project knowledge base (AGENTS.md) and Claude Code guidance (CLAUDE.md) into a single file. Update CONTRIBUTING.md reference accordingly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9d505db commit 3bfe890

2 files changed

Lines changed: 91 additions & 99 deletions

File tree

Lines changed: 90 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,42 @@
1-
# PROJECT KNOWLEDGE BASE
1+
# CLAUDE.md
22

3-
**Generated:** 2026-02-11
4-
**Commit:** 5fd1715
5-
**Branch:** main
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
64

7-
## OVERVIEW
5+
## Project
86

9-
Mac dev environment setup CLI. Go 1.24 + Cobra + Charmbracelet (bubbletea/lipgloss/huh) TUI.
10-
Installs Homebrew packages, casks, npm globals, shell config, macOS preferences, dotfiles.
7+
OpenBoot is a macOS-only CLI tool (Go 1.24) that automates dev environment setup — Homebrew packages/casks, npm globals, shell config (Oh-My-Zsh), macOS preferences, and dotfiles. Built with Cobra (CLI) and Charmbracelet (bubbletea/lipgloss/huh for TUI).
118

12-
## STRUCTURE
9+
## Commands
10+
11+
```bash
12+
# Build
13+
make build # Dev build (version=dev)
14+
make build VERSION=0.24.0 # Specific version
15+
make build-release VERSION=0.24.0 # Optimized + UPX compression
16+
17+
# Test
18+
make test-unit # go test -v -timeout 5m ./...
19+
make test-integration # go test -v -tags=integration ./...
20+
make test-e2e # go test -v -tags=e2e -short ./...
21+
make test-all # All tests + coverage report
22+
23+
# Run a single test
24+
go test -v -run TestFunctionName ./internal/package/...
25+
26+
# Lint
27+
go vet ./...
28+
29+
# Clean
30+
make clean
31+
```
32+
33+
## Architecture
34+
35+
Entry point: `cmd/openboot/main.go``cli.Execute()`.
36+
37+
The installer orchestrates a 7-step wizard: check deps → Homebrew setup → git config → preset selection → package install → shell setup → macOS prefs + dotfiles.
38+
39+
### Structure
1340

1441
```
1542
openboot/
@@ -22,39 +49,24 @@ openboot/
2249
│ ├── config/ # Embedded YAML (packages + presets), remote config fetch
2350
│ │ └── data/ # packages.yaml (9 categories), presets.yaml (3 presets)
2451
│ ├── dotfiles/ # Clone + stow/symlink with .openboot.bak backup
25-
│ ├── installer/ # Main orchestrator: 7-step wizard + snapshot restore (git/shell/packages)
52+
│ ├── installer/ # Main orchestrator: 7-step wizard + snapshot restore
2653
│ ├── macos/ # `defaults write` preferences, app restart
2754
│ ├── npm/ # Batch install with sequential fallback, uninstall
2855
│ ├── search/ # Online search via openboot.dev API (8s timeout)
29-
│ ├── shell/ # Oh-My-Zsh install, .zshrc config, snapshot restore (theme/plugins)
30-
│ ├── snapshot/ # Capture/match/restore environment state (see subdir AGENTS.md)
56+
│ ├── shell/ # Oh-My-Zsh install, .zshrc config, snapshot restore
57+
│ ├── snapshot/ # Capture/match/restore environment state
3158
│ ├── system/ # RunCommand/RunCommandSilent, arch detection, git config
32-
│ ├── ui/ # TUI components (see subdir AGENTS.md)
59+
│ ├── ui/ # TUI components (bubbletea Model pattern, lipgloss styling)
3360
│ └── updater/ # Auto-update: check GitHub → download → replace binary
3461
├── test/
3562
│ ├── integration/ # Build tag: //go:build integration
3663
│ └── e2e/ # Build tag: //go:build e2e
3764
├── testutil/ # Shared test helpers
3865
├── scripts/install.sh # curl|bash installer (detects arch, verifies checksums)
39-
└── Makefile # Build targets
66+
└── Makefile
4067
```
4168

42-
## WHERE TO LOOK
43-
44-
| Task | Location | Notes |
45-
|------|----------|-------|
46-
| Add CLI command | `internal/cli/` | Register in root.go init(), follow cobra pattern |
47-
| Add package category | `internal/config/data/packages.yaml` | Rebuild after changing embedded YAML |
48-
| Change install flow | `internal/installer/installer.go` | 7 steps: homebrew → git → preset → packages → shell → macos → dotfiles |
49-
| Change clean/uninstall | `internal/cleaner/cleaner.go` | Diffs current vs desired, calls brew/npm Uninstall |
50-
| Add TUI component | `internal/ui/` | Use bubbletea Model pattern, lipgloss styling |
51-
| Change brew behavior | `internal/brew/brew.go` | Parallel workers, StickyProgress for output, Uninstall/UninstallCask |
52-
| Add snapshot data | `internal/snapshot/capture.go` | Add to CaptureWithProgress steps |
53-
| Change snapshot restore | `internal/installer/installer.go` | stepRestoreGit, stepRestoreShell + packages/shell/macos |
54-
| Update self-update | `internal/updater/updater.go` | AutoUpgrade() called from root.go RunE |
55-
| Modify presets | `internal/config/data/presets.yaml` | 3 presets: minimal, developer, full |
56-
57-
## DEPENDENCY GRAPH
69+
### Dependency Graph
5870

5971
```
6072
cli (root)
@@ -73,61 +85,58 @@ cli (root)
7385
└── snapshot → config, macos
7486
```
7587

76-
## CONVENTIONS
88+
### Where to Look
7789

78-
- **Error wrapping**: `fmt.Errorf("context: %w", err)` — always wrap with context
79-
- **UI output**: Use `ui.Header/Success/Error/Info/Warn/Muted` — never raw fmt for user-facing text
80-
- **Command exec**: `system.RunCommand()` (interactive) or `system.RunCommandSilent()` (capture output)
81-
- **Embedded data**: `//go:embed data/*.yaml` with `embed.FS`, loaded in `init()`
82-
- **Testing**: Table-driven with testify/assert. Build tags for integration/e2e
83-
- **Concurrency**: `sync.WaitGroup` with bounded workers (max 4 for brew)
84-
- **Dry-run**: All destructive operations check `cfg.DryRun` first
85-
- **Version string**: Default `"dev"` in `internal/cli/root.go` — injected via ldflags at build time, never edit manually
86-
- **Config storage**: `~/.openboot/` directory for auth, state, snapshots
87-
- **CLI backward compatibility**: All CLI changes (commands, flags, arguments) must maintain backward compatibility. Old syntax must continue to work when adding new features
88-
89-
## ANTI-PATTERNS
90-
91-
- No `as any` equivalent — no type assertion abuse
92-
- No ignored errors (`_ = err`) in production code
93-
- No `panic()` except `log.Fatalf` in `init()` for fatal config errors
94-
- No hardcoded `~` paths — always `os.UserHomeDir()`
95-
- No unbounded goroutines — always WaitGroup + max workers
96-
- No direct stdout for styled text — always through `ui` package
90+
| Task | Location | Notes |
91+
|------|----------|-------|
92+
| Add CLI command | `internal/cli/` | Register in root.go init(), follow cobra pattern |
93+
| Add package category | `internal/config/data/packages.yaml` | Rebuild after changing embedded YAML |
94+
| Change install flow | `internal/installer/installer.go` | 7 steps: homebrew → git → preset → packages → shell → macos → dotfiles |
95+
| Change clean/uninstall | `internal/cleaner/cleaner.go` | Diffs current vs desired, calls brew/npm Uninstall |
96+
| Add TUI component | `internal/ui/` | Use bubbletea Model pattern, lipgloss styling |
97+
| Change brew behavior | `internal/brew/brew.go` | Parallel workers, StickyProgress for output, Uninstall/UninstallCask |
98+
| Add snapshot data | `internal/snapshot/capture.go` | Add to CaptureWithProgress steps |
99+
| Change snapshot restore | `internal/installer/installer.go` | stepRestoreGit, stepRestoreShell + packages/shell/macos |
100+
| Update self-update | `internal/updater/updater.go` | AutoUpgrade() called from root.go RunE |
101+
| Modify presets | `internal/config/data/presets.yaml` | 3 presets: minimal, developer, full |
97102

98-
## COMMANDS
103+
## Conventions
99104

100-
```bash
101-
make build # Dev build (version=dev)
102-
make build VERSION=0.19.0 # Build with specific version
103-
make build-release VERSION=0.19.0 # Optimized + UPX with version
104-
make test-unit # go test -v ./...
105-
make test-integration # go test -v -tags=integration ./...
106-
make test-e2e # go test -v -tags=e2e -short ./...
107-
make test-all # All above + coverage
108-
make clean # Remove binaries + coverage
109-
go vet ./... # Lint check
110-
```
105+
- **Error wrapping**: Always `fmt.Errorf("context: %w", err)` — never bare error returns
106+
- **UI output**: Use `ui.Header/Success/Error/Info/Warn/Muted` — never raw `fmt` for user-facing text
107+
- **Command execution**: `system.RunCommand()` (interactive) or `system.RunCommandSilent()` (capture output)
108+
- **Embedded data**: `//go:embed data/*.yaml` with `embed.FS`, loaded in `init()`
109+
- **Dry-run**: All destructive operations must check `cfg.DryRun` first
110+
- **Paths**: Always `os.UserHomeDir()` — never hardcoded `~`
111+
- **Concurrency**: `sync.WaitGroup` with bounded workers (max 4 for brew) — no unbounded goroutines
112+
- **Version**: Default `"dev"` in `internal/cli/root.go`, injected via `-ldflags -X` at build time. Never edit manually.
113+
- **Config storage**: `~/.openboot/` directory for auth, state, snapshots
114+
- **Commits**: Conventional format (`feat:`, `fix:`, `docs:`, `refactor:`), one thing per commit
115+
- **CLI changes**: Must maintain backward compatibility — old syntax continues to work
116+
- **Testing**: Table-driven tests with `testify/assert` (non-fatal) and `testify/require` (fatal). Integration tests use `//go:build integration`, E2E uses `//go:build e2e`.
117+
- **No `panic()`** except `log.Fatalf` in `init()` for fatal config errors
118+
- **No ignored errors** (`_ = err`) in production code
119+
- **No direct stdout** for styled text — always through `ui` package
120+
- **Color palette**: Primary `#22c55e`, Secondary `#60a5fa`, Warning `#eab308`, Danger `#ef4444`, Subtle `#666666`
111121

112-
## RELEASE PROCESS
122+
## Release Process
113123

114124
Tag-driven. CI handles everything. **Never edit root.go for version bumps.**
115125

116126
```bash
117-
git tag v0.24.0
127+
git tag v0.25.0
118128
git push --tags
119129
# CI builds binaries with version injected via ldflags, creates GitHub release
120130
```
121131

122132
- Version is `"dev"` in source — overridden by `-ldflags -X` at build time
123133
- Dev builds (`version=dev`) skip auto-update
124134
- CI workflow: `.github/workflows/release.yml` extracts version from git tag
135+
- **When to release**: Only for user-facing changes (features, bug fixes, package updates). Skip for docs, CI config, test-only changes.
125136

126-
**When to release**: Only for user-facing changes (features, bug fixes, package updates). Skip for docs, AGENTS.md, CI config, test-only changes.
127-
128-
### Writing Release Notes (Changelog)
137+
### Writing Release Notes
129138

130-
CI creates a release with a generic install-only body. After CI completes, update it with a proper changelog using `gh release edit`.
139+
CI creates a release with a generic install-only body. After CI completes, update with a proper changelog via `gh release edit`.
131140

132141
**Step 1: Gather commits since last release**
133142

@@ -138,8 +147,6 @@ git log ${PREV_TAG}..HEAD --oneline
138147

139148
**Step 2: Write the changelog**
140149

141-
Follow this exact format:
142-
143150
```markdown
144151
## What's New
145152
- **Feature name** — One sentence, user-facing benefit only (`openboot <command>`)
@@ -164,14 +171,12 @@ brew install openbootdotdev/tap/openboot
164171
| macOS | Intel | `openboot-darwin-amd64` |
165172
```
166173

167-
> **Note:** The `\`\`\`` above is how triple backticks are shown inside a Markdown code block. In the actual `gh release edit` command, use real unescaped triple backticks (` ``` `).
168-
169174
**Rules:**
170175

171176
- Omit empty sections (no "Bug Fixes" if there are none)
172177
- Write for **users**, not developers. No internal refactors, no test-only changes
173178
- **Bold name**: 2–4 words max, noun form. Not a sentence.
174-
- **Description**: ONE sentence, ~10–15 words max. User benefit only — no implementation details, no "how it works".
179+
- **Description**: ONE sentence, ~10–15 words max. User benefit only — no implementation details.
175180
- Include the CLI command at the end if it's a new/changed command
176181
- Keep Installation and Binaries sections at the bottom (always)
177182

@@ -187,10 +192,10 @@ brew install openbootdotdev/tap/openboot
187192

188193
**Step 3: Update the release on GitHub**
189194

190-
Use a `'EOF'` heredoc so the shell doesn't interpret backticks — this is the only safe way to embed triple backtick code blocks:
195+
Use a `'EOF'` heredoc so the shell doesn't interpret backticks:
191196

192197
```bash
193-
gh release edit v0.24.0 --repo openbootdotdev/openboot --notes "$(cat <<'EOF'
198+
gh release edit v0.25.0 --repo openbootdotdev/openboot --notes "$(cat <<'EOF'
194199
## What's New
195200
- **Feature name** — One sentence description (`openboot <command>`)
196201
@@ -210,34 +215,21 @@ EOF
210215
)"
211216
```
212217

213-
**Example (v0.24.0):**
218+
## Environment Variables
214219

215-
```markdown
216-
## What's New
217-
- **Clean command** — Remove packages not in your config or snapshot (`openboot clean`)
218-
- **Full snapshot restore** — Importing a snapshot now restores git identity, Oh-My-Zsh theme, and plugins
219-
220-
## Improvements
221-
- **Brew & npm uninstall** — Internal support for package removal, used by `openboot clean`
222-
223-
## Installation
224-
225-
\`\`\`bash
226-
brew install openbootdotdev/tap/openboot
227-
\`\`\`
228-
229-
## Binaries
230-
231-
| Platform | Architecture | Download |
232-
|----------|--------------|----------|
233-
| macOS | Apple Silicon (M1/M2/M3/M4) | `openboot-darwin-arm64` |
234-
| macOS | Intel | `openboot-darwin-amd64` |
235-
```
220+
| Variable | Purpose |
221+
|----------|---------|
222+
| `OPENBOOT_DRY_RUN` | Enable dry-run mode |
223+
| `OPENBOOT_DISABLE_AUTOUPDATE` | Disable auto-update (`1`) |
224+
| `OPENBOOT_GIT_NAME` / `OPENBOOT_GIT_EMAIL` | Git identity |
225+
| `OPENBOOT_PRESET` | Default preset |
226+
| `OPENBOOT_USER` | Config alias/username |
227+
| `OPENBOOT_VERSION` | Version for `install.sh` |
228+
| `OPENBOOT_INSTALL_DIR` | Custom install directory |
236229

237-
## NOTES
230+
## Notes
238231

239232
- **macOS only**: No Linux/Windows support. darwin binaries only.
240233
- **Auto-update**: Enabled by default. Config: `~/.openboot/config.json` `{"autoupdate": "true"|"notify"|"false"}`. Env: `OPENBOOT_DISABLE_AUTOUPDATE=1`.
241-
- **Color palette**: Primary #22c55e (green), Secondary #60a5fa (blue), Warning #eab308, Danger #ef4444, Subtle #666666.
242234
- **Snapshot upload**: Requires auth token from openboot.dev OAuth flow.
243235
- **install.sh**: Supports `OPENBOOT_DRY_RUN=true` and `OPENBOOT_INSTALL_DIR=path`.

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ make test-all # Everything + coverage
5050

5151
## Architecture
5252

53-
See [AGENTS.md](AGENTS.md) for how everything fits together.
53+
See [CLAUDE.md](CLAUDE.md) for how everything fits together.
5454

5555
## Questions
5656

0 commit comments

Comments
 (0)