# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Core CLI (`forge.lthn.ai/core/cli`) is a Go CLI tool for managing development workflows across Go, PHP, and Wails projects. It wraps common tooling (testing, linting, building, releasing, multi-repo management) behind a unified `core` command. Built on Cobra with the Core framework's dependency injection for service lifecycle management. ## Build & Development Commands ```bash # Run all tests go test ./... # Run a single test go test -run TestName ./... # Build CLI binary go build -o dist/core . # Install from source go install forge.lthn.ai/core/cli@latest # Verify environment go run . doctor # Format and lint gofmt -w . go vet ./... golangci-lint run ./... ``` **Go version:** 1.26+ ## Architecture ### Entry Point & Command Registration `main.go` wires everything together. Commands register in two ways: 1. **Explicit registration** via `cli.WithCommands()` — local command packages in `cmd/` pass an `AddXCommands(root *cli.Command)` function that receives the root cobra command during service startup. 2. **Self-registration** via `cli.RegisterCommands()` — ecosystem packages (imported as blank `_` imports in `main.go`) call `cli.RegisterCommands()` in their `init()` functions. This is how external modules like `go-build`, `go-devops`, `go-scm`, `agent`, etc. contribute commands without coupling to `main.go`. ### `pkg/cli` — The CLI Runtime This is the core package. Everything commands need is re-exported here to avoid direct Cobra/lipgloss/bubbletea imports: - **`runtime.go`**: Singleton `Init()`/`Shutdown()`/`Execute()` lifecycle. Creates a Core framework instance, attaches services, handles signals (SIGINT/SIGTERM/SIGHUP). - **`command.go`**: `NewCommand()`, `NewGroup()`, `NewRun()` builders, flag helpers (`StringFlag`, `BoolFlag`, etc.), arg validators — all wrapping Cobra types so command packages don't import cobra directly. `Command` is a type alias for `cobra.Command`. - **`output.go`**: Styled output functions — `Success()`, `Error()`, `Warn()`, `Info()`, `Dim()`, `Progress()`, `Label()`, `Section()`, `Hint()`, `Severity()`. Use these instead of raw `fmt.Print`. - **`errors.go`**: `Err()`, `Wrap()`, `WrapVerb()`, `Exit()` for error creation. Re-exports `errors.Is`/`As`/`Join`. Commands should return errors (via `RunE`), not call `Fatal()` (deprecated). - **`frame.go`**: Bubbletea-based TUI framework. `NewFrame("HCF")` with HLCRF region layout (Header, Left, Content, Right, Footer), focus management, content navigation stack. - **`tracker.go`**: `TaskTracker` for concurrent task display with spinners. TTY-aware (live updates vs static output). - **`daemon.go`**: Execution mode detection (`ModeInteractive`/`ModePipe`/`ModeDaemon`). - **`styles.go`**: Shared lipgloss styles and colour constants. - **`glyph.go`**: Shortcode system for emoji/symbols (`:check:`, `:cross:`, `:warn:`, `:info:`). ### Command Package Pattern Every command package in `cmd/` follows this structure: ```go package mycommand import "forge.lthn.ai/core/cli/pkg/cli" func AddMyCommands(root *cli.Command) { myCmd := cli.NewGroup("my", "My commands", "") root.AddCommand(myCmd) // Add subcommands... } ``` Commands use `cli.NewCommand()` (returns error) or `cli.NewRun()` (no error) and the `cli.StringFlag()`/`cli.BoolFlag()` helpers for flags. ### External Module Integration The CLI imports ecosystem modules as blank imports that self-register via `init()`: - `forge.lthn.ai/core/go-build` — build, CI, SDK commands - `forge.lthn.ai/core/go-devops` — dev, deploy, docs, git, setup commands - `forge.lthn.ai/core/go-scm` — forge, gitea, collect commands - `forge.lthn.ai/core/agent` — agent, dispatch, task commands - `forge.lthn.ai/core/lint` — QA commands - Others: go-ansible, go-api, go-container, go-crypt, go-infra ### Daemon/Service Management `cmd/service/` implements `start`/`stop`/`list`/`restart` for manifest-driven daemons. Reads `.core/manifest.yaml` from the project directory (walks up). Daemons run detached with `CORE_DAEMON=1` env var and are tracked in `~/.core/daemons/`. ## Test Naming Convention Tests use `_Good`, `_Bad`, `_Ugly` suffix pattern: - `_Good`: Happy path tests - `_Bad`: Expected error conditions - `_Ugly`: Panic/edge cases ## Commit Message Convention [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`, `refactor:`, `chore:` ## Configuration - Global config: `~/.core/config.yaml` (YAML, dot-notation keys) - Project config: `.core/build.yaml`, `.core/release.yaml`, `.core/ci.yaml` - Environment override: `CORE_CONFIG_` (underscores become dots, lowercased) - Multi-repo registry: `repos.yaml` (searched cwd upward, then `~/.config/core/repos.yaml`) ## i18n Commands use `i18n.T("key")` for translatable strings and the grammar system (`i18n.ActionFailed()`, `i18n.Progress()`) for consistent error/progress messages. The CLI wraps these in `cli.Echo()`, `cli.WrapVerb()`, `cli.ErrorWrapVerb()`.