Contributing · 7. Submitting a change

No human approval is required to merge, so your commit body and your PR description are the review. Write them for a reader who was not in your head. This chapter tells you what the log actually looks like, which parts of the local convention you should copy, and which parts you cannot.

This is a how-to. It assumes your change already passes the gates in chapter 5.

7.1 Before you open a pull request

Run the checklist from 5.11. Then check these five, which are specific to submitting rather than to code:

CheckWhy
Did you add a new crate?It needs crates/<name>/AGENTS.md, 60 lines or fewer, or Verify agent-doc references resolve fails. Section 7.7
Did you rename a public symbol?If docs/agent/repo-manifest.yaml references it, the same required check fails. Section 7.7
Did you edit a document linked from llms.txt?Regenerate llms-full.txt with bash scripts/build-llms-full.sh
Is your change user-facing?Add an entry to CHANGELOG.md under [Unreleased]. Section 7.8
Did you introduce a new domain term?Add it to _typos.toml or Lint goes red

7.2 Fork, branch, push

The process in CONTRIBUTING.md:50 is the standard one and it is accurate as far as it goes:

gh repo fork CueCrux/Crux --clone
cd Crux
git checkout -b <type>/<short-description>
# make your change
git push -u origin <type>/<short-description>
gh pr create --fill

Branch names in the merge log follow <type>/<kebab-description>. Real examples from the tree: fix/studio-library-and-heading, feat/execplan-board-drift-layer3, docs/vaultcrux-upload-script, console/surfaces-remediation. The prefix is a loose type or a domain; both appear.

Merges use merge_method: MERGE, so the log carries merge commits reading Merge pull request #NNN from CueCrux/<branch>.

7.3 The commit convention, derived from the log

CONTRIBUTING.md:54 says only "clear, descriptive commits". That is not what the log looks like, and a newcomer following it produces commits that stand out immediately.

The actual convention is Conventional-Commits-flavoured but uses domain scopes rather than the standard type vocabulary. Real subjects from main:

console(studio): route the Library section; heading reads Studio (post-#519 fix)
daemon+cli(studio): central template library — signed catalog, install-by-id with provenance
daemon(integrations): generic sync scheduler + markdown-vault FileWatcher runtime (I4)
daemon(outbound): enforce declared NetworkAccess.allowed_hosts + SafetyPolicy budgets (I3.1)
console(rail+workspaces+settings): pages-rendering fix, icons-only rail, single switcher (M17)
ci: unwrap ratchet baseline +55 — PR #519 HTTP test fixtures in http/tests.rs only
docs: in-depth developer guide — extending the Crux Daemon (D1)
chore(release): v0.5.52

The observable rules:

RuleDetail
Scope first, not type firstconsole, daemon, cli, ci, docs. Compounds are common: daemon+cli, console+daemon
Sub-scope in parenthesesconsole(studio), daemon(integrations), daemon(outbound). Multiple sub-scopes are joined with +
Standard types appear but do not dominatefeat, fix, chore show up; scope-first is the majority form
Bodies are long and explanatoryThe convention is a narrative: why it broke, what changed, how it was verified
A verification line closes the bodyReal example shape: smoke PASS; console tests 118 pass; Playwright 33/33, 0 pageerrors.
Co-Authored-By: trailersUsed for AI-assisted commits
chore(release): v<version>Produced by scripts/cut-release.sh. Do not write one by hand

Copy all of the above. A commit subject of console(studio): route the Library section with a body explaining the cause and the verification is exactly what a maintainer wants to read.

7.4 The milestone tags, and what you should do instead

Look again at the log and you will see trailing parenthesised tags: (M17), (I4), (I3.1), (D1), (L1+L2 daemon). They are near-universal on feature commits.

These tags reference ExecPlans in PlanCrux, a private monorepo you do not have and cannot see. (M17) means "milestone 17 of a named plan"; the plan is not in this repository, not on GitHub, and not resolvable from anything you have access to. The repository even runs a CI workflow, Private Paths Guard, whose entire job is to stop PlanCrux/ paths leaking into public source and documentation, while the commit subjects reference that same private planning system by milestone number.

What to do: do not imitate them. Omit the trailing tag entirely. If your change is one step in a larger piece of work, say so in plain English in the body, and reference a public artefact:

daemon(config): validate mutually exclusive embedding sources at startup

Second of two changes adding startup validation for the embedding lane.
The first (#NNN) added the config fields; this one rejects the invalid
combinations in validate_embedding_selection so a bad configuration
fails at boot instead of at first query.

Verified: cargo test -p corecruxd config (14 new cases), manual boot
with each rejected combination.

Reference pull request numbers, issue numbers, or commit SHAs. Those resolve for everyone.

This is a known gap in CONTRIBUTING.md, and it points at a real decision the project has not yet made: either explain the tags publicly or stop putting them in public commit subjects.

7.5 The pull-request template

.github/PULL_REQUEST_TEMPLATE.md has four sections.

Summary. What the PR does.

Type. One of Bug fix, New feature, Refactoring, Documentation, Test coverage.

Checklist, as shipped:

ItemNote
cargo fmt --check passesRemember max_width = 120
cargo clippy --workspace passes with no new warningsCI adds -D warnings
cargo test --workspace passesUse --locked
Coverage does not decreaseThe gate has twelve floors. See 5.8
CHANGELOG.md updated if user-facingSection 7.8
Documentation updated if the API changed

Integration Packs, completed only for PRs touching integrations/community/:

Item
The pack manifest uses crux.integration.v1
A manifest hash and an Ed25519 Passport signature are included
The pack is declarative-only, with no external_helper
Capabilities, network hosts and data access are documented in the pack README
Dangerous capabilities include a maintainer-approved review.json

The checklist omits the three gates that fail newcomers most often: typos, the licence-header check, and the unwrap ratchet. Tick the boxes, then run 5.11 anyway.

7.6 What review actually means here

ExpectationReality
Someone will approve my PRrequired_approving_review_count is 0. Nobody has to review it, but from a fork, somebody must approve the workflow run before checks start (§5.0)
A code owner will be assigned.github/CODEOWNERS is * @myles plus explicit entries for the trust-core, retrieval and MCP crates. require_code_owner_reviews is false, so it is advisory
The checks are the gateCorrect. Eleven of them. See 5.2
Merging is automatic once greenIt goes through the merge queue, usually via gh pr merge --auto. A batch merges only if the whole group passes
My branch must be currentYes. strict: true on branch protection. The queue handles the rebasing

Two consequences follow, and both are on you.

Your description is the review. Nobody is obliged to ask you what you meant. Say what changed, why, and how you verified it.

Green does not mean correct. Semver Compatibility cannot fail (5.2). Route-auth scope enforcement is shadow by default at runtime (3.3). Coverage floors are ratchets, not targets. If your change touches a trust-core crate, say in the description what you did to convince yourself it is safe.

7.7 The obligations CONTRIBUTING.md omits

Sixteen things are missing from CONTRIBUTING.md. Most are covered elsewhere in this set; these three are specific to submitting and have no other home.

The per-crate AGENTS.md obligation

A new crate needs crates/<name>/AGENTS.md, 60 lines or fewer. All 28 existing crates have one. scripts/check-agent-docs.sh enforces both existence and the line cap, and it backs the required check Verify agent-doc references resolve. Write it as you write the crate; retrofitting is worse.

The repo-manifest symbol contract

docs/agent/repo-manifest.yaml carries a ci_assertions block naming symbols, tests, crate directories and fuzz targets that must exist in the tree. The same script asserts every one of them.

Renaming a symbol that appears there fails a required check. Two things follow:

SituationDo
You renamed a symbol named in ci_assertionsUpdate the manifest in the same commit
You added a symbol that agent docs should referenceAdd it to ci_assertions, and anchor the reference by symbol name, never line number; that is on the "Never" list at AGENTS.md:75

Check locally:

bash scripts/check-agent-docs.sh --exec

There is no CLA, and no DCO bot

Verified: no .github/workflows/dco.yml, no CLA application in the required-check list, and no CLA document anywhere in the tree.

The contribution grant lives in the licence itself. LICENSE:130, Submission of Contributions, verbatim:

"Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions."

This is inbound=outbound: contributions are licensed under Apache-2.0 on the same terms as the rest of the work. You keep your own copyright; there is no separate CLA document to sign. See 8.4.

Opening a pull request is the act that grants it. If that is not acceptable to you or your employer, do not open one.

7.8 The changelog

CHANGELOG.md follows Keep a Changelog 1.1.0 and Semantic Versioning.

Structure: ## [Unreleased] at the top, then ## [X.Y.Z] - YYYY-MM-DD headings descending. Sections are ### Added, ### Changed, ### Fixed, ### Security.

Style: entries are a bold lead sentence followed by an explanatory paragraph, not a one-line bullet. Feature entries in the existing file carry a trailing ExecPlan back-reference in italics; as with commit tags, omit that since it does not resolve for outside readers.

Add your entry under [Unreleased] in the section that matches. If your change is not user-facing, do not add one.

The cadence note at CHANGELOG.md:8 is the project's own rule: weekly rolling builds are cut from main, versioned releases ship every four to eight weeks, and "if you tag a release, you write its entry." That rule is not currently being kept, see 9.7.

7.9 Issues, and where to raise things

You want toRoute
Report a bug.github/ISSUE_TEMPLATE/bug_report.yml. Blank issues are disabled
Request a feature.github/ISSUE_TEMPLATE/feature_request.yml
Report a security vulnerabilityNot GitHub. Email security@cuecrux.com. See 8.6
Propose an "Ask first" change, a new on-disk artifact type, a receipt or seal-material change, a default port changeOpen an issue or discussion before writing the code. AGENTS.md:70
Find something to work onThere are no open issues. See chapter 10

Labels that exist: bug, documentation, duplicate, enhancement, good first issue, help wanted, invalid, question, wontfix, ci:fallback. Dependabot adds dependencies and ci. Note that good first issue is currently applied to nothing.

CONTRIBUTING.md:41 names the contribution types the project welcomes: bug fixes with a clear description of the issue and how you verified the fix; corrections to documentation or code comments; performance improvements with benchmark evidence; and test-coverage improvements. Take the benchmark-evidence requirement literally, a performance claim without a measurement is not reviewable.

Sources