The canonical contribution guide lives in CONTRIBUTING.md at the repository root, where GitHub surfaces it in the new-issue and pull-request flows. This page is a short orientation; the root file is the source of truth.
How contributions reach the package
hve-squad ships through APM as one-directional package content: consumers pull the package, and the package never reads from consumer environments. The only route for a change to reach the published package is a fork and pull request against the repository.
- Fork the repository.
- Create a branch for your change.
- Add a change fragment with
apm run change. - Open a pull request against the default branch.
- A maintainer reviews, requests changes when needed, and merges.
Consumers receive the merged change the next time they run apm run sync-deps.
Recording your change
Do not edit CHANGELOG.md and do not bump version: in
apm.yml. Both are release outputs, assembled on the default branch when a release
is cut, and CI rejects a pull request that touches either.
The reason is mechanical. A version line is a single line and the newest changelog heading is a
single position, so two pull requests that both touch them always conflict — and the
second one to merge silently reuses a version number the first already claimed. Instead every
pull request adds one new file under .changes/unreleased/. Two
pull requests adding two differently named files never conflict.
apm run change
The script asks four things and writes the file for you:
- Type — the Keep a Changelog section your entry belongs to:
Added,Changed,Deprecated,Removed,Fixed, orSecurity. - Bump — how the version should move. This tracks ideas, not artifacts, so most changes are
patch. - Title — a short phrase, used only to name the file.
- Entry — the changelog text itself, written the way it should read in the release notes.
Choosing the bump
| Value | Use when | In this repo |
|---|---|---|
major |
A consumer must change something to keep working. | Not used yet. |
minor |
A genuinely new idea, or a change that materially changes how the package is used. | 0.10.0 introduced federation. 0.11.0 reworked hve-core attachment. |
patch |
Everything else, including new agents, skills, prompts, instructions, and roles that extend an idea that already shipped. | A new squad role under federation. A new OWASP skill. A wording fix. |
Adding an agent is not a minor. Adding the concept the agent belongs to is. Ten agents
that all serve one idea that already ships are ten patches, not ten minors. When in doubt choose
patch — the maintainer sees the resolved level on the pull request check and
corrects the line before merging, and raising is cheap while an accidental minor is permanent.
You end up with a file like .changes/unreleased/20260804-roster-row-resolves-to-nothing.md:
---
bump: patch
type: Fixed
---
- **A roster Primary pointed at an agent hve-core no longer ships.** Repointed it to ...
Write the entry as markdown bullets starting with - , because the release step
copies them verbatim. Lead with a bold sentence naming the problem, then say what changed, then
cite the file paths in backticks. Commit the fragment with the rest of your change. One fragment
per idea — a pull request doing two unrelated things adds two fragments.
Merging your pull request does not release it. The fragment waits in
.changes/unreleased/ with everything else already merged, and a maintainer cuts a
release when that batch is ready — the same hour for a quick fix, or later for something
that needs time in testing. In the meantime the merge is published to the
rolling pre-release, so your change is installable and testable within minutes:
apm install "Peter-N91/hve-squad#v0.15.0-pre" --target copilot
The exact tag is on the
Releases page, marked as a
pre-release. It is a channel rather than a fixed point: the tag moves on every merge, and it is
renamed when a minor fragment lands. Pin a released version for anything
you depend on. The full format reference lives in
.changes/README.md.
Shipping a fix without shipping everything else
A release ships a commit, not a selection of fragments. The tag is cut from the branch head, so a release from the default branch contains everything merged into it, whatever the CHANGELOG happens to list. Choosing which fragments to consume changes the release notes, not the code. That leaves two cases, and only the second needs anything unusual.
The default branch is shippable. A maintainer dispatches Release Prep and your
fix goes out with everything else pending, as one version. If a pending fragment asked for
minor, that version is a minor — and it still contains your patch, so
consumers get the fix. This is almost always the right answer.
The default branch holds something that must not ship yet. Then a release from it would carry that work out alongside the fix, so the fix has to come from somewhere that does not contain it: a hotfix branch cut off the last release tag.
git switch --detach v0.14.0
git switch -c hotfix/v0.14.1
# apply the fix, then record it
apm run change # Type: Fixed, Bump: patch
git push -u origin hotfix/v0.14.1
A maintainer then dispatches Release Prep with ref set to the
hotfix branch. It assembles the CHANGELOG from that branch's fragments only, bumps
apm.yml to 0.14.1, and cuts the tag from that branch. The rolling
pre-release on the default branch is left alone, because the batch it describes is still
pending. The hotfix branch is then merged back with the release-merge-back label,
which is what allows that pull request to carry the release state Release Prep already wrote.
A hotfix released after a higher version does not steal the Latest badge: the release workflow compares versions and declines it when the tag is lower than the current latest.
Proposing a shared learning
A shared learning is a durable, broadly applicable rule discovered while using the squad that should help every other consumer facing the same scenario. Live agent memory always stays local to each consumer and is never promoted automatically. Promotion is a deliberate, human-reviewed pull request, and that review is the defense against memory poisoning, data leakage, and context drift.
Sanitize every entry before you propose it:
- Remove all secrets, tokens, credentials, and connection strings.
- Remove customer, organization, and individual names.
- Remove repository-specific absolute paths and internal URLs.
- Generalize stack-specific details so the learning applies beyond its origin.
- Confirm the learning is broadly applicable across consumers and scenarios.
Curated shared learnings travel as package content in
squad-src/.github/skills/squad/learnings/shared-learnings.md. When a learning is
specific to one organization's projects, promote it to a tenant-internal repository instead. The
two paths, and the squad-learnings-tenant scaffold, are described in
Shared learnings.