Thanks for your interest in contributing!
- Go 1.26+
- Git
git clone https://github.com/dotcommander/piglet
cd piglet
go build ./...
go test -race ./...
go vet ./...All three must pass before submitting a PR. CI runs them automatically on every push and PR.
Piglet is extension-first. The core agent loop (core/) imports nothing from piglet — all functionality registers through ext.App. An architecture test enforces dependency boundaries:
go test ./ext/... -run TestArchitectureKey rule: new functionality should be an extension, not a core modification. See CLAUDE.md for the full architecture overview.
core/ Agent loop, streaming, types (imports nothing from piglet)
ext/ Registration surface (ext.App)
tool/ Built-in tools (read, write, edit, bash, grep, find, ls)
command/ Built-in slash commands
prompt/ System prompt builder
provider/ OpenAI, Anthropic, Google streaming
sdk/ Go Extension SDK (standalone module)
tui/ Bubble Tea v2 terminal UI
Extensions are the preferred way to add functionality. They run as standalone binaries communicating via JSON-RPC over stdin/stdout.
# Scaffold a new extension from inside piglet:
/ext-init my-extensionSee docs/extensions.md for the SDK reference and examples/extensions/ for working code.
Official extensions live in a separate repo: piglet-extensions.
- Fork the repo and create a branch from
main - Make your changes
- Add tests for new functionality
- Ensure
go build ./...,go test -race ./..., andgo vet ./...pass - Submit a pull request
Use conventional commits:
feat(tool): add support for binary file detection
fix(provider): handle empty SSE data lines
docs: update extension SDK examples
test(session): add fork/branch coverage
- Focused — one feature or fix per PR
- Tested — new code has tests, existing tests still pass
- Clean — no unrelated changes, no debug output, no commented-out code
- Modifying
core/without a strong reason (everything should be an extension) - Adding dependencies without checking if an existing one covers the need
- Hardcoding configuration data in Go source — prompts, defaults, and behavioral text belong in config files under
~/.config/piglet/ - Committing secrets, local paths, or binary artifacts
- Short functions (80 lines max)
- Pointer receivers by default
context.Contextas first paramfmt.Errorfwith%wfor error wrapping- No
init(), no mutable package globals t.Parallel()on all tests- Table-driven tests for multiple cases
See CLAUDE.md for the complete conventions.
Open an issue with:
- What you expected
- What happened
- Steps to reproduce
- Go version and OS
By contributing, you agree that your contributions will be licensed under the MIT License.