Two files, one repository
devopsfactory-io/neptune ships 3 formats across 8 indexed files. The question worth asking is whether the second one says anything the first does not.
| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 15 | 9 | 0% |
| Commands | 5 | 9 | 7 | 24% |
| Section tags | 5 | 4 | 4 | 38% |
What each file covers
Sections
0 shared · 15 only in A · 9 only in B- − AGENTS.md
- − Project Overview
- − Repository Structure
- − Setup Commands
- − Build binary
- − Run all tests (main module)
- − Lambda (separate module under lambda/): build, package, test
- − Check Go formatting (includes lambda/)
- − Lint (optional; requires golangci-lint)
- − Code Style
- − Testing
- − CI
- − Documentation and AI Context (Mandatory)
- − PR Guidance
- − References
- + Neptune
- + Mandatory Rules
- + DCO Sign-off
- + Documentation After Changes
- + Issue Creation Validation
- + Go Standards
- + Config Schema (`.neptune.yaml`)
- + CI and Release
- + Agents, Commands, and Skills
Commands
5 shared · 9 only in A · 7 only in B- − make build
- − make test-all
- − make lambda.build
- − make lambda.zip
- − make lambda.test
- − make lint
- − go test ./...
- − make e2e
- − go.*
- + git config user.name
- + git config user.email
- + git config user.name "<resolved name>"
- + git config user.email "<resolved email>"
- + gh api user --jq '.name,.email'
- + gh api user/emails --jq '.[].email'
- + go-developer
- make check-fmt
- go.mod
- gh issue create
- git commit -s
- git commit --amend -s --no-edit
Section tags
5 shared · 4 only in A · 4 only in B- − setup
- − build
- − test
- − architecture
- + types
- + database
- + deployment
- + do-not
- lint-format
- code-style
- testing-strategy
- git-pr
- docs
Line diff
devopsfactory-io/neptune · AGENTS.md
@@ −1 @@
1# AGENTS.md
2
3Guidance for AI coding agents working on the Neptune project.
4
5---
6
7## Project Overview
8
9**Neptune** is a Terraform and OpenTofu pull request automation tool inspired by [Atlantis](https://github.com/runatlantis/atlantis). It runs plan/apply (Terraform or OpenTofu) on pull requests using the [Terramate](https://github.com/terramate-io/terramate) Go SDK for change detection and run order. When a step has `once` false or unset (default), Neptune runs the step’s command in each changed stack (Terramate SDK or local stacks; no Terramate CLI needed when using Terramate); object storage (GCS or S3) is used for stack locking, and GitHub for PR requirements and comments.
10
11**Main capabilities**: Load config from `.neptune.yaml` and env; in CI (non-E2E), config is loaded from the repository’s default branch via git (fallback to PR branch) so PR authors cannot change workflow steps; check PR requirements (approved, mergeable, undiverged, rebased); lock stacks in object storage (GCS, AWS S3, or S3-compatible e.g. MinIO); run workflow steps (per-stack by default, or once in root when `once: true`); for stacks_management: local, **neptune stacks** provides list (--changed) and create, with **--format** (json, yaml, text, formatted; default formatted); when using discovery, run order can be set via **depends_on** in each **stack.hcl** (path-only; relative paths and directory-of-stacks supported); post results as PR comments. Optional `repository.automerge: true` enables PR auto-merge after a successful apply (GitHub GraphQL). Log level is configurable via `log_level` (config), `NEPTUNE_LOG_LEVEL`, or the global **--log-level** CLI flag (DEBUG, INFO, ERROR).
12
13**Language**: Go (see `go.mod`).
14
15---
16
17## Repository Structure
18
19- **`main.go`** – Entry point; version/commit/date via ldflags.
20- **`cmd/`** – CLI (Cobra): `root.go` (global **--log-level** flag), `version.go`, `command.go`, `unlock.go`, `stacks.go` (stacks list, create; **--format** json|yaml|text|formatted, default formatted; **neptune stacks create** supports optional **--depends-on** comma-separated paths). **neptune stacks list** and **neptune stacks create** are for local use and do not require `GITHUB_TOKEN` or other CI env vars (unlike **neptune command** and **neptune unlock**).
21- **`internal/config`** – Load env + YAML, validate `.neptune.yaml` (including optional `log_level`, `stacks_management`, root-level `local_stacks`).
22- **`internal/domain`** – Config, lock, run, and GitHub domain structs (WorkflowStep uses `once`; RepositoryConfig has `StacksManagement`, `LocalStacks`).
23- **`internal/log`** – Structured logging (DEBUG, INFO, ERROR) via `log/slog`; level from `NEPTUNE_LOG_LEVEL` or config `log_level`.
24- **`internal/stacks`** – Stacks provider interface (terramate, local); list/changed stacks for locking and runner.
25- **`internal/lock`** – Lock interface: gets stack list from stacks provider, object-storage lock files (GCS, S3).
26- **`internal/run`** – Execute workflow phase steps (shell).
27- **`internal/github`** – GitHub API client, PR requirements (approved, mergeable, undiverged), commit statuses (GetHeadSHA, CreateCommitStatus) for **neptune plan** / **neptune apply**; GraphQL EnablePullRequestAutoMerge when `repository.automerge` is true.
28- **`internal/git`** – Rebased check; DefaultBranch (git CLI), ShowFileFromRef, FetchBranch for loading config from default branch.
29- **`internal/notifications/github`** – Format and post PR comments.
30- **`examples/`** – Infra examples (S3/GCS backend, automerge, Terramate stacks, Terragrunt).
31- **`scripts/`** – Maintainer scripts (if any).
32- **`e2e/`** – End-to-end tests: three Terramate stacks (null_resource/local_file), MinIO via Docker Compose, and `scripts/run-terramate.sh` that runs Neptune plan/apply with `NEPTUNE_E2E=1` (skips GitHub; see [e2e/README.md](e2e/README.md)).
33- **`lambda/`** – AWS Lambda handler for Neptune GitHub App webhooks (verify signature, parse `pull_request`—including `labeled` when the added label is `NEPTUNE_PR_LABEL`—and `issue_comment`, trigger `repository_dispatch`; optional `NEPTUNE_PR_LABEL` gates on PR label). See [lambda/README.md](lambda/README.md).
34- **`lambda/cloudformation/`** – CloudFormation template to deploy the Lambda (Function URL, IAM, Secrets Manager). See [lambda/README.md](lambda/README.md#deploy-with-cloudformation).
35- **`Makefile`**, **`.golangci.yml`**, **`.goreleaser.yml`**, **`.github/workflows/`** – Build, test, lint, release.
36- **`.claude/agents/` (migrated to hub)** – Agent definitions have been moved to the [code-agent-hub](https://github.com/devopsfactory-io/code-agent-hub) at `.claude/agents/neptune/`. Agents include: documentation-maintainer, em, go-developer, iac-developer, issue-reviewer, issue-writer, platform-engineering, pr-reviewer, qa, security.
37- **`.claude/commands/`** – Claude slash commands: `/feature`, `/bug` (invoke the issue-writer workflow to create issues from the repo’s issue templates; the draft is validated by issue-reviewer before `gh issue create`).
38- **Root community docs**: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md), [SECURITY.md](SECURITY.md), [GOVERNANCE.md](GOVERNANCE.md), [MAINTAINERS.md](MAINTAINERS.md), [ROADMAP.md](ROADMAP.md), [LICENSE](LICENSE).
39
40---
41
42## Setup Commands
43
44```bash
45# Build binary
46make build
47
48# Run all tests (main module)
49make test-all
50
51# Lambda (separate module under lambda/): build, package, test
52make lambda.build
53make lambda.zip
54make lambda.test
55
56# Check Go formatting (includes lambda/)
57make check-fmt
58
59# Lint (optional; requires golangci-lint)
60make lint
61```
62
63Use Go version from `go.mod`. No other prerequisites for building or testing the Go CLI. CI runs `make test-all`, `make lambda.test`, and `make check-fmt`.
64
65---
66
67## Code Style
68
69- **Format**: Use `gofmt -s`; run `make check-fmt` before committing.
70- **Linting**: `.golangci.yml` is authoritative; do not introduce new linter violations.
71- **Packages**: Code under `internal/` must not be imported from outside this module.
72- **Errors**: Return errors with context (e.g. `fmt.Errorf("...: %w", err)`); avoid naked returns.
73- **Exports**: Public functions and types should have doc comments starting with the name.
74
75---
76
77## Testing
78
79- **Run**: `go test ./...` or `make test-all`.
80- **Location**: Place `*_test.go` next to the code under test (same package).
81- **Coverage**: Existing tests cover `internal/config`, `internal/git`, `internal/github`, `internal/run`, `internal/notifications/github`; add tests for new behavior and keep coverage for touched code.
82- **No external services**: Unit tests should not require live GitHub or GCS; mock or stub as needed.
83- **E2E**: Run `make e2e` or `./e2e/scripts/run-terramate.sh` (requires Docker, Terraform). Uses MinIO and `NEPTUNE_E2E=1` to skip GitHub. For **stacks_management: local**, run `./e2e/scripts/run-local-stacks-files.sh` or `./e2e/scripts/run-local-declared-stacks.sh`. E2E config uses steps with default `once: false` (Neptune runs commands per stack).
84- **Automerge**: E2E and integration tests in this repo do not exercise the automerge feature. A separate repository (e.g. a fork or copy of [examples/](examples/)) can be used to test automerge end-to-end (e.g. open a PR with changes in two stacks, comment `@neptbot apply`, then verify the apply comment and that the PR is set to auto-merge after checks pass).
85
86---
87
88## CI
89
90- **`.github/workflows/test.yml`** – On push to `main`/`release-*` and on PRs; path filter for Go files; runs `make test-all` and `make check-fmt`.
91- **`.github/workflows/e2e.yml`** – On push/PR when e2e-related paths change; runs `./e2e/scripts/run-terramate.sh` with MinIO (Docker Compose). See [e2e/README.md](e2e/README.md).
92- **`.github/workflows/integration.yml`** – On PRs when integration-relevant paths change; runs Neptune plan/apply on the same PR with real GitHub (requirements check, PR comments, commit statuses) and MinIO for locks. Needs `statuses: write` for commit status API. See [e2e/README.md](e2e/README.md#integration-tests).
93- **`.github/workflows/cross-repo-test.yml`** – On PRs (non-draft) to `main`/`release-*` when core paths change (`e2e/**`, `cmd/**`, `internal/**`, `lambda/**`, `go.*`); runs cross-repo integration tests against the external `neptune-tests` repository. Creates dynamic Terramate stacks on a throwaway branch in `neptune-tests`, opens a test PR with a `neptune-ref` marker, waits for neptbot to execute the full plan/apply webhook flow (up to 10 minutes each), verifies commit statuses (`neptune plan`, `neptune apply`), checks automerge state, and cleans up the branch and PR. Uses the `neptune-ci` GitHub App (secrets: `NEPTUNE_CI_APP_ID`, `NEPTUNE_CI_PRIVATE_KEY`) for cross-repo operations. Runs in parallel with `e2e.yml` and `integration.yml`.
94- **`.github/workflows/lint.yml`** – On PRs; path filter for Go; runs golangci-lint.
95- **`.github/workflows/labeler.yml`** – On pull_request (opened, synchronize, reopened); runs [actions/labeler](https://github.com/actions/labeler) with [.github/labeler.yml](.github/labeler.yml). Path-based: neptune, dependencies, documentation. Head-branch (branch name): `feat*`→feature, `enhance*`→enhancement, `fix*` (not fix*dep*)→bug, branch containing `!`→breaking-change, `ci*`→github-actions, `(deps)`→dependencies. See CONTRIBUTING.md for contributor-facing branch naming.
96- **`.github/workflows/label-old-prs.yml`** – workflow_dispatch; applies the labeler to existing PRs (inputs: state e.g. merged/closed/all, limit). Use to backfill labels on old or merged PRs (Actions → "Label old PRs" → Run workflow). Because the labeler does not receive branch context on workflow_dispatch, a separate step applies the same rules as `.github/labeler.yml` to both head branch and PR title (e.g. `feat*`→feature if either branch or title matches), then the labeler runs for path-based labels.
97- **`.github/workflows/release.yml`** – On push of tags `v*.*.*` (and workflow_dispatch); runs GoReleaser to create GitHub Release with neptune binaries (archives e.g. `neptune_linux_amd64.tar.gz` and raw binaries e.g. `neptune_linux_amd64`), Lambda zip (`neptune-webhook.zip`) and raw binary `neptune-webhook_linux_amd64` (Lambda binary is `neptune-webhook`; zip contains it), checksums, and release notes. The release body is generated by **GitHub** (GoReleaser uses `changelog.use: github-native`) and categorized using [.github/release.yml](.github/release.yml) and PR labels (Breaking Changes, Features, Bug fixes, Documentation, Dependency updates, Other work). Release footer includes Full Changelog link.
98- **Renovate** – Dependency-update PRs (Go modules and GitHub Actions) are opened by [Renovate](https://docs.renovatebot.com/) from [.github/renovate.json5](.github/renovate.json5). To enable Renovate, install the [Renovate GitHub App](https://github.com/apps/renovate) and select the repo. Do not remove or override this config without reason.
99
100Semantic versioning: use tags like `v0.2.0`. GoReleaser injects version/commit/date into the binary via ldflags.
101
102**Changelog and breaking changes**: The release body is generated by GitHub (github-native) and categorized by [.github/release.yml](.github/release.yml) and **PR labels**. For breaking changes to appear under "Breaking Changes", apply the `breaking-change` label to the PR before merge. The commit subject convention (`!:`) is still recommended for semver (e.g. `feat!: remove deprecated flag`) but does not drive release-note sections; labels do.
103
104---
105
106## Documentation and AI Context (Mandatory)
107
108After any change that affects behavior, APIs, config, or CI:
109
1101. **Delegate**: Delegate documentation updates to the **documentation-maintainer** agent (defined in the hub at `.claude/agents/neptune/documentation-maintainer/`) so it runs the full maintain-documentation checklist (README, docs/, examples/, AGENTS.md, CLAUDE.md, .claude/commands, .claude/skills).
1112. **Do not edit plan files** (e.g. `neptune_go_rewrite*.plan.md` or `ai_agent_config*.plan.md`) unless the user explicitly asks.
112
113When in doubt, update. See `CLAUDE.md` (Documentation rule, always applies) and the **maintain-documentation** skill (`.claude/skills/maintain-documentation/`); the agent holds the detailed checklist.
114
115---
116
117## PR Guidance
118
119Before submitting:
120
1211. **Commits must be signed off (DCO).** Use `git commit -s` when creating commits. Do not add a `Made-with: Cursor` (or similar) trailer to commit messages. If you already committed without sign-off, run `git commit --amend -s --no-edit` then force-push. See [CONTRIBUTING.md](CONTRIBUTING.md) and `CLAUDE.md` (DCO rule).
1222. Run `make test-all` and `make check-fmt`.
1233. Ensure no new linter errors (`make lint` if available).
1244. If behavior or setup changed, delegate to the **documentation-maintainer** subagent.
1255. **Branch naming**: Branch names matching [.github/labeler.yml](.github/labeler.yml) (e.g. `feat/...`, `fix/...`, `enhance/...`, `(deps)/...`, `ci/...`, or branch containing `!` for breaking) get PR labels applied automatically, which drive release-note categories. See [CONTRIBUTING.md](CONTRIBUTING.md#branch-naming-and-pr-labels).
126
127PR titles may follow a conventional style (e.g. `feat(cmd): ...`, `fix(lock): ...`, `docs: ...`) but this is not enforced.
128
129---
130
131## References
132
133- **Contributing (human)**: [CONTRIBUTING.md](CONTRIBUTING.md) – main entry for contributors; [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md), [SECURITY.md](SECURITY.md); issue and PR templates in [.github/ISSUE_TEMPLATE/](.github/ISSUE_TEMPLATE/) and [.github/pull_request_template.md](.github/pull_request_template.md).
134- **Governance**: [GOVERNANCE.md](GOVERNANCE.md), [MAINTAINERS.md](MAINTAINERS.md), [ROADMAP.md](ROADMAP.md).
135- **Claude project rules**: `CLAUDE.md` – mandatory rules (DCO, Go standards, CI/release, config schema) embedded as project instructions.
136- **Claude commands**: `.claude/commands/` – slash commands (e.g. `/feature`, `/bug`) that trigger the issue-writer workflow. Drafts are validated by issue-reviewer before creation.
137- **Claude skills**: `.claude/skills/` – workflows for documentation maintenance, releases, testing, and open-pull-request (open a PR from current changes via gh CLI).
138- **Getting started**: [docs/getting-started-terramate.md](docs/getting-started-terramate.md) and [docs/getting-started-local-stacks.md](docs/getting-started-local-stacks.md) – onboarding with GitHub Actions and neptbot (Terramate or local stacks).
139- **Neptune config**: [docs/configuration.md](docs/configuration.md) and [.neptune.example.yaml](.neptune.example.yaml) for `.neptune.yaml` schema; [docs/object-storage.md](docs/object-storage.md) for backend env vars.
140- **Why Neptune / workflow comparison**: [docs/workflow-comparison.md](docs/workflow-comparison.md) – comparison of normal Terraform + GitHub Actions, Neptune, and Atlantis; use when explaining rationale for apply-before-merge.
141
devopsfactory-io/neptune · CLAUDE.md
@@ +1 @@
1# Neptune
2
3Neptune is a Terraform and OpenTofu PR automation tool. It runs plan/apply on pull requests using the [Terramate](https://github.com/terramate-io/terramate) Go SDK for change detection and run order. Object storage (GCS or S3) is used for stack locking; GitHub handles PR requirements and comments.
4
5**Language**: Go. See `go.mod` for the current version.
6
7---
8
9## Mandatory Rules
10
11These rules always apply — do not skip them under any circumstances.
12
13### DCO Sign-off
14
15Every commit **must** be signed off with `git commit -s`. The DCO bot is enabled; PRs with unsigned commits will fail.
16
17- If you committed without sign-off: `git commit --amend -s --no-edit` then force-push.
18- Never add `Made-with: Cursor` or similar trailers to commit messages.
19
20Before every commit, verify `user.name` and `user.email` are set in git config (global or local):
21
22```sh
23git config user.name # must return a non-empty value
24git config user.email # must return a non-empty value
25```
26
27If either is missing, resolve the values before committing:
28
291. Try to infer them from context — run `gh api user --jq '.name,.email'` to retrieve the authenticated GitHub user's name and email.
302. If the email is private or empty, try `gh api user/emails --jq '.[].email'` and pick the primary address.
313. If the values still cannot be determined, **ask the user** what `user.name` and `user.email` should be — do not use placeholder values.
32
33Once resolved:
34
35```sh
36git config user.name "<resolved name>"
37git config user.email "<resolved email>"
38```
39
40### Documentation After Changes
41
42After any change that affects behavior, config, CLI flags, or CI, delegate documentation updates to the **documentation-maintainer** agent.
43
44**Within a Claude Code session:** Use the Agent tool with `subagent_type: "documentation-maintainer"` and describe what changed in the prompt.
45
46**From terminal:**
47
48```bash
49claude --agent documentation-maintainer "update docs for: <what changed>"
50```
51
52The agent runs the full checklist: README, docs/, examples/, AGENTS.md, CLAUDE.md, .claude/commands, .claude/skills. Do not skip this step.
53
54### Issue Creation Validation
55
56When creating GitHub issues via `/feature` or `/bug`, validate the draft with the **issue-reviewer** agent before calling `gh issue create`. Do not upload until the draft is approved or refined.
57
58---
59
60## Go Standards
61
62Applies to all `**/*.go` files:
63
64- **Format**: `gofmt -s`. Run `make check-fmt` before committing; CI enforces it.
65- **Lint**: Conform to `.golangci.yml`. Do not introduce new violations.
66- **Packages**: Code in `internal/` must not be imported from outside this module.
67- **Errors**: Wrap errors with context: `fmt.Errorf("context: %w", err)`. Never silently ignore errors.
68- **Exports**: Public functions and types must have doc comments starting with the identifier name.
69- **Tests**: Place `*_test.go` in the same package as the code. Use table-driven tests.
70
71---
72
73## Config Schema (`.neptune.yaml`)
74
75Top-level keys:
76
77```yaml
78repository:
79 object_storage: "gs://..." # GCS or S3 bucket for locking
80 branch: main
81 plan_requirements: [...]
82 apply_requirements: [...]
83 allowed_workflow: <string>
84 automerge: true/false # Optional; enables auto-merge after apply
85workflows:
86 <name>:
87 steps:
88 - run: <command>
89 once: false # default: run per stack; true: run once in root
90 depends_on: [...] # optional
91```
92
93Required environment variables: `NEPTUNE_CONFIG_PATH`, `GITHUB_REPOSITORY`, `GITHUB_TOKEN`, plus object storage credentials.
94
95When the schema changes, update README, `.neptune.example.yaml`, `examples/`, and AGENTS.md.
96
97---
98
99## CI and Release
100
101Applies to `.github/**/*.yml`, `Makefile`, `.goreleaser.yml`:
102
103- **Semver**: Tags use `vMAJOR.MINOR.PATCH` (e.g. `v0.2.0`). The `v` prefix is required.
104- **Release**: Push a tag → CI runs `release.yml` → GoReleaser creates GitHub Release with binaries, Lambda zip, checksums, and release notes.
105- **Release notes**: Generated by GitHub (github-native) and categorized by `.github/release.yml` + PR labels. For breaking changes to appear under "Breaking Changes", apply the `breaking-change` label before merge.
106- **Branch naming for labels**: `feat/...` → feature, `fix/...` → bug, `enhance/...` → enhancement, `ci/...` → github-actions, `(deps)/...` → dependencies, branch with `!` → breaking-change.
107- Keep path filters and job dependencies intact in CI workflows. Do not remove or override Renovate config in `.github/renovate.json5`.
108
109---
110
111## Agents, Commands, and Skills
112
113Agents are managed centrally in the [code-agent-hub](https://github.com/devopsfactory-io/code-agent-hub) at `.claude/agents/<role>/AGENTS.md`, each loading project-specific context from `.claude/skills/neptune/<role>/SKILL.md`. Commands and skills remain local in `.claude/`:
114
115| Type | Name | Purpose | Location |
116| ---- | ---- | ------- | -------- |
117| Agent | `documentation-maintainer` | Runs full doc checklist after code/config/CI changes | hub |
118| Agent | `em` | Engineering Manager — coordinates Neptune team | hub |
119| Agent | `go-developer` | Go implementation for Neptune | hub |
120| Agent | `iac-developer` | IaC modules and GitHub Actions | hub |
121| Agent | `issue-reviewer` | Triages open issues; validates drafts before upload | hub |
122| Agent | `issue-writer` | Creates GitHub issues from `/feature` and `/bug` commands | hub |
123| Agent | `platform-engineering` | GitOps, CI/CD, observability | hub |
124| Agent | `pr-reviewer` | Reviews PRs via `gh` CLI — DCO, Go style, tests, docs | hub |
125| Agent | `qa` | Code quality and test coverage | hub |
126| Agent | `security` | Security scanning for code and IaC | hub |
127| Command | `/bug` | Create a bug report (invokes issue-writer) | local |
128| Command | `/feature` | Create a feature request (invokes issue-writer) | local |
129| Skill | `maintain-documentation` | Delegates doc updates to documentation-maintainer agent | local |
130| Skill | `open-pull-request` | Commits and opens a PR via `gh` with DCO sign-off | local |
131| Skill | `release-and-versioning` | Cuts a semver release with GoReleaser | local |
132| Skill | `testing-and-ci` | Runs tests, lint, format checks; explains CI | local |
133
@@ −1 +1 @@
1−# AGENTS.md
1+# Neptune
22
3−Guidance for AI coding agents working on the Neptune project.
3+Neptune is a Terraform and OpenTofu PR automation tool. It runs plan/apply on pull requests using the [Terramate](https://github.com/terramate-io/terramate) Go SDK for change detection and run order. Object storage (GCS or S3) is used for stack locking; GitHub handles PR requirements and comments.
44
5+**Language**: Go. See `go.mod` for the current version.
6+
57 ---
68
7−## Project Overview
9+## Mandatory Rules
810
9−**Neptune** is a Terraform and OpenTofu pull request automation tool inspired by [Atlantis](https://github.com/runatlantis/atlantis). It runs plan/apply (Terraform or OpenTofu) on pull requests using the [Terramate](https://github.com/terramate-io/terramate) Go SDK for change detection and run order. When a step has `once` false or unset (default), Neptune runs the step’s command in each changed stack (Terramate SDK or local stacks; no Terramate CLI needed when using Terramate); object storage (GCS or S3) is used for stack locking, and GitHub for PR requirements and comments.
11+These rules always apply — do not skip them under any circumstances.
1012
11−**Main capabilities**: Load config from `.neptune.yaml` and env; in CI (non-E2E), config is loaded from the repository’s default branch via git (fallback to PR branch) so PR authors cannot change workflow steps; check PR requirements (approved, mergeable, undiverged, rebased); lock stacks in object storage (GCS, AWS S3, or S3-compatible e.g. MinIO); run workflow steps (per-stack by default, or once in root when `once: true`); for stacks_management: local, **neptune stacks** provides list (--changed) and create, with **--format** (json, yaml, text, formatted; default formatted); when using discovery, run order can be set via **depends_on** in each **stack.hcl** (path-only; relative paths and directory-of-stacks supported); post results as PR comments. Optional `repository.automerge: true` enables PR auto-merge after a successful apply (GitHub GraphQL). Log level is configurable via `log_level` (config), `NEPTUNE_LOG_LEVEL`, or the global **--log-level** CLI flag (DEBUG, INFO, ERROR).
13+### DCO Sign-off
1214
13−**Language**: Go (see `go.mod`).
15+Every commit **must** be signed off with `git commit -s`. The DCO bot is enabled; PRs with unsigned commits will fail.
1416
15−---
17+- If you committed without sign-off: `git commit --amend -s --no-edit` then force-push.
18+- Never add `Made-with: Cursor` or similar trailers to commit messages.
1619
17−## Repository Structure
20+Before every commit, verify `user.name` and `user.email` are set in git config (global or local):
1821
19−- **`main.go`** – Entry point; version/commit/date via ldflags.
20−- **`cmd/`** – CLI (Cobra): `root.go` (global **--log-level** flag), `version.go`, `command.go`, `unlock.go`, `stacks.go` (stacks list, create; **--format** json|yaml|text|formatted, default formatted; **neptune stacks create** supports optional **--depends-on** comma-separated paths). **neptune stacks list** and **neptune stacks create** are for local use and do not require `GITHUB_TOKEN` or other CI env vars (unlike **neptune command** and **neptune unlock**).
21−- **`internal/config`** – Load env + YAML, validate `.neptune.yaml` (including optional `log_level`, `stacks_management`, root-level `local_stacks`).
22−- **`internal/domain`** – Config, lock, run, and GitHub domain structs (WorkflowStep uses `once`; RepositoryConfig has `StacksManagement`, `LocalStacks`).
23−- **`internal/log`** – Structured logging (DEBUG, INFO, ERROR) via `log/slog`; level from `NEPTUNE_LOG_LEVEL` or config `log_level`.
24−- **`internal/stacks`** – Stacks provider interface (terramate, local); list/changed stacks for locking and runner.
25−- **`internal/lock`** – Lock interface: gets stack list from stacks provider, object-storage lock files (GCS, S3).
26−- **`internal/run`** – Execute workflow phase steps (shell).
27−- **`internal/github`** – GitHub API client, PR requirements (approved, mergeable, undiverged), commit statuses (GetHeadSHA, CreateCommitStatus) for **neptune plan** / **neptune apply**; GraphQL EnablePullRequestAutoMerge when `repository.automerge` is true.
28−- **`internal/git`** – Rebased check; DefaultBranch (git CLI), ShowFileFromRef, FetchBranch for loading config from default branch.
29−- **`internal/notifications/github`** – Format and post PR comments.
30−- **`examples/`** – Infra examples (S3/GCS backend, automerge, Terramate stacks, Terragrunt).
31−- **`scripts/`** – Maintainer scripts (if any).
32−- **`e2e/`** – End-to-end tests: three Terramate stacks (null_resource/local_file), MinIO via Docker Compose, and `scripts/run-terramate.sh` that runs Neptune plan/apply with `NEPTUNE_E2E=1` (skips GitHub; see [e2e/README.md](e2e/README.md)).
33−- **`lambda/`** – AWS Lambda handler for Neptune GitHub App webhooks (verify signature, parse `pull_request`—including `labeled` when the added label is `NEPTUNE_PR_LABEL`—and `issue_comment`, trigger `repository_dispatch`; optional `NEPTUNE_PR_LABEL` gates on PR label). See [lambda/README.md](lambda/README.md).
34−- **`lambda/cloudformation/`** – CloudFormation template to deploy the Lambda (Function URL, IAM, Secrets Manager). See [lambda/README.md](lambda/README.md#deploy-with-cloudformation).
35−- **`Makefile`**, **`.golangci.yml`**, **`.goreleaser.yml`**, **`.github/workflows/`** – Build, test, lint, release.
36−- **`.claude/agents/` (migrated to hub)** – Agent definitions have been moved to the [code-agent-hub](https://github.com/devopsfactory-io/code-agent-hub) at `.claude/agents/neptune/`. Agents include: documentation-maintainer, em, go-developer, iac-developer, issue-reviewer, issue-writer, platform-engineering, pr-reviewer, qa, security.
37−- **`.claude/commands/`** – Claude slash commands: `/feature`, `/bug` (invoke the issue-writer workflow to create issues from the repo’s issue templates; the draft is validated by issue-reviewer before `gh issue create`).
38−- **Root community docs**: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md), [SECURITY.md](SECURITY.md), [GOVERNANCE.md](GOVERNANCE.md), [MAINTAINERS.md](MAINTAINERS.md), [ROADMAP.md](ROADMAP.md), [LICENSE](LICENSE).
22+```sh
23+git config user.name # must return a non-empty value
24+git config user.email # must return a non-empty value
25+```
3926
40−---
27+If either is missing, resolve the values before committing:
4128
42−## Setup Commands
29+1. Try to infer them from context — run `gh api user --jq '.name,.email'` to retrieve the authenticated GitHub user's name and email.
30+2. If the email is private or empty, try `gh api user/emails --jq '.[].email'` and pick the primary address.
31+3. If the values still cannot be determined, **ask the user** what `user.name` and `user.email` should be — do not use placeholder values.
4332
44−```bash
45−# Build binary
46−make build
33+Once resolved:
4734
48−# Run all tests (main module)
49−make test-all
50−
51−# Lambda (separate module under lambda/): build, package, test
52−make lambda.build
53−make lambda.zip
54−make lambda.test
55−
56−# Check Go formatting (includes lambda/)
57−make check-fmt
58−
59−# Lint (optional; requires golangci-lint)
60−make lint
35+```sh
36+git config user.name "<resolved name>"
37+git config user.email "<resolved email>"
6138 ```
6239
63−Use Go version from `go.mod`. No other prerequisites for building or testing the Go CLI. CI runs `make test-all`, `make lambda.test`, and `make check-fmt`.
40+### Documentation After Changes
6441
65−---
42+After any change that affects behavior, config, CLI flags, or CI, delegate documentation updates to the **documentation-maintainer** agent.
6643
67−## Code Style
44+**Within a Claude Code session:** Use the Agent tool with `subagent_type: "documentation-maintainer"` and describe what changed in the prompt.
6845
69−- **Format**: Use `gofmt -s`; run `make check-fmt` before committing.
70−- **Linting**: `.golangci.yml` is authoritative; do not introduce new linter violations.
71−- **Packages**: Code under `internal/` must not be imported from outside this module.
72−- **Errors**: Return errors with context (e.g. `fmt.Errorf("...: %w", err)`); avoid naked returns.
73−- **Exports**: Public functions and types should have doc comments starting with the name.
46+**From terminal:**
7447
75−---
48+```bash
49+claude --agent documentation-maintainer "update docs for: <what changed>"
50+```
7651
77−## Testing
52+The agent runs the full checklist: README, docs/, examples/, AGENTS.md, CLAUDE.md, .claude/commands, .claude/skills. Do not skip this step.
7853
79−- **Run**: `go test ./...` or `make test-all`.
80−- **Location**: Place `*_test.go` next to the code under test (same package).
81−- **Coverage**: Existing tests cover `internal/config`, `internal/git`, `internal/github`, `internal/run`, `internal/notifications/github`; add tests for new behavior and keep coverage for touched code.
82−- **No external services**: Unit tests should not require live GitHub or GCS; mock or stub as needed.
83−- **E2E**: Run `make e2e` or `./e2e/scripts/run-terramate.sh` (requires Docker, Terraform). Uses MinIO and `NEPTUNE_E2E=1` to skip GitHub. For **stacks_management: local**, run `./e2e/scripts/run-local-stacks-files.sh` or `./e2e/scripts/run-local-declared-stacks.sh`. E2E config uses steps with default `once: false` (Neptune runs commands per stack).
84−- **Automerge**: E2E and integration tests in this repo do not exercise the automerge feature. A separate repository (e.g. a fork or copy of [examples/](examples/)) can be used to test automerge end-to-end (e.g. open a PR with changes in two stacks, comment `@neptbot apply`, then verify the apply comment and that the PR is set to auto-merge after checks pass).
54+### Issue Creation Validation
8555
56+When creating GitHub issues via `/feature` or `/bug`, validate the draft with the **issue-reviewer** agent before calling `gh issue create`. Do not upload until the draft is approved or refined.
57+
8658 ---
8759
88−## CI
60+## Go Standards
8961
90−- **`.github/workflows/test.yml`** – On push to `main`/`release-*` and on PRs; path filter for Go files; runs `make test-all` and `make check-fmt`.
91−- **`.github/workflows/e2e.yml`** – On push/PR when e2e-related paths change; runs `./e2e/scripts/run-terramate.sh` with MinIO (Docker Compose). See [e2e/README.md](e2e/README.md).
92−- **`.github/workflows/integration.yml`** – On PRs when integration-relevant paths change; runs Neptune plan/apply on the same PR with real GitHub (requirements check, PR comments, commit statuses) and MinIO for locks. Needs `statuses: write` for commit status API. See [e2e/README.md](e2e/README.md#integration-tests).
93−- **`.github/workflows/cross-repo-test.yml`** – On PRs (non-draft) to `main`/`release-*` when core paths change (`e2e/**`, `cmd/**`, `internal/**`, `lambda/**`, `go.*`); runs cross-repo integration tests against the external `neptune-tests` repository. Creates dynamic Terramate stacks on a throwaway branch in `neptune-tests`, opens a test PR with a `neptune-ref` marker, waits for neptbot to execute the full plan/apply webhook flow (up to 10 minutes each), verifies commit statuses (`neptune plan`, `neptune apply`), checks automerge state, and cleans up the branch and PR. Uses the `neptune-ci` GitHub App (secrets: `NEPTUNE_CI_APP_ID`, `NEPTUNE_CI_PRIVATE_KEY`) for cross-repo operations. Runs in parallel with `e2e.yml` and `integration.yml`.
94−- **`.github/workflows/lint.yml`** – On PRs; path filter for Go; runs golangci-lint.
95−- **`.github/workflows/labeler.yml`** – On pull_request (opened, synchronize, reopened); runs [actions/labeler](https://github.com/actions/labeler) with [.github/labeler.yml](.github/labeler.yml). Path-based: neptune, dependencies, documentation. Head-branch (branch name): `feat*`→feature, `enhance*`→enhancement, `fix*` (not fix*dep*)→bug, branch containing `!`→breaking-change, `ci*`→github-actions, `(deps)`→dependencies. See CONTRIBUTING.md for contributor-facing branch naming.
96−- **`.github/workflows/label-old-prs.yml`** – workflow_dispatch; applies the labeler to existing PRs (inputs: state e.g. merged/closed/all, limit). Use to backfill labels on old or merged PRs (Actions → "Label old PRs" → Run workflow). Because the labeler does not receive branch context on workflow_dispatch, a separate step applies the same rules as `.github/labeler.yml` to both head branch and PR title (e.g. `feat*`→feature if either branch or title matches), then the labeler runs for path-based labels.
97−- **`.github/workflows/release.yml`** – On push of tags `v*.*.*` (and workflow_dispatch); runs GoReleaser to create GitHub Release with neptune binaries (archives e.g. `neptune_linux_amd64.tar.gz` and raw binaries e.g. `neptune_linux_amd64`), Lambda zip (`neptune-webhook.zip`) and raw binary `neptune-webhook_linux_amd64` (Lambda binary is `neptune-webhook`; zip contains it), checksums, and release notes. The release body is generated by **GitHub** (GoReleaser uses `changelog.use: github-native`) and categorized using [.github/release.yml](.github/release.yml) and PR labels (Breaking Changes, Features, Bug fixes, Documentation, Dependency updates, Other work). Release footer includes Full Changelog link.
98−- **Renovate** – Dependency-update PRs (Go modules and GitHub Actions) are opened by [Renovate](https://docs.renovatebot.com/) from [.github/renovate.json5](.github/renovate.json5). To enable Renovate, install the [Renovate GitHub App](https://github.com/apps/renovate) and select the repo. Do not remove or override this config without reason.
62+Applies to all `**/*.go` files:
9963
100−Semantic versioning: use tags like `v0.2.0`. GoReleaser injects version/commit/date into the binary via ldflags.
64+- **Format**: `gofmt -s`. Run `make check-fmt` before committing; CI enforces it.
65+- **Lint**: Conform to `.golangci.yml`. Do not introduce new violations.
66+- **Packages**: Code in `internal/` must not be imported from outside this module.
67+- **Errors**: Wrap errors with context: `fmt.Errorf("context: %w", err)`. Never silently ignore errors.
68+- **Exports**: Public functions and types must have doc comments starting with the identifier name.
69+- **Tests**: Place `*_test.go` in the same package as the code. Use table-driven tests.
10170
102−**Changelog and breaking changes**: The release body is generated by GitHub (github-native) and categorized by [.github/release.yml](.github/release.yml) and **PR labels**. For breaking changes to appear under "Breaking Changes", apply the `breaking-change` label to the PR before merge. The commit subject convention (`!:`) is still recommended for semver (e.g. `feat!: remove deprecated flag`) but does not drive release-note sections; labels do.
103−
10471 ---
10572
106−## Documentation and AI Context (Mandatory)
73+## Config Schema (`.neptune.yaml`)
10774
108−After any change that affects behavior, APIs, config, or CI:
75+Top-level keys:
10976
110−1. **Delegate**: Delegate documentation updates to the **documentation-maintainer** agent (defined in the hub at `.claude/agents/neptune/documentation-maintainer/`) so it runs the full maintain-documentation checklist (README, docs/, examples/, AGENTS.md, CLAUDE.md, .claude/commands, .claude/skills).
111−2. **Do not edit plan files** (e.g. `neptune_go_rewrite*.plan.md` or `ai_agent_config*.plan.md`) unless the user explicitly asks.
77+```yaml
78+repository:
79+ object_storage: "gs://..." # GCS or S3 bucket for locking
80+ branch: main
81+ plan_requirements: [...]
82+ apply_requirements: [...]
83+ allowed_workflow: <string>
84+ automerge: true/false # Optional; enables auto-merge after apply
85+workflows:
86+ <name>:
87+ steps:
88+ - run: <command>
89+ once: false # default: run per stack; true: run once in root
90+ depends_on: [...] # optional
91+```
11292
113−When in doubt, update. See `CLAUDE.md` (Documentation rule, always applies) and the **maintain-documentation** skill (`.claude/skills/maintain-documentation/`); the agent holds the detailed checklist.
93+Required environment variables: `NEPTUNE_CONFIG_PATH`, `GITHUB_REPOSITORY`, `GITHUB_TOKEN`, plus object storage credentials.
11494
95+When the schema changes, update README, `.neptune.example.yaml`, `examples/`, and AGENTS.md.
96+
11597 ---
11698
117−## PR Guidance
99+## CI and Release
118100
119−Before submitting:
101+Applies to `.github/**/*.yml`, `Makefile`, `.goreleaser.yml`:
120102
121−1. **Commits must be signed off (DCO).** Use `git commit -s` when creating commits. Do not add a `Made-with: Cursor` (or similar) trailer to commit messages. If you already committed without sign-off, run `git commit --amend -s --no-edit` then force-push. See [CONTRIBUTING.md](CONTRIBUTING.md) and `CLAUDE.md` (DCO rule).
122−2. Run `make test-all` and `make check-fmt`.
123−3. Ensure no new linter errors (`make lint` if available).
124−4. If behavior or setup changed, delegate to the **documentation-maintainer** subagent.
125−5. **Branch naming**: Branch names matching [.github/labeler.yml](.github/labeler.yml) (e.g. `feat/...`, `fix/...`, `enhance/...`, `(deps)/...`, `ci/...`, or branch containing `!` for breaking) get PR labels applied automatically, which drive release-note categories. See [CONTRIBUTING.md](CONTRIBUTING.md#branch-naming-and-pr-labels).
103+- **Semver**: Tags use `vMAJOR.MINOR.PATCH` (e.g. `v0.2.0`). The `v` prefix is required.
104+- **Release**: Push a tag → CI runs `release.yml` → GoReleaser creates GitHub Release with binaries, Lambda zip, checksums, and release notes.
105+- **Release notes**: Generated by GitHub (github-native) and categorized by `.github/release.yml` + PR labels. For breaking changes to appear under "Breaking Changes", apply the `breaking-change` label before merge.
106+- **Branch naming for labels**: `feat/...` → feature, `fix/...` → bug, `enhance/...` → enhancement, `ci/...` → github-actions, `(deps)/...` → dependencies, branch with `!` → breaking-change.
107+- Keep path filters and job dependencies intact in CI workflows. Do not remove or override Renovate config in `.github/renovate.json5`.
126108
127−PR titles may follow a conventional style (e.g. `feat(cmd): ...`, `fix(lock): ...`, `docs: ...`) but this is not enforced.
128−
129109 ---
130110
131−## References
111+## Agents, Commands, and Skills
132112
133−- **Contributing (human)**: [CONTRIBUTING.md](CONTRIBUTING.md) – main entry for contributors; [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md), [SECURITY.md](SECURITY.md); issue and PR templates in [.github/ISSUE_TEMPLATE/](.github/ISSUE_TEMPLATE/) and [.github/pull_request_template.md](.github/pull_request_template.md).
134−- **Governance**: [GOVERNANCE.md](GOVERNANCE.md), [MAINTAINERS.md](MAINTAINERS.md), [ROADMAP.md](ROADMAP.md).
135−- **Claude project rules**: `CLAUDE.md` – mandatory rules (DCO, Go standards, CI/release, config schema) embedded as project instructions.
136−- **Claude commands**: `.claude/commands/` – slash commands (e.g. `/feature`, `/bug`) that trigger the issue-writer workflow. Drafts are validated by issue-reviewer before creation.
137−- **Claude skills**: `.claude/skills/` – workflows for documentation maintenance, releases, testing, and open-pull-request (open a PR from current changes via gh CLI).
138−- **Getting started**: [docs/getting-started-terramate.md](docs/getting-started-terramate.md) and [docs/getting-started-local-stacks.md](docs/getting-started-local-stacks.md) – onboarding with GitHub Actions and neptbot (Terramate or local stacks).
139−- **Neptune config**: [docs/configuration.md](docs/configuration.md) and [.neptune.example.yaml](.neptune.example.yaml) for `.neptune.yaml` schema; [docs/object-storage.md](docs/object-storage.md) for backend env vars.
140−- **Why Neptune / workflow comparison**: [docs/workflow-comparison.md](docs/workflow-comparison.md) – comparison of normal Terraform + GitHub Actions, Neptune, and Atlantis; use when explaining rationale for apply-before-merge.
113+Agents are managed centrally in the [code-agent-hub](https://github.com/devopsfactory-io/code-agent-hub) at `.claude/agents/<role>/AGENTS.md`, each loading project-specific context from `.claude/skills/neptune/<role>/SKILL.md`. Commands and skills remain local in `.claude/`:
114+
115+| Type | Name | Purpose | Location |
116+| ---- | ---- | ------- | -------- |
117+| Agent | `documentation-maintainer` | Runs full doc checklist after code/config/CI changes | hub |
118+| Agent | `em` | Engineering Manager — coordinates Neptune team | hub |
119+| Agent | `go-developer` | Go implementation for Neptune | hub |
120+| Agent | `iac-developer` | IaC modules and GitHub Actions | hub |
121+| Agent | `issue-reviewer` | Triages open issues; validates drafts before upload | hub |
122+| Agent | `issue-writer` | Creates GitHub issues from `/feature` and `/bug` commands | hub |
123+| Agent | `platform-engineering` | GitOps, CI/CD, observability | hub |
124+| Agent | `pr-reviewer` | Reviews PRs via `gh` CLI — DCO, Go style, tests, docs | hub |
125+| Agent | `qa` | Code quality and test coverage | hub |
126+| Agent | `security` | Security scanning for code and IaC | hub |
127+| Command | `/bug` | Create a bug report (invokes issue-writer) | local |
128+| Command | `/feature` | Create a feature request (invokes issue-writer) | local |
129+| Skill | `maintain-documentation` | Delegates doc updates to documentation-maintainer agent | local |
130+| Skill | `open-pull-request` | Commits and opens a PR via `gh` with DCO sign-off | local |
131+| Skill | `release-and-versioning` | Cuts a semver release with GoReleaser | local |
132+| Skill | `testing-and-ci` | Runs tests, lint, format checks; explains CI | local |
141133
