Synapse is currently invite-only on the source repo. If you have access, this is the operational guide. If you don’t and would like to, open a thread.
One-time setup
git clone https://github.com/romulofebasi/synapse.git
cd synapse
./scripts/bootstrap.sh # activates .githooks/ and checks toolchain
Required:
- Rust 1.89+ (matches
Cargo.tomland native file locking) - POSIX shell for the git hooks
Recommended (the bootstrap script lists what’s missing):
cargo-nextest: faster test runnercargo-deny: license/advisory/ban auditcargo-shear: orphan dep detectortypos: pre-commit typo catchergit-cliff: local changelog preview
Commit messages (mandatory)
Conventional Commits, with scope:
type(SCOPE): subject
type ∈ {feat, fix, docs, refactor, perf, test, chore, build, ci, revert, style}SCOPEis the SYN-N ticket (e.g.SYN-60) or an area (cli,mcp,index,store,core,model,i18n,config,deps,ci,hooks)subjectis imperative, lowercase first letter, ≤72 chars total, no trailing period!before:marks a breaking change:feat(SYN-60)!: rename roles to memberships
Enforced by .githooks/commit-msg and re-enforced by .github/workflows/commit-lint.yml on every PR.
Examples that pass:
feat(SYN-22): introduce note entity type
fix(index): respect PRAGMA foreign_keys on reopened connections
docs(adr): record adoption of rmcp 1.7
chore(deps)!: bump rusqlite 0.38 to 0.39
Before pushing
The pre-push hook requires Cargo and rejects failed validation:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo nextest run --all-features # falls back to cargo test
python3 scripts/check-native-contracts.py
cargo doc --no-deps --all-features # if src/ changed
You can run these any time:
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo nextest run --all-features
cargo deny check
Adding a feature
- Ticket exists? If yes, the SYN-N is your scope. If no, open one tied to the right phase milestone (
v0.1/v0.2/v0.3/v0.4/v0.5/v1.0). - Business rule exists? Check
docs/business/BUSINESS_RULES.md. If your change contradicts a rule, the rule changes first (PR + ADR). - Where does code go? Edge (CLI or MCP) calls the same function in
core/. A feature that lives only in one edge is a bug. - File-size sanity (ADR-015). Before adding 100+ lines to an existing file, check
wc -l. Yellow tier (500-800 lines): the reviewer must call it out. Red tier (800+): a refactor issue must exist and be linked, and the new code must either be part of the refactor or already remove lines. - Tests. Unit tests next to the code; integration tests in
tests/cli.rs; snapshot tests withinsta. Property tests on parsing/encoding code. - Smoke test the release binary. After clippy + unit tests pass, build
--releaseand exercise the feature end-to-end against a temp workspace.cargo testcovers logic; smoke covers integration (filesystem, CLI parsing, MCP stdio). Don’t mark the ticket done without it. - Translate. Every user-visible message gets a key in
i18n/en/synapse.ftlandi18n/pt-BR/synapse.ftl, in the same commit as the feature.
File-size policy (ADR-015)
Code-review caps to keep the project legible:
| Tier | Lines | What it means |
|---|---|---|
| Green | < 500 | Healthy. No action. |
| Yellow | 500-800 | The reviewer of any PR touching the file flags it. A refactor proposal is welcome, not forced. |
| Red | 800+ | A refactor issue must exist and be linked from every PR adding code. New code blocks merge unless it (a) net removes lines, or (b) is part of the refactor. |
Line count is a heuristic, not dogma: what matters is cohesion. A 600-line file of schemars-derived argument structs is fine; a 600-line file of braided business logic is not. ADR-015 has the full playbook and the principles (single responsibility per module, dependency inversion at boundaries, use-case isolation, edge/core/data layering preserved).
Current candidates (2026-05-25): none in red tier. src/mcp/server.rs was the example that drove ADR-015 and landed at ~640 lines (yellow tier) after the SYN-150 split: every other module in src/mcp/ stays green.
Adding an ADR
A non-obvious decision needs an Architecture Decision Record. Copy docs/adr/template.md, name it NNN-kebab-title.md, link from docs/adr/README.md. One decision per file.
Releasing
Maintainers prepare releases through ordinary reviewed source changes:
# Generate a candidate section with the reviewed git-cliff version and cliff.toml.
git cliff --unreleased --tag vX.Y.Z --strip all --offline --no-exec
# Validate committed manifest/lock versions, notes and publication controls.
python3 scripts/check-release-tests.py -v
python3 scripts/check-release-independent-tests.py -v
python3 scripts/check-release-document-tests.py -v
Replace the candidate section rather than prepending it twice. Preserve older
sections exactly. Commit matching root manifest and lockfile versions with the
reviewed notes, then require exact-source CI, MSRV and independent review. Only
after those gates pass, create the authorized annotated version tag on that
reviewed source. Use Rômulo Febasi <romulo@febasi.com.br> for both commit and tag
identity. Changelog generation alone does not create a Git tag.
The tagged workflow builds four native targets: Linux x86_64 and ARM64, Apple Silicon macOS, and Windows x86_64. It packages document bytes from committed Git blobs, checks every archive changelog against the source receipt, and signs the checksum manifest before publication. It does not write back to main. The public mirror preserves the original assets and signature. npm independently verifies the exact source receipt, signature and archive layout before publishing five platform/launcher packages with OIDC.
Existing release tags and assets are never replaced by the workflow. Fix a published packaging defect with a new reviewed patch version. An explicit retry of an unpublished release must select the existing tag as the workflow ref and input; a branch dispatch does not retain the required signing identity.
See ADR-007 and release verification for the complete contract and platform limits. Checksums and signatures authenticate selected bytes; they do not prove independent build reproducibility.
House rules
- Don’t add a dependency without an ADR.
- Don’t reach for
unsafe:#![forbid(unsafe_code)]is set at the crate root. - Don’t introduce
serde_yamlorserde_yml: both are banned indeny.toml(ADR-004). - Don’t use
unwrap()in library code; doctests use?with# Ok::<_, Error>(()). - Don’t shell out to
gitfrom production code: usegixif needed. - Don’t add a CLI message without a Fluent key.
If something here is wrong, edit it (this file is the source of truth for contributors).
Ship it.