ajhahn.de
← eeco
Markdown 114 lines
<div align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="assets/eeco_logo_dark.png">
    <img src="assets/eeco_logo_light.png" alt="eeco" width="280">
  </picture>

<h1>Contributing</h1>

<p><i>How to build, which checks must pass, and the rules a change holds to.</i></p>

<p>
    <a href="README.md"><b>README</b></a> ·
    <a href="VISION.md"><b>Vision</b></a> ·
    <a href="docs/COCKPIT.md"><b>Cockpit</b></a> ·
    <a href="docs/USAGE.md"><b>Usage</b></a> ·
    <a href="docs/ARCHITECTURE.md"><b>Architecture</b></a> ·
    <a href="docs/PUBLIC_API.md"><b>Public API</b></a> ·
    <a href="EXTENDING.md"><b>Extending</b></a> ·
    <b>Contributing</b> ·
    <a href="docs/UPGRADING.md"><b>Upgrading</b></a> ·
    <a href="VERSIONING.md"><b>Versioning</b></a> ·
    <a href="CHANGELOG.md"><b>Changelog</b></a> ·
    <a href="SECURITY.md"><b>Security</b></a>
  </p>

</div>

---

## Contributing to eeco

eeco is a solo project with a deliberately small contribution surface. This is a
lightweight contract — how to build, which checks must pass, and the rules a
change holds to — not community-health boilerplate. For how to *add* something —
a workflow, a config key, a verb — see [EXTENDING.md](EXTENDING.md).

## Build and checks

eeco builds with the Go toolchain through a `Makefile`:

| Command              | What it does                                                                 |
| -------------------- | ---------------------------------------------------------------------------- |
| `make build`       | Build the single `eeco` binary.                                            |
| `make verify`      | `go build ./...` + `go vet ./...` + `go test ./...`.                   |
| `make gates`       | Run the `comment-hygiene`, `leak-guard`, and `version-sync` workflows. |
| `make lint`        | `golangci-lint` — must report **0 issues**.                         |
| `make cover-check` | Fail if total statement coverage drops below the ratchet floor.              |
| `make bench`       | Scanner benchmarks; keep them under the five-second budget.                  |
| `make sync-guide`  | Mirror `docs/USAGE.md` into the in-binary guide after editing it.          |

## Definition of Done

A change is done when **all** of these hold:

- **`make verify` green** — build, vet, and tests pass.
- **`make gates` green**`comment-hygiene`, `leak-guard`, `version-sync`.
- **`make lint` green**`golangci-lint`, 0 issues.
- **`make cover-check` green** — total statement coverage does not regress.
- **Additive over the public surface** — no change to an item frozen in
  [`docs/PUBLIC_API.md`](docs/PUBLIC_API.md) unless a semver bump is explicitly
  declared; when one is, the README version badge is bumped **before** the tag.
- **No AI attribution** — no AI-tool fingerprint or `Co-Authored-By` trailer in
  any commit, tag, file, or PR body.
- **CHANGELOG entry when user-facing** — a binary- or user-facing change gets a
  [CHANGELOG.md](CHANGELOG.md) entry; infra-only changes (CI, scripts) do not.

## Public surface and versioning

From v0.1.0, eeco follows Semantic Versioning over the surface frozen in
[`docs/PUBLIC_API.md`](docs/PUBLIC_API.md): the CLI verbs and flags, the
`eeco go --json` keys, exit codes, config keys, memory frontmatter fields, the
queue / ledger / hook formats, and the builtin workflow names. Nothing outside
that list is covered. Adding to the surface is a MINOR bump; post-1.0, changing
or removing a frozen item is a MAJOR bump with the deprecation window described
in [`VERSIONING.md`](VERSIONING.md). While eeco is pre-1.0 (`v0.x`) a MINOR MAY
change or remove a frozen item with a CHANGELOG migration note — see
[`VERSIONING.md`](VERSIONING.md) §2.1. Keep changes additive by default.

## Trust boundaries

Three invariants are sacred and are pinned by the boundary suite
(`*_boundary_test.go`):

- **The engine never writes the tracked tree.** Only the command-layer
  `initgit.go` / `historygit.go` write git, and only to the workspace's own
  private history — never the host repository.
- **Hooks stay reversible.** Every hook records its install in a ledger and
  removes byte-identically; disabling a hook restores the prior state exactly.
- **AI stays gated.** No AI call happens without consent and budget, and when
  memory or input is malformed the AI path degrades instead of failing the
  command.

A change that touches these areas keeps the boundary suite green. Treat a
boundary-test failure as a design error, not a test to update.

## Working habit

Big or design-forked changes get a short planning pass before code; small,
mechanical changes can be planned and built in one go. Either way: edit on a
branch, get the Definition of Done green, keep the change additive (or declare
the bump), add a one-line CHANGELOG entry when it is user-facing, and open a PR.

## Pull requests

Clone, branch, and make your change. Run `make verify`, `make gates`,
`make lint`, and `make cover-check` until they are green; intent-add any new
files (`git add -N <path>`) before `leak-guard` so it scans them. Open the PR
with the [template](.github/PULL_REQUEST_TEMPLATE.md) and link any
[issue](.github/ISSUE_TEMPLATE).

---

[← Prev: Extending](EXTENDING.md) · [Next: Upgrading →](docs/UPGRADING.md)