Skip to content

Git-native claims

A work claim can be scoped to the git branch the work happens on. The hub stays git-agnostic — it never runs git and never reads a filesystem — so all git resolution happens client-side and the branch travels as opaque metadata on an ordinary claim. The hub stores it, replays it from the durable log on restart, and shows it in the state view, but it never acts on it. That keeps the local-first, single-dependency guarantee intact while making claims branch-aware.

Claim on the current branch

synapse git-claim TASK-1 --paths src/auth.py --base main
# equivalent for structured argv builders:
synapse git-claim --task-id TASK-1 --paths src/auth.py --base main

The branch is resolved locally with git rev-parse --abbrev-ref HEAD and sent on an ordinary claim, carrying the branch, the base it will merge into, and the declared auto-release policy. The repository root is resolved too (with git rev-parse --show-toplevel) and set as the claim's worktree, so a git-claim is isolated to its own repository: two repositories that declare identically-named paths never contend, while two claims in the same repository still detect an overlap. synapse state then shows the branch alongside the claim:

Active claims (1):
  TASK-1 [claimed] owner=USER paths=src/auth.py checkpoint=- git=feature/x->main

Options

Option Meaning
--paths File-scope path the claim intends to touch (repeatable).
--module, --symbol, --api, --source, --test, --generated, --migration Resolve semantic selectors locally and merge their derived source/test/generated/migration paths into the ordinary claim paths sent to the hub.
--semantic-evidence-json Write receipt-ready semantic selector evidence JSON under the git root, or to an absolute path.
--base The branch the work merges back into (default: main).
--auto-release-on The release trigger recorded on the claim: manual, commit, or merge (default merge).

Claim paths are coordination scopes, not filesystem reads. Use normal repository-relative paths such as src/auth.py or docs/cli.md for narrow claims. Absolute paths and any path containing .. are treated as traversal-like declarations and widen to the whole worktree. That conservative fallback may over-claim, but it does not under-claim and miss a real conflict.

The --auto-release-on value is the policy stored with the claim; a client-side git hook enacts it so a finished branch frees its claim without a manual step.

Use either the positional TASK-1 form or --task-id TASK-1, not both. The named form exists for scripts and agent adapters that assemble command arguments from structured fields. synapse git-release is reserved for the installed hooks and auto-detects releasable claims from the git diff; for a manual release, use synapse release <task> --name <owner>.

Claim a semantic selector

Use the semantic flags when the work is naturally described by a module, symbol, API object, source path, owning test, generated artefact, or migration:

synapse git-claim TASK-RECEIPTS \
  --symbol synapse_channel.core.receipts.build_release_receipt \
  --semantic-evidence-json semantic-evidence.json

The command resolves the current git root first, runs the same deterministic resolver as python tools/semantic_claims.py, and expands the selector into the source file, likely owning tests, and generated outputs that should share one claim. Those derived paths are merged with any explicit --paths and sent to the hub as ordinary file-scope paths. The selector text and derived paths stay local unless you choose --semantic-evidence-json and later attach that JSON to a release receipt.

Auto-release on commit or merge

Install the git hooks once per repository so finished work frees its claims with no manual step:

synapse git-hook install

This writes a post-commit and a post-merge hook that call synapse git-release. After each commit or merge, git-release resolves the changed files locally (git diff-tree for a commit, git diff ORIG_HEAD HEAD for a merge) and releases any claim you hold whose --auto-release-on matches the trigger and whose declared paths were touched. Add --name (and --token-file for a secured hub) to match the identity your agent claims under; a pre-existing hook from anything else is left untouched.

The hub is never involved: it only ever receives an ordinary release, and a hook never blocks a commit — an unreachable hub or no matching claim is simply a no-op.

Because a missing hook — or one whose baked-in synapse path has since moved — fails silently at commit time, confirm the setup with:

synapse git-hook test

It reports whether each post-commit/post-merge hook is installed and whether the executable it invokes still resolves, exiting non-zero on any gap. Gate your deployment on it: this project's own CI installs the hooks in a scratch repo and runs git-hook test on every push, so a regression in the install-or-resolve path is caught before release. (synapse git-init installs the hooks and writes the conventions guide in one step.)

Predict merge conflicts

See a collision before it happens:

synapse conflicts
synapse conflicts --check-diff

synapse conflicts reads the hub's live claims and flags every pair held on different branches with the same merge base whose declared paths overlap — two agents about to edit the same files on branches that will merge into one target. Claims with different bases are ignored because their branch-integration risk is not the same merge point. --check-diff refines the prediction against each branch's actual git diff base...branch, so only files both branches have really changed are reported. A directory-scoped claim such as --paths src matches changed files below that directory, and a whole-worktree claim is refined to the common changed files when both branch diffs are available. A branch that is not checked out locally is kept as a conservative warning rather than dropped.

Predicted conflicts (1):
  A@feature/x vs B@feature/y (both -> main): src/auth.py

synapse conflicts exits 0 when nothing is predicted, 2 when a conflict is, and 1 if the hub is unreachable — so a gate like synapse conflicts && git merge feature/x proceeds only on a clean, successfully checked result.

The prediction is computed entirely on the client from the ordinary state snapshot; the hub runs no git.

For semantic merge-risk beyond direct path overlap, run the import graph merge-risk radar against changed files or a branch diff:

python tools/import_merge_risk.py --changed src/auth.py --claimed src/session.py --check
python tools/import_merge_risk.py --base main --head HEAD --claims-json claims.json --json

The radar combines package-local Python import edges, CODEOWNERS, and mapped test owners with the changed and claimed paths. It is advisory and client-side only; use it to decide whether to coordinate, expand tests, or include more evidence in the release receipt.

What stays out of the hub

A git-scoped claim is an ordinary claim with one extra field. The hub deserialises that field for storage and display but runs no git and reads no filesystem — the branch is resolved and acted on entirely on the client. Resist any temptation to move git execution into the hub: the git-agnostic hub is the whole local-first guarantee.