Skip to content

Commit e9b048d

Browse files
committed
docs: add hierarchical AGENTS.md knowledge base for AI-assisted development
1 parent 36f2ac7 commit e9b048d

3 files changed

Lines changed: 227 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# PROJECT KNOWLEDGE BASE
2+
3+
**Generated:** 2026-02-11
4+
**Commit:** 5fd1715
5+
**Branch:** main
6+
7+
## OVERVIEW
8+
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.
11+
12+
## STRUCTURE
13+
14+
```
15+
openboot/
16+
├── cmd/openboot/ # main.go → cli.Execute()
17+
├── internal/
18+
│ ├── auth/ # OAuth-like login, token in ~/.openboot/auth.json (0600)
19+
│ ├── brew/ # Homebrew ops, parallel install (4 workers), retry logic
20+
│ ├── cli/ # Cobra commands: root, snapshot, doctor, update, version
21+
│ ├── config/ # Embedded YAML (packages + presets), remote config fetch
22+
│ │ └── data/ # packages.yaml (9 categories), presets.yaml (3 presets)
23+
│ ├── dotfiles/ # Clone + stow/symlink with .openboot.bak backup
24+
│ ├── installer/ # Main orchestrator: 7-step wizard (693 lines)
25+
│ ├── macos/ # `defaults write` preferences, app restart
26+
│ ├── npm/ # Batch install with sequential fallback
27+
│ ├── search/ # Online search via openboot.dev API (8s timeout)
28+
│ ├── shell/ # Oh-My-Zsh install, .zshrc config
29+
│ ├── snapshot/ # Capture/match/restore environment state (see subdir AGENTS.md)
30+
│ ├── system/ # RunCommand/RunCommandSilent, arch detection, git config
31+
│ ├── ui/ # TUI components (see subdir AGENTS.md)
32+
│ └── updater/ # Auto-update: check GitHub → download → replace binary
33+
├── test/
34+
│ ├── integration/ # Build tag: //go:build integration
35+
│ └── e2e/ # Build tag: //go:build e2e
36+
├── testutil/ # Shared test helpers
37+
├── scripts/install.sh # curl|bash installer (detects arch, verifies checksums)
38+
└── Makefile # Build targets
39+
```
40+
41+
## WHERE TO LOOK
42+
43+
| Task | Location | Notes |
44+
|------|----------|-------|
45+
| Add CLI command | `internal/cli/` | Register in root.go init(), follow cobra pattern |
46+
| Add package category | `internal/config/data/packages.yaml` | Rebuild after changing embedded YAML |
47+
| Change install flow | `internal/installer/installer.go` | 7 steps: homebrew → git → preset → packages → shell → macos → dotfiles |
48+
| Add TUI component | `internal/ui/` | Use bubbletea Model pattern, lipgloss styling |
49+
| Change brew behavior | `internal/brew/brew.go` | Parallel workers, StickyProgress for output |
50+
| Add snapshot data | `internal/snapshot/capture.go` | Add to CaptureWithProgress steps |
51+
| Update self-update | `internal/updater/updater.go` | AutoUpgrade() called from root.go RunE |
52+
| Modify presets | `internal/config/data/presets.yaml` | 3 presets: minimal, developer, full |
53+
54+
## DEPENDENCY GRAPH
55+
56+
```
57+
cli (root)
58+
├── installer (orchestrator)
59+
│ ├── brew → ui
60+
│ ├── npm → ui
61+
│ ├── config (no deps)
62+
│ ├── dotfiles (no deps)
63+
│ ├── macos (no deps)
64+
│ ├── shell (no deps)
65+
│ ├── system (no deps)
66+
│ └── ui → config, search, snapshot, system
67+
├── updater → ui
68+
├── auth → ui
69+
└── snapshot → config, macos
70+
```
71+
72+
## CONVENTIONS
73+
74+
- **Error wrapping**: `fmt.Errorf("context: %w", err)` — always wrap with context
75+
- **UI output**: Use `ui.Header/Success/Error/Info/Warn/Muted` — never raw fmt for user-facing text
76+
- **Command exec**: `system.RunCommand()` (interactive) or `system.RunCommandSilent()` (capture output)
77+
- **Embedded data**: `//go:embed data/*.yaml` with `embed.FS`, loaded in `init()`
78+
- **Testing**: Table-driven with testify/assert. Build tags for integration/e2e
79+
- **Concurrency**: `sync.WaitGroup` with bounded workers (max 4 for brew)
80+
- **Dry-run**: All destructive operations check `cfg.DryRun` first
81+
- **Version string**: Hardcoded in `internal/cli/root.go` — bump manually before release
82+
- **Config storage**: `~/.openboot/` directory for auth, state, snapshots
83+
84+
## ANTI-PATTERNS
85+
86+
- No `as any` equivalent — no type assertion abuse
87+
- No ignored errors (`_ = err`) in production code
88+
- No `panic()` except `log.Fatalf` in `init()` for fatal config errors
89+
- No hardcoded `~` paths — always `os.UserHomeDir()`
90+
- No unbounded goroutines — always WaitGroup + max workers
91+
- No direct stdout for styled text — always through `ui` package
92+
93+
## COMMANDS
94+
95+
```bash
96+
make build # go build -o openboot ./cmd/openboot
97+
make build-release # Optimized: -ldflags="-s -w" -trimpath + UPX
98+
make test-unit # go test -v ./...
99+
make test-integration # go test -v -tags=integration ./...
100+
make test-e2e # go test -v -tags=e2e -short ./...
101+
make test-all # All above + coverage
102+
make clean # Remove binaries + coverage
103+
go vet ./... # Lint check
104+
```
105+
106+
## RELEASE PROCESS
107+
108+
1. Bump version in `internal/cli/root.go`
109+
2. `git commit && git push`
110+
3. Build: `GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o openboot-darwin-arm64 ./cmd/openboot`
111+
4. `gh release create vX.Y.Z openboot-darwin-arm64 openboot-darwin-amd64 checksums.txt`
112+
113+
CI auto-releases on `v*` tags via `.github/workflows/release.yml`.
114+
115+
## NOTES
116+
117+
- **macOS only**: No Linux/Windows support. darwin binaries only.
118+
- **Auto-update**: Enabled by default. Config: `~/.openboot/config.json` `{"autoupdate": "true"|"notify"|"false"}`. Env: `OPENBOOT_DISABLE_AUTOUPDATE=1`.
119+
- **Color palette**: Primary #22c55e (green), Secondary #60a5fa (blue), Warning #eab308, Danger #ef4444, Subtle #666666.
120+
- **Snapshot upload**: Requires auth token from openboot.dev OAuth flow.
121+
- **install.sh**: Supports `OPENBOOT_DRY_RUN=true` and `OPENBOOT_INSTALL_DIR=path`.

internal/snapshot/AGENTS.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# SNAPSHOT PACKAGE
2+
3+
Environment capture, matching, and restoration. 8 files (4 source + 4 test), 1,783 lines.
4+
5+
## FILES
6+
7+
| File | Lines | Purpose |
8+
|------|-------|---------|
9+
| `capture.go` | 528 | Capture formulae/casks/taps/npm/prefs/shell/git/devtools |
10+
| `match.go` | 112 | Match captured packages against catalog, Jaccard similarity for preset detection |
11+
| `local.go` | 62 | Read/write snapshots to `~/.openboot/snapshot.json` |
12+
| `snapshot.go` | 61 | Data structures: Snapshot, PackageSnapshot, MacOSPrefs, ShellConfig |
13+
14+
## CAPTURE PIPELINE
15+
16+
`CaptureWithProgress()` runs 8 sequential steps, each reporting via callback:
17+
18+
1. Homebrew Formulae → `brew list --formula`
19+
2. Homebrew Casks → `brew list --cask`
20+
3. Homebrew Taps → `brew tap`
21+
4. npm Packages → `npm list -g --json`
22+
5. macOS Preferences → reads known defaults keys
23+
6. Shell Config → detects shell, oh-my-zsh, plugins, aliases
24+
7. Git Config → user.name, user.email, core.editor, etc.
25+
8. Dev Tools → version detection for node, go, python, rust, docker, etc.
26+
27+
Each step is independent. Failures are non-fatal (captured as empty).
28+
29+
## MATCHING LOGIC (match.go)
30+
31+
- `MatchPackages()`: Maps captured package names → catalog entries. Returns matched + unmatched lists.
32+
- `DetectBestPreset()`: Jaccard similarity between snapshot packages and each preset. Threshold: 0.3.
33+
- Package names matched case-insensitively against `config.Categories`.
34+
35+
## SNAPSHOT FORMAT
36+
37+
```json
38+
{
39+
"version": 1,
40+
"captured_at": "2026-01-15T10:30:00Z",
41+
"hostname": "macbook",
42+
"packages": {
43+
"formulae": ["curl", "wget"],
44+
"casks": ["visual-studio-code"],
45+
"taps": ["homebrew/core"],
46+
"npm": ["typescript"]
47+
},
48+
"macos_prefs": { ... },
49+
"shell_config": { ... },
50+
"git_config": { ... },
51+
"dev_tools": { ... }
52+
}
53+
```
54+
55+
## WHEN MODIFYING
56+
57+
- Adding capture step: Add to `CaptureWithProgress()`, update `totalSteps`, add to `Snapshot` struct
58+
- Adding preset detection: Modify `DetectBestPreset()` scoring in `match.go`
59+
- Tests: Table-driven with testify. `capture_test.go` mocks command output. `match_test.go` tests Jaccard scoring.

internal/ui/AGENTS.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# UI PACKAGE
2+
3+
TUI components built on Charmbracelet (bubbletea + lipgloss + huh). 5 files, 2,206 lines.
4+
5+
## FILES
6+
7+
| File | Lines | Purpose |
8+
|------|-------|---------|
9+
| `selector.go` | 986 | Package selector: tabs, fuzzy search, online search, multi-select |
10+
| `snapshot_editor.go` | 518 | Snapshot editing: diff view, toggle packages, confirm |
11+
| `progress.go` | 289 | StickyProgress: per-package timing, succeeded/failed/skipped counters |
12+
| `scanprogress.go` | 228 | Scan progress: step timing, overall counter `[3/8]` |
13+
| `ui.go` | 185 | Base styles, form helpers (SelectPreset, InputGitConfig, Confirm) |
14+
15+
## PATTERNS
16+
17+
- **bubbletea Model**: `selector.go` and `snapshot_editor.go` implement `tea.Model` (Init/Update/View)
18+
- **Sticky output**: `progress.go` writes directly to stderr via ANSI escape codes, not bubbletea
19+
- **Styles**: All lipgloss styles defined as package-level vars at top of file
20+
- **Color palette**: Primary=#22c55e, Subtle=#666, Warning=#eab308, Danger=#ef4444
21+
- **Width adaptation**: Components read `tea.WindowSizeMsg` and adapt layout
22+
23+
## SELECTOR ARCHITECTURE (selector.go)
24+
25+
Two render modes: normal (tab navigation) and search (`/` key).
26+
27+
- **Tab bar**: Sliding window — shows active tab + neighbors + `N/M` position. Adapts to terminal width.
28+
- **Search**: Fuzzy local match (sahilm/fuzzy) + debounced online search (500ms). Animated spinner during fetch.
29+
- **Toast**: 1.5s auto-fade notifications on toggle (`+ Added node` / `- Removed node`).
30+
- **Scroll**: `scrollOffset` + `getVisibleItems()` for height-adaptive list (5-20 items).
31+
- **Alt screen**: Uses `tea.WithAltScreen()` for full-screen mode.
32+
33+
## PROGRESS ARCHITECTURE (progress.go)
34+
35+
NOT a bubbletea model. Direct stderr writer for use during brew install.
36+
37+
- `IncrementWithStatus(success bool)` — tracks succeeded/failed count
38+
- `SetSkipped(count int)` — for already-installed packages
39+
- `Finish()` — prints summary line: `✔ 28 installed ○ 2 skipped ✗ 1 failed (1m23s)`
40+
- Thread-safe: called from 4 parallel brew workers via mutex
41+
42+
## WHEN ADDING NEW UI
43+
44+
1. Interactive full-screen → bubbletea Model in new file
45+
2. Progress/status during install → extend StickyProgress or ScanProgress
46+
3. Simple form input → use helpers in ui.go (huh-based)
47+
4. Styled text output → use ui.Header/Success/Error/Info/Warn/Muted

0 commit comments

Comments
 (0)