Contributing
Open an issue and get maintainer agreement before starting a large change. Security vulnerabilities are the exception: never open them as public issues. Report them privately through the security policy.
Setup with a coding agent
The repository includes a contributor bootstrap skill for signing, pinned dependencies, local builds/tests, and PR readiness. From a checkout of this repository, invoke it with:
- Codex:
$hikyo-contributor-bootstrap - Claude Code:
/hikyo-contributor-bootstrap
No separate skill installation is needed. The shared instructions live under
.agents/skills/; .claude/skills/ links to the same copy. The skill asks
whether you also want a local Docker or source-built instance to explore, and
continues independent contributor setup while you decide. It preserves existing
signing configuration and does not push, merge, or deploy without authorization.
Finding the right CI workflow
Start with the CI guide. It explains the required PR
checks, the maintenance and release-acceptance menus, and which workflows are
internal helpers. Every push receives automatic ci-feedback. Before merge, a
maintainer adds the approved PR to the mandatory merge queue. ci-queue-required
admits the exact head, then requires full validation of its current-base merge
group. ci:full and ci-required-next remain the full-only rollback route.
Developer Certificate of Origin
Every commit in a pull request must carry a Developer Certificate of Origin (DCO) sign-off. It must also carry a cryptographic signature that GitHub reports as Verified. After completing the signing setup, commit with:
git commit -S -sThe sign-off certifies the Developer Certificate of Origin 1.1. CI checks the pull request’s commit history; a sign-off added only to a squash message does not satisfy the gate. Hikyo uses the DCO, never a Contributor License Agreement (CLA), so contributors retain their copyright.
Lowercase -s (--signoff) adds the DCO trailer. Uppercase -S (--gpg-sign)
creates a cryptographic signature using your configured signing key. With
commit.gpgsign=true, git commit -s also signs cryptographically, but the
explicit -S -s example makes both requirements visible. Neither flag configures
a signing key for you.
Commit signing setup
Run the commands below from the repository root in a POSIX-compatible shell
(including Bash or Zsh). Git configuration commands use --local so they apply
to this clone. If your signatures already pass local and GitHub verification,
keep your existing key and configuration and proceed to
verification.
Identity and signing key
Set your actual name and an email verified on your GitHub account, including a GitHub-provided private noreply address if preferred:
git config --local user.name "Your Name"
git config --local user.email "your-verified-email@example.com"For SSH signing, use Git 2.34 or newer and an existing SSH key, or follow
GitHub’s key generation and ssh-agent setup guide.
Adjust the key path below to your key. ssh-add needs a running SSH agent and
may prompt for your key’s passphrase:
hikyo_signing_key="$HOME/.ssh/id_ed25519"
ssh-add "$hikyo_signing_key"
git config --local gpg.format ssh
git config --local user.signingkey "$hikyo_signing_key.pub"
git config --local commit.gpgsign trueAdd the public key to GitHub as a Signing Key, following GitHub’s key registration guide. An existing Authentication Key must also be registered as a Signing Key.
Local SSH verification
GitHub key registration does not configure local Git verification. The pre-push
checker requires a locally trusted signature (G), so configure an
allowed-signers file.
Continuing in the same shell, add your public key to a file inside Git’s metadata
directory, outside tracked source files:
hikyo_allowed_signers="$(git rev-parse --absolute-git-dir)/hikyo-allowed-signers"
hikyo_signer="$(git config --local user.email) $(cat "$hikyo_signing_key.pub")"
if ! grep -Fqx -- "$hikyo_signer" "$hikyo_allowed_signers" 2>/dev/null; then
printf '%s\n' "$hikyo_signer" >> "$hikyo_allowed_signers"
fi
git config --local gpg.ssh.allowedSignersFile "$hikyo_allowed_signers"If you already maintain an allowed-signers file, retain it and add your public key there instead. For commits from other contributors in your branch, verify their key identities before adding their public keys to your local trust file.
Other signing formats
You can keep an existing GPG or S/MIME signing setup. GitHub documents
generating a GPG key,
adding a GPG key to GitHub,
and configuring Git for GPG, SSH, or X.509 signing.
Keep commit.gpgsign=true. The local checker requires status G; a valid GPG
signature with unknown local trust (U) does not pass. Establish local trust
only after verifying the signing key’s identity.
Verify before pushing
Install the hook once per clone and fetch the canonical repository’s main branch
as the checker base. The dedicated hikyo-upstream/main reference keeps canonical
history separate from your fork’s origin/main, so ordinary fork fetches cannot
replace the comparison base:
scripts/git/install-hooks.sh
git fetch https://github.com/Hikyo-Org/Hikyo.git refs/heads/main:refs/remotes/hikyo-upstream/mainAfter creating your contribution with git commit -S -s, run:
git log -1 --format='%h %G? %s'
scripts/ci/check-dco.sh hikyo-upstream/main HEAD
scripts/ci/check-commit-signatures.sh hikyo-upstream/main HEADExpect G in the log and both checks to report success for the complete PR
range. Re-run the checks after amending or rebasing. If signing or verification
fails, keep signing enabled and resolve the reported key, agent, or trust error;
do not bypass the hook. After pushing, confirm Verified for every PR commit
on GitHub. Local verification and
GitHub verification
are separate checks, and both must pass.
Pull requests from forks
Hikyo uses vouch. CI validates a fork’s
pull request only after its author is listed in
.github/VOUCHED.td;
until then, ci-queue-required reports the author as not vouched and the pull
request stays open. A maintainer vouches for you, usually after you have opened
an issue about the change, and a maintainer approves each workflow run from a
fork. CI runs fork code without secrets. A fork pull
request that changes anything under .github/ cannot pass CI; a maintainer
lands such changes from a branch in this repository.
Security-sensitive contributions
Contributions touching cryptography, authentication, deployment adapters, or delivery paths require maintainer security review. Maintainer-authored changes also require adversarial security review. Automated review is a compensating check and does not constitute independent human review.
Do not report vulnerabilities in public issues. Use the private channels in the security policy.
Design decisions
The locked architecture decision records live in docs/adr/
and the build-ready specification set in docs/spec/.
Code comments cite them by file stem (“the encryption-model ADR” is
docs/adr/encryption-model.md); docs/adr/README.md maps every short name to
its file. A change that contradicts a locked ADR reopens it under the
amendment procedure rather than silently
diverging. See the OSS mechanics ADR, section
Governance, for the full mechanism.
Local verification
Before you request review, run the checks for what you touched:
- Go changes:
go test ./<changed-package>/..., plusgo test ./...for anything cross-cutting. Add or update tests for the behaviour you change. There is no numeric coverage gate, so reviewers, not an automated threshold, judge whether the tests cover the change. web/changes:node --run typecheckandnode --run testinweb/.- Run the formatter and linters so the
lintgate does not bounce the pull request.
You do not need to reproduce the full release gate locally; CI is the source of truth for that.
For browser flow tests, run pnpm --dir web run e2e:install, then
pnpm --dir web run e2e from the repository root. Local development can leave
HIKYO_E2E_MAIL_BINARY unset: the fixture builds its TLS SMTP helper from the
current checkout using Go. To use a prebuilt helper instead, set it to the
absolute path of a fresh binary built with
go build -o ./mail-sink ./internal/mailtest/cmd. When CI is present, the
fixture requires a non-empty HIKYO_E2E_MAIL_BINARY before creating temporary
files or starting a process. The browser workflow supplies this binary from its
same-run app artifact; missing configuration fails instead of compiling locally.
For optional feedback using the same package checks as the fast CI workflow:
scripts/ci/fast-feedback.sh
scripts/ci/fast-feedback.sh --working-tree # explicitly include local editsThe default comparison base is hikyo-upstream/main. Set FAST_FEEDBACK_BASE
and FAST_FEEDBACK_HEAD to test an explicit base/revision pair in a clean
checkout of that revision. --plan prints the selected domains without running
checks. Prepare the pinned tools and frozen client/web dependencies first; this
command does not install Node dependencies, generate files, or fix source. Go
checks can download modules/toolchains and populate normal Go caches. See
the local feedback contract
for the checks and limits. The signed-commit pre-push hook remains installed;
the local feedback helper is optional and does not authorize merge. Hosted
useful feedback must pass before queue admission.
Continuous integration
Each pushed commit receives fast ci-feedback using selected package checks.
Its four-minute runner timeout includes setup; shared-runner queue time is extra.
Application Go, tooling Go and frontend checks have independent runners with
the same deadline. All three lanes must succeed before queue admission.
This feedback does not authorize merge or replace any full-suite coverage.
When the change is ready, a maintainer adds the reviewed PR to the mandatory
merge queue. The trusted ci-queue-required check admits the exact head only
with successful useful feedback, valid signatures/DCO, and current review and
workflow authority. Admission alone cannot merge a PR. The queue runs the
complete suite on its immutable merge group against current main; every rebuilt
or reordered group needs fresh full proof. You do not need ci:full in queue
mode. The group remains blocked until it passes all mandatory domains, including:
lint,test, and the sharded isolation suites;race, the race detector over every package except./internal/isolation/(that suite runs race-instrumented in thereliabilityworkflow’sracesuite, scheduled Mondays at 04:00 UTC or started manually withsuite=race);fuzz(see below);govulncheckfor known vulnerabilities, plus the supply-chain, web, compose, and Kubernetes end-to-end checks.
You do not need to run the complete suite locally. Follow automatic feedback,
resolve review findings, and request maintainer queue admission. The permanent
ci:full / ci-required-next route is used only when operators restore the
strict legacy full-candidate policy. See the CI guide
for queue proof and protected rollback.
Fuzzing
Fuzzing feeds a function randomised inputs to surface crashes and panics that
example-based tests miss. CI runs a bounded fuzz pass over every Fuzz* target
on every admitted full candidate, so you never have to fuzz manually. To reproduce or
extend one target locally:
go test -run='^$' -fuzz='^FuzzParseHeader$' -fuzztime=30s ./internal/crypto/When fuzzing finds a failure, CI keeps the minimised input for 30 days and
replays it against the pull request’s trusted base. A finding that does not
reproduce on the base is added to the pull request with its replay command; one
that also fails on the base opens or updates a standalone bug issue. Either way,
fuzz and the required full-proof check stay red until it is fixed. Commit the minimised input
with the fix so go test ./... keeps it as a regression case.