Contributing to Clawker

August 16, 2026 · View on GitHub

Thanks for your interest in contributing to Clawker! This project is currently in alpha, maintained by a solo developer opening up for community contributions. All skill levels welcome.

Getting Started

Prerequisites

  • Go 1.26+
  • Docker running locally
  • Git

Development Setup

git clone https://github.com/schmitthub/clawker.git
cd clawker
git submodule update --init
make clawker
export PATH="$PWD/bin:$PATH"

go install ./cmd/clawker and bare go build ./cmd/clawker are unsupported — they fail at compile time because the four Linux assets (clawkerd, clawkercp, ebpf-manager, coredns-clawker) referenced by //go:embed are gitignored. make clawker produces them via the per-target chain (clawkerd-binary, cp-binary, ebpf-binary, coredns-binary) and then builds the host CLI. All four are plain CGO_ENABLED=0 Go cross-compiles to linux/$GOARCH; the only Docker hop is the bpf-bindings extraction needed on macOS (where clang cannot emit BPF object files) — Linux contributors install the pinned BPF toolchain once with sudo make bpf-deps and everything builds natively. The make release-embeds / make stage-embeds-{amd64,arm64} targets are for the goreleaser pipeline; contributors do not invoke them for local development.

Running Tests

Clawker has multiple test tiers. All relevant tests must pass before submitting a PR.

# Unit tests (no Docker required) — run these first
make test

# Integration tests (Docker required)
go test ./test/e2e/... -v -timeout 10m        # E2E integration
go test ./test/whail/... -v -timeout 5m       # Whail BuildKit integration

# All test suites
make test-all

Golden File Tests

Some tests use golden files for output comparison. To update golden files after intentional changes:

GOLDEN_UPDATE=1 go test ./path/to/package/... -run TestName -v

Code Style

Key Rules

  • zerolog is for file logging only — user-visible output uses fmt.Fprintf to IOStreams
  • Import boundaries are enforced:
    • Only internal/iostreams imports lipgloss
    • Only internal/tui imports bubbletea/bubbles
    • Only internal/term imports golang.org/x/term
    • Only pkg/whail wraps the Docker SDK; only internal/docker imports pkg/whail
  • Cobra commands use PersistentPreRunE (never PersistentPreRun)
  • Output conventions: stdout for data, stderr for status/warnings/errors
  • Error handling: Return typed errors to Main() — never print errors directly

Command Pattern

Every CLI command follows the Factory/Options/runF pattern:

  1. NewCmd(f *cmdutil.Factory, runF func(*Options) error) constructor
  2. Options struct declares only what the command needs
  3. Run function receives *Options, never *Factory

See docs/architecture.mdx for the full pattern with examples.

Making Changes

Branch Naming

Use descriptive branch names:

  • feat/description — New features
  • fix/description — Bug fixes
  • refactor/description — Code improvements
  • docs/description — Documentation changes

What to Include in a PR

  1. Code changes with tests
  2. Updated documentation — if you change a package's public API, update its CLAUDE.md and relevant docs
  3. Passing tests — run make test at minimum before submitting
  4. A changelog entry — if the PR changes the user surface or adds behavior (see below)

Changelog

The root CHANGELOG.md is the curated, human, user-facing changelog, in Keep a Changelog format. It is not the exhaustive commit log — that is generated per release into the GitHub release's "Commits" section. CHANGELOG.md intentionally covers only the handful of releases that change what a user sees or does.

  • If your PR changes the user surface or adds behavior (a new command or flag, a behavior change, a user-visible fix, a breaking change), add an entry in the same PR, so it is committed before the release tag. Releases are cut by tagging main, and the release notes are rendered from the committed file — an entry added after the tag misses that release.
  • Tech-debt, refactor, chore, and dependency-bump PRs add nothing. They are not user-facing and do not belong in the curated changelog.

Entry format. Add a new ## [VERSION] - DATE section at the top, with the Keep a Changelog ### Added / ### Changed / ### Fixed / ### Removed body. Also add the matching reference-link line at the bottom of the file. The format is plain Keep a Changelog — there is no per-entry metadata; the whole section body is rendered verbatim as markdown.

## [0.13.0] - 2026-07-01

### Added

- **Headline of the change.** A sentence or two of user-facing detail.
  Link relevant docs inline where they belong: [Docs](https://docs.clawker.dev/some-page).

Put docs links inline in the bullet next to the change they describe. HTML comment lines are stripped from the rendered body, so a metadata comment would be silently dropped — don't add one.

One source, two surfaces. The same CHANGELOG.md feeds a show-once-on-upgrade teaser (printed on the first interactive run after an upgrade — except the first changelog-aware run, which seeds last_seen_changelog to the current version and shows nothing, with no catch-up backfill) and the curated header at the top of the GitHub release notes. The CLI does not embed the file — it fetches the raw CHANGELOG.md from main over the network at runtime (the CLI runs on the host and is always online). GitHub release notes are currently produced by GoReleaser's auto changelog groups (not extracted from CHANGELOG.md in CI yet). There is no second source to keep in sync.

PR Processs

  1. Fork the repository
  2. Create a feature branch from main
  3. Make your changes with tests
  4. Ensure make test passes
  5. Open a PR against main
  6. Describe what changed and why in the PR description

PRs are reviewed by the maintainer. Expect feedback within a few days. For larger changes, open an issue first to discuss the approach.

Architecture

Before making significant changes, familiarize yourself with the codebase:

Package-specific docs live in internal/*/CLAUDE.md files.

Issue Labels

LabelDescription
bugBug reports
enhancementFeature requests
good first issueBeginner-friendly tasks
known-issueKnown bugs or limitations
roadmapPlanned features

Code of Conduct

Please read and follow our Code of Conduct. Be kind, be constructive, be welcoming.

License & Contributor Agreement

Clawker is dual-licensed: AGPL-3.0-or-later for everyone, with commercial licenses available from the maintainer. So that contributions can ship under both, this project uses a Contributor License Agreement: you keep copyright of your work, your contribution is published under the AGPL-3.0-or-later, and you grant the maintainer the right to also license it under commercial terms.

One subproject is the exception: the clawker-support plugin, tracked as the clawker-plugin/ git submodule (schmitthub/clawker-plugin), is licensed separately under the MIT License (see its LICENSE file).

Read the full text in CLA.md. On your first pull request, a CLA assistant asks you to sign by commenting a short confirmation phrase; merging is gated until you do.