# AGENTS.md ## Overview clnkr is a coding agent CLI that queries LLMs and executes bash commands in a loop. Core library is stdlib only. Talks to the Anthropic Messages API and any OpenAI-compatible endpoint. Ships `clnkr` (plain CLI) and `clnkrd` (stdio JSONL adapter). Evals run through the standalone `clankerval` project. ## Commands ``` make build # Build shipped binaries (default target) make test # Run all tests make check # Run the full quality suite make man # Generate staged man pages from doc/*.1.md make docs # Build the documentation site make docs-serve # Run the documentation site locally make _fmt # Format source make _hooks # Configure repo-local Git hooks ``` Run `make _fmt` then `make check` before committing. Do not commit if either fails. ## Rules - No external deps in root go.mod. Stdlib only. - Assume Unix (`bash`, process groups, `/usr/bin/env`). Windows unsupported. - Root `clnkr` is the only public import surface. `internal/` is allowed when it clarifies ownership. - Output goes through typed events. Do not add `io.Writer` parameters. - Policy logic in `Run()`, shared logic in `Step()`. No policy in `Step()`. - CLI config resolution stays in `cmd/internal/providerconfig`: env/flag precedence, `CLNKR_*`, API keys, base URL parsing, provider detection, and user-facing config errors. - Provider request semantics stay in `internal/providers/providerconfig`: provider/API constants, request options, model capability checks, and provider-specific validation. - Provider adapters serialize validated options; they do not resolve CLI config. - Wrap errors: `fmt.Errorf("context: %w", err)`. No bare returns or third-party error packages. - Adapter tests use external packages (`package anthropic_test`). Core tests use internal (`package clnkr`). CLI tests use internal (`package main`). Match the existing pattern. - `exhaustive` linter is enabled. Switch on sealed types must cover all cases. `default` counts as exhaustive. - Do not manually edit `CHANGELOG.md`; generated by the release pipeline. - Do not hand-edit generated files in `build/docs/`, `site/content/docs/clnkr.md`, `site/content/docs/clnkrd.md`, or `site/public/`. - Public-facing docs describe current behavior, not implementation history. No `in this pass`, `for now`, `currently deferred`. - SLOC gates count non-test Go only. Treat them as invariants and honesty constraints: do not shrink counted CLI help, diagnostics, UX, or error clarity to satisfy them, and do not weaken tests or docs to normalize that kind of regression. Agents must not raise SLOC limits unless the user explicitly gives a target number. If raising a gate is the only reasonable path, stop and ask for clarification. - For changes that touch clnkr's agent design, read `doc/clnkr.7.md` for current architecture context: act protocol, transcript, provider boundary, command execution, and 12-factor mapping. It is descriptive, not prescriptive. Verify behavior in code and follow this file for rules. - Repo-maintenance helpers live under `scripts/`. Read `scripts/README.md` before adding new ones. ## Architecture Core importable library at module root. Two command adapters. `evaluations/` consumed by external `clankerval` runner. ``` clnkr/ # core: types, Agent, events (stdlib only) ├── internal/providers/ # Anthropic/OpenAI adapters ├── cmd/clnkr/ # Plain CLI (root go.mod, no external deps) ├── cmd/clnkrd/ # Stdio JSONL adapter └── evaluations/ # Eval suites for clankerval ``` **Agent API:** `Step()` = one typed-turn cycle, no policy. `ExecuteTurn()` = run an act turn, update state, emit events. `Run()` = full-send policy loop (3 consecutive protocol failures = exit). **Act protocol:** Three turn types: `act`, `clarify`, `done`. Providers own wire translation. Root `ParseTurn` validates canonical internal JSON for replay/tests only. **Events:** Sealed interface, five types: `EventResponse`, `EventCommandStart`, `EventCommandDone`, `EventProtocolFailure`, `EventDebug`. Nil `Notify` = silent. **Command results (host→model):** JSON with `stdout`, `stderr`, `outcome`, and optional `feedback`. Exit outcomes include `exit_code`; non-exit outcomes include timeout, cancelled, denied, skipped, and error. ## Release Tag-driven. Push feature to `main`, wait for CI/evals/site to go green, then push the plain semantic version tag. Release workflow triggers from semver tags, updates `debian/main`, and generates Debian changelog. Remote `main` may move. Fetch and rebase before follow-up pushes. ## Evals Optimize for live runs that measure actual agent behavior. Fixture evals exist for harness determinism in CI, not as the primary signal. `clankerval` requires a clean checkout. Make a temporary commit from a dirty worktree, run, then unroll. ## Site Hugo site under `site/`. Source of truth for reference docs is `doc/*.1.md`. Run `make docs` to regenerate. Do not commit `site/public/`. Deployment to `gh-pages` is automatic from `main`. ## Testing - Provider adapters: `httptest.NewServer`, external test packages, no real API calls - Agent loop: `fakeModel`/`fakeExecutor` in `agent_test.go` - CLI: inject via narrowest local interface, not concrete structs - Executor: real shell integration tests; handles macOS `/private/tmp` symlink ## CI GitHub Actions on push to `main` and PRs. Runs lint, tests (`-race`), build, docs, and evals. `make check` also enforces architecture edges and core SLOC accounting. Run `make _hooks` for local pre-commit. golangci-lint required.