librecode is a local-first AI coding assistant and programmable terminal runtime written in Go. The default product experience is Go-owned for performance and polish; Lua extensions are optional escape hatches for commands, keymaps, hooks, tools, and small overlays.
After code changes, run all of:
mise exec -- go test ./...
mise exec -- task build
mise exec -- task ciReport the results before committing. Use mise exec -- for Task/Go tooling in this repo.
mise exec -- task build # build ./bin/librecode
mise exec -- task run # build and run
mise exec -- task test # tests with race detector
mise exec -- task test-coverage # coverage report
mise exec -- task lint # golangci-lint
mise exec -- task fmt # auto-format and auto-fix lint issues
mise exec -- task fmt-check # check formatting without modifying files
mise exec -- task ci # non-mutating full CI pipelinecmd/librecode/ # Cobra CLI commands and entrypoint
internal/assistant/ # assistant runtime, model retry, tool loop, slash commands
internal/auth/ # provider auth and credential storage
internal/config/ # YAML/env/default config loading and validation
internal/core/ # resources, skills, system prompt helpers
internal/database/ # SQLite sessions/migrations and ksqlDB client
internal/di/ # samber/do dependency registration
internal/event/ # in-process event bus
internal/extension/ # trusted Lua extension host/runtime
internal/model/ # model/provider registry
internal/terminal/ # TUI rendering/input/session UX
internal/tool/ # built-in tools: read, bash, edit, write, grep, find, ls
internal/vinfo/ # build version info
- Keep the default terminal UI, transcript rendering, composer, autocomplete, resize behavior, sessions, tools, and provider orchestration in Go.
- Keep Lua extensions optional and trusted. They may customize behavior, but the default UX must remain fast and polished without extensions.
- Prefer primitive extension APIs (
buf,win,layout,ui,keymap,timer, lifecycle events) plus higher-level helpers in Lua/userland. - Avoid adding product-specific host APIs unless they are clearly needed by the Go core.
- Skills follow the Agent Skills
SKILL.mddirectory convention with project-local roots taking priority.
Useful docs:
docs/runtime-architecture.mddocs/extension-api.mddocs/extension-runtime.mddocs/extension-roadmap.mddocs/skills.mddocs/rendering-boundary.md
- Follow existing package patterns and keep changes small/focused.
- Use
oops.In("domain").Code("code").Wrapf(err, "message")for contextual errors where the package already usessamber/oops. - Never ignore errors;
errcheckwithcheck-blank: trueis enabled. - Handle
fmt.Fprintf/fmt.Fprintlnreturn values. - Keep the default render path hot and allocation-conscious; do not route default UI through Lua unless explicitly required and benchmarked.
- Prefer table-driven tests for core behavior and regression tests for terminal rendering bugs.
- Add a focused file under
cmd/librecode/. - Expose a
newXCmd()constructor returning*cobra.Command. - Register it from the appropriate parent command.
- Add tests for argument validation and user-visible behavior when practical.
- Create the service under the appropriate
internal/package. - Register dependencies in
internal/di/register.gowhen the service is app-wide. - Inject via
do.MustInvoke/do.Invokefollowing existing patterns.
The public bash tool requires a Bash-compatible shell. On Windows, librecode should prefer configured/Git Bash/MSYS2/Cygwin/WSL Bash and should not silently fall back to cmd.exe for Bash semantics.