Architecture
mine is a single Go binary built with Cobra (CLI), Lipgloss (styling), and SQLite (storage). It follows a clean domain separation pattern where each feature is an independent package under internal/.
Directory Structure
Section titled “Directory Structure”mine/├── main.go # Entry point — calls cmd.Execute()├── cmd/ # Command definitions (Cobra)│ ├── root.go # Dashboard, command registration│ ├── init.go # First-time setup│ ├── todo.go # Todo CRUD subcommands│ ├── stash.go # Dotfile management│ ├── craft.go # Project scaffolding│ ├── dig.go # Focus timer│ ├── shell.go # Shell completions & aliases│ ├── config.go # Config display│ └── version.go # Version info├── internal/ # Domain logic (not exported)│ ├── config/ # XDG config management│ │ ├── config.go # Load, save, paths│ │ └── config_test.go│ ├── store/ # SQLite database│ │ └── store.go # Connection, migrations│ ├── todo/ # Todo domain│ │ ├── todo.go # Models, queries, store│ │ └── todo_test.go│ ├── ui/ # Terminal UI│ │ ├── theme.go # Colors, icons, styles│ │ └── print.go # Output helpers│ └── version/ # Build metadata│ └── version.go├── site/ # Documentation site (Astro Starlight)├── scripts/ # Build & install helpers├── .github/ # CI/CD workflows├── .goreleaser.yaml # Release configuration├── Makefile # Build commands└── CLAUDE.md # Project knowledge baseDesign Patterns
Section titled “Design Patterns”1. Thin Command Layer
Section titled “1. Thin Command Layer”Files in cmd/ are orchestration only. They:
- Parse arguments and flags
- Call domain logic in
internal/ - Format output using
internal/ui
They do not contain business logic or direct database queries.
Hook wrapping is mandatory. Every Cobra command handler must use RunE (not Run) and be wrapped with hook.Wrap:
var myCmd = &cobra.Command{ RunE: hook.Wrap("domain.subcommand", runMyCommand),}This ensures all commands are observable and extensible by plugins and user hooks. A command that bypasses hook.Wrap breaks the extensibility guarantee. The hook name must follow the domain.subcommand convention (e.g. plugin.install, todo.add).
2. Domain Packages
Section titled “2. Domain Packages”Each feature owns its domain under internal/:
todoowns the todo model, queries, and store interfaceconfigowns configuration loading and XDG path resolutionstoreowns database connection, pragmas, and migrationsuiowns all terminal styling and output formatting
Packages don’t import each other unnecessarily. store.DB provides *sql.DB via .Conn(), and domain packages accept *sql.DB directly.
3. Progressive Migration
Section titled “3. Progressive Migration”Schema changes are defined in store.migrate() and auto-applied on every store.Open(). This means:
- No migration CLI needed
- Database always matches expected schema
- New tables added with
CREATE TABLE IF NOT EXISTS - Safe for concurrent reads (WAL mode)
4. XDG Compliance
Section titled “4. XDG Compliance”All file paths follow the XDG Base Directory Specification:
| Purpose | Path | Env Override |
|---|---|---|
| Config | ~/.config/mine/ | $XDG_CONFIG_HOME |
| Data | ~/.local/share/mine/ | $XDG_DATA_HOME |
| Cache | ~/.cache/mine/ | $XDG_CACHE_HOME |
| State | ~/.local/state/mine/ | $XDG_STATE_HOME |
5. Consistent UI
Section titled “5. Consistent UI”All output goes through internal/ui helpers:
ui.Ok(),ui.Err(),ui.Warn()— semantic messagesui.Kv()— key-value pairs with consistent paddingui.Header()— section headersui.Tip()— contextual tipsui.Greet()— personality-infused greetings
Never use raw fmt.Println in commands.
6. Terminal Markdown Rendering
Section titled “6. Terminal Markdown Rendering”internal/ui provides a reusable MarkdownWriter adapter for rendering AI streaming output as styled terminal markdown via glamour.
mdw := ui.NewMarkdownWriter(os.Stdout, rawFlag)provider.Stream(ctx, req, mdw)mdw.Flush()Mode selection:
| Context | Behaviour |
|---|---|
| TTY + default | Buffer chunks, render as styled markdown on Flush |
| Non-TTY / piped | Pass-through immediately (no buffering) |
--raw flag | Pass-through immediately (no buffering) |
If renderer initialisation or rendering fails, Flush falls back to emitting raw markdown and prints a warning to stderr — commands always produce output.
Commands using this pattern: mine ai ask, mine ai review.
Data Flow
Section titled “Data Flow”SQLite Configuration
Section titled “SQLite Configuration”The database uses performance-optimized pragmas:
journal_mode=WAL— concurrent reads, single writersynchronous=NORMAL— safe with WALcache_size=-64000— 64MB in-memory cacheforeign_keys=ON— referential integritytemp_store=MEMORY— temp tables in RAMbusy_timeout=5000— 5s retry on lock contention
Build System
Section titled “Build System”make build— builds with ldflags for version injectionmake test— runs the Go test suite- GoReleaser handles cross-compilation for releases
- CI runs vet, test (with coverage), build, and smoke test
Plugin System
Section titled “Plugin System”mine supports extensibility via plugins:
Plugins are standalone binaries that communicate via JSON-over-stdin. See the Plugin Protocol for details.
Contribution Workflow (internal/contrib/)
Section titled “Contribution Workflow (internal/contrib/)”The contrib package orchestrates AI-assisted contribution workflows. It has no persistent
storage — all operations are transient GitHub API calls and local filesystem operations via
the gh CLI.
Key responsibilities:
- Repo slug validation (
ValidateRepo) - Issue fetching and selection policy (
FetchCandidateIssues,FetchIssue) - Fork detection and creation (
CheckForkState,EnsureFork) - Clone and branch setup (
CloneRepo,CreateBranch,BranchName)
The cmd/contrib.go command wires these together with:
- An explicit opt-in confirmation prompt before any action
- A clear warning that actions use the user’s own GitHub quota
- TTY-aware issue selection (interactive picker in TTY,
--issuerequired otherwise) - Optional
--tmuxflag for a two-pane workspace
mine meta contrib is a thin shortcut in cmd/meta.go that calls the same flow
with rnwolfe/mine as the target repo.