{"id":51173228,"url":"https://github.com/anulum/synapse-channel","last_synced_at":"2026-07-04T09:00:45.980Z","repository":{"id":366268248,"uuid":"1275648362","full_name":"anulum/synapse-channel","owner":"anulum","description":"Local-first multi-agent coordination bus","archived":false,"fork":false,"pushed_at":"2026-06-30T07:36:20.000Z","size":4271,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-30T08:27:04.448Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anulum.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":"GOVERNANCE.md","roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":".zenodo.json","notice":"NOTICE.md","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"anulum","custom":["https://www.anulum.li/licensing","https://www.paypal.com/donate?hosted_button_id=4X5F6DNT934HY"]}},"created_at":"2026-06-21T01:11:20.000Z","updated_at":"2026-06-30T06:52:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/anulum/synapse-channel","commit_stats":null,"previous_names":["anulum/synapse-channel"],"tags_count":49,"template":false,"template_full_name":null,"purl":"pkg:github/anulum/synapse-channel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anulum%2Fsynapse-channel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anulum%2Fsynapse-channel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anulum%2Fsynapse-channel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anulum%2Fsynapse-channel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anulum","download_url":"https://codeload.github.com/anulum/synapse-channel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anulum%2Fsynapse-channel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35115742,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-27T02:01:42.829Z","updated_at":"2026-07-04T09:00:45.951Z","avatar_url":"https://github.com/anulum.png","language":"Python","funding_links":["https://github.com/sponsors/anulum","https://www.anulum.li/licensing","https://www.paypal.com/donate?hosted_button_id=4X5F6DNT934HY"],"categories":[],"sub_categories":[],"readme":"\u003c!--\nSPDX-License-Identifier: AGPL-3.0-or-later\nCommercial license available\n© Concepts 1996–2026 Miroslav Šotek. All rights reserved.\n© Code 2020–2026 Miroslav Šotek. All rights reserved.\nORCID: 0009-0009-3560-0851\nContact: www.anulum.li | protoscience@anulum.li\nSYNAPSE CHANNEL — repository overview\n--\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/anulum/synapse-channel/main/docs/assets/header.png\" width=\"1280\" alt=\"SYNAPSE CHANNEL — local-first multi-agent coordination bus\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eStop parallel AI coding agents from clobbering each other's files.\u003c/strong\u003e\u003cbr\u003e\n  Local-first coordination bus — file-scope claims, a shared plan, and durable leases — for one repository or a whole ecosystem of them.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/anulum/synapse-channel/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/anulum/synapse-channel/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/anulum/synapse-channel/actions/workflows/codeql.yml\"\u003e\u003cimg src=\"https://github.com/anulum/synapse-channel/actions/workflows/codeql.yml/badge.svg\" alt=\"CodeQL\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/synapse-channel/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/synapse-channel\" alt=\"PyPI version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/synapse-channel/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/dm/synapse-channel\" alt=\"PyPI downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pepy.tech/project/synapse-channel\"\u003e\u003cimg src=\"https://static.pepy.tech/badge/synapse-channel\" alt=\"Total downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://anulum.li/synapse/pricing.html\"\u003e\u003cimg src=\"https://img.shields.io/badge/commercial%20licence-available-0a7d3c\" alt=\"Commercial licence available\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/python-3.10%2B-blue\" alt=\"Python 3.10+\"\u003e\n  \u003ca href=\"https://codecov.io/gh/anulum/synapse-channel\"\u003e\u003cimg src=\"https://codecov.io/gh/anulum/synapse-channel/branch/main/graph/badge.svg\" alt=\"Coverage\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://api.reuse.software/info/github.com/anulum/synapse-channel\"\u003e\u003cimg src=\"https://api.reuse.software/badge/github.com/anulum/synapse-channel\" alt=\"REUSE status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://securityscorecards.dev/viewer/?uri=github.com/anulum/synapse-channel\"\u003e\u003cimg src=\"https://api.securityscorecards.dev/projects/github.com/anulum/synapse-channel/badge\" alt=\"OpenSSF Scorecard\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/astral-sh/ruff\"\u003e\u003cimg src=\"https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\" alt=\"Ruff\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://doi.org/10.5281/zenodo.20801559\"\u003e\u003cimg src=\"https://zenodo.org/badge/DOI/10.5281/zenodo.20801559.svg\" alt=\"DOI\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nA local-first coordination bus for a fleet of AI agents working in parallel —\nwithin a single repository or spread across a whole ecosystem of them. One\nWebSocket hub is the shared source of truth for **presence**, **work claims**,\n**chat**, **task status**, and **resource offers**: agents address each other\nacross projects and share one plan, while file-scope claims keep the agents in any\none repository off each other's files.\n\nThe bus is transport-light (one dependency, `websockets`), hub-centric by design\n(one place owns presence, leases, and history), and runs entirely on the local\nmachine. Model workers reply on-channel through any OpenAI-compatible endpoint,\nincluding a local Ollama server, with a deterministic rule-based fallback for\noffline use.\n\n**Your existing agents plug in without new code.** Any Model Context Protocol\nhost — Claude Code, Claude Desktop, Cursor — reaches the bus through the bundled\n`synapse mcp` server, which exposes the coordination verbs (claim, release, hand\noff, send, task) as MCP tools and the board, agents, and resources as read-only\nMCP resources. Agents that speak A2A connect through the Agent Card face instead.\nThe hub itself stays protocol-agnostic and the core install keeps its single\ndependency — the MCP and A2A adapters are optional extras (`pip install\n'synapse-channel[mcp]'`). See the [MCP guide](docs/mcp.md).\n\n## At a glance\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/anulum/synapse-channel/main/docs/assets/demo.gif\" width=\"720\" alt=\"A synapse session: declare a plan with a dependency, complete a task, and watch the dependent unblock\"\u003e\n\u003c/p\u003e\n\n```mermaid\ngraph LR\n    A1[\"Agent\"] --\u003e H\n    A2[\"Agent\"] --\u003e H\n    A3[\"Worker\"] --\u003e H\n    SUP[\"Supervisor\"] --\u003e H\n    H[\"SynapseHub\u003cbr/\u003esingle source of truth\"] --\u003e CL[\"Claims \u0026 leases\u003cbr/\u003escope · epoch · checkpoint\"]\n    H --\u003e BB[\"Blackboard\u003cbr/\u003eplan + progress\"]\n    H --\u003e CAP[\"Capabilities\u003cbr/\u003ecards + routing\"]\n    H --\u003e LOG[\"Event log (SQLite WAL)\u003cbr/\u003edurable · replayed on restart\"]\n```\n\nA claim leases a unit of work with a file scope, so two agents never edit the\nsame files; the plan, handoffs, checkpoints, and a stall supervisor keep the work\nmoving; and the durable event log means a hub restart resumes live leases rather\nthan losing them.\n\n\u003e **Coming: Studio** — the dashboard is growing into an operator **[Studio](docs/studio.md)**:\n\u003e a control plane that answers, at a glance, what is happening, what is at risk, and\n\u003e what is safe to do next. The instrument-panel design system and the `/studio`\n\u003e reference have shipped; the live command centre is next. Local-first and read-only by\n\u003e default — an organisation-level workbench is planned as a separate layer.\n\n## Install\n\n```bash\npython -m pip install synapse-channel       # the release from PyPI\npython -m pip install -e \".[dev]\"           # or an editable dev checkout\n```\n\nFor an editable checkout, keep the local `.venv` aligned with the repository's\ndeclared dev, docs, and benchmark extras:\n\n```bash\n.venv/bin/python tools/check_dev_dependency_drift.py --check\n.venv/bin/python tools/audit_dependency_tooling.py --check\n```\n\nThe second check is offline. It verifies that local preflight still covers the\nexpected tool gates, GitHub Actions are pinned to full commit SHAs, Dependabot\ncovers actions/Python/Docker, and the PyPI publish/download metadata surfaces\nremain wired.\n\nThis installs the `synapse` command. To run the hub as an always-on local service\nor a container, see the [deployment guide](docs/deployment.md) (a `systemd` user\nunit and `docker compose` are both included).\n\nTwo optional shell conveniences ship with the CLI: `synapse completions\nbash|zsh|fish` prints tab completion for every subcommand (generated from the\nlive parser, so it never drifts), and `synapse install-shell-hook` adds the\nguarded block that auto-arms a wake listener in each new terminal:\n\n```bash\nsynapse completions bash \u003e ~/.local/share/bash-completion/completions/synapse\nsynapse install-shell-hook          # auto-arm Bash, Zsh, and Fish terminals\n```\n\n## First 60 seconds\n\nOn a clean Python environment, verify the installed CLI before wiring agents into\na real repository:\n\n```bash\npython -m pip install synapse-channel\nsynapse doctor\nsynapse demo\nsynapse quickstart-coding\n```\n\n`synapse doctor` reports local setup issues such as identity, hub exposure,\nroot-filesystem pressure, and missing waiters. A brand-new machine may warn that\nno hub or waiter is running; that is expected before service setup. `synapse\ndemo` starts its own local hub, drives a planner/worker coordination flow, and\nsucceeds when it prints:\n\n```text\nsuccess: coordination demo completed\n```\n\n`synapse quickstart-coding` creates a temporary coding-fleet workspace, runs the\nsame no-collision coding demo used by generated workspaces, removes the temporary\nworkspace after success, and prints:\n\n```text\nsuccess: coding fleet demo completed\n```\n\nOr run the whole first-run sequence as one command:\n\n```bash\nsynapse fleet-init\n```\n\nIt runs the doctor (`--fix` to repair the default local hub and waiter),\nscaffolds a persistent `./synapse-fleet` workspace, probes which provider CLIs\nthis machine can seat (claude, codex, kimi, ollama, …), runs the demo smoke,\nand prints the next-steps plan — waiter arming, per-provider seat commands,\n`git-init`, dashboard — with the workspace's project name filled in.\n\n## Fastest safe trial path\n\nAfter the self-contained demos pass, try Synapse against a real checkout in this\norder:\n\n```bash\npython -m pip install synapse-channel\nsynapse doctor\nsynapse demo\nsynapse quickstart-coding\nsynapse git-init --name trial-agent\nsynapse dashboard --port 8765\nsynapse a2a-card --endpoint-url http://127.0.0.1:8877\nsynapse a2a-serve --endpoint-url http://127.0.0.1:8877\n```\n\nRun this in a disposable or already-versioned repository. `synapse git-init\n--name trial-agent` installs the claim-aware git hooks and writes the local\n`.synapse/` conventions guide before agents edit files. The A2A bridge step is\noptional and local-only: it lets another local tool inspect the Agent Card or\ntalk to the HTTP+JSON bridge, but it is not an external conformance claim. Do not\nbind it off-loopback without bearer auth.\n\n## Releases\n\nThis package is developed in the open and dogfooded daily: a fleet of coding\nagents runs its own coordination on it, so problems surface in real use and are\nfixed quickly. Releases are therefore frequent and mostly small — fixes and\nhardening rather than churn. The wire protocol and the public Python API stay\nbackwards-compatible within a major version; any breaking change is called out in\nthe changelog.\n\nCurrent `0.x` releases are pre-1.0 development releases, not the stable\ncommercial release line. `1.0.0` is planned as the first stable commercial\nrelease of SYNAPSE CHANNEL, with the operational contracts, packaging, support\nsurface, and commercial licensing terms documented as part of that release.\n\nSYNAPSE CHANNEL is seeking startup funding, strategic partners, and aligned\necosystem co-owners who want to help mature the coordination layer for\nproduction multi-agent development. See [commercial licensing](docs/commercial.md)\nor write to `protoscience@anulum.li`.\n\nIf you need a fixed target, pin a version (`synapse-channel==X.Y.Z`); to get the\nlatest fixes, track the newest release. Both are supported.\n\n## Quick start\n\nLaunch a hub plus one or two local model workers in one command:\n\n```bash\nsynapse team\n```\n\nThen, from another terminal, watch the channel or send a message:\n\n```bash\nsynapse listen --name USER\nsynapse send --name USER --target FAST \"what is the status of TASK-1?\"\nsynapse send --require-recipient --target FAST \"ping\"  # fail if FAST is not online\n```\n\nOne-shot sends avoid the common waiter-name collision: `synapse send --name\napi-dev-rx ...` sends as `api-dev`, leaving the persistent `api-dev-rx` wake\nsocket connected. Add `--require-recipient` for directed sends that must not\nsilently miss: the hub returns a private receipt naming the matched online\nrecipients, and the command exits non-zero when none match `--target`.\n\nFor selected sensitive payloads, encrypt the body before it reaches the hub and\ndecrypt it only on the recipient side:\n\n```bash\nsynapse send --target FAST \\\n  --encrypt-key-file ./payload.key \\\n  --encrypt-key-id project-main-v1 \\\n  --encrypt-recipient FAST \\\n  \"private handoff note\"\nsynapse listen --name FAST --for FAST --decrypt-key-file ./payload.key\n```\n\nThe hub still sees sender, target, channel id, key id, recipient names, nonce,\nciphertext, and delivery metadata. This does not manage key discovery or\nrotation.\n\n### Running pieces individually\n\n```bash\nsynapse hub --port 8876\nsynapse hub --port 8876 --db ./synapse.db            # crash-safe: resumes leases + history on restart\nsynapse hub --port 8876 --relay-log ./feed.ndjson    # mirror the channel to a compact file for observers\nsynapse hub --shutdown-close-timeout 5               # bound active socket close handshakes on stop\nsynapse hub --max-progress-per-author 500            # cap retained board progress per author\nsynapse hub --max-findings-per-agent 200             # cap durable findings admitted per agent\nsynapse hub --tls-certfile ./hub.crt --tls-keyfile ./hub.key  # native wss://\nsynapse worker --name FAST --provider ollama --model gemma3:4b\nsynapse worker --name OFFLINE --provider rule        # no network, canned replies\nsynapse worker --name TIER --provider tiered --model small --heavy-model big  # route trivial→rule, hard→heavy\nsynapse relay ./feed.ndjson                          # decode and print that file as readable lines\nsynapse ingest ./synapse.db --memory --cursor ./mem.cursor  # stream durable memory events since a seq cursor (NDJSON)\nsynapse memory-recall ./synapse.db \"transport handoff\"       # local recall over durable memory records\nsynapse compact ./synapse.db --all --max-checkpoints-per-task 3 --archive-report ./compact-report.html\nsynapse board                                        # print the shared task/progress blackboard\nsynapse task declare BUILD --title \"compile\"         # declare/update the shared plan from the CLI\nsynapse task update BUILD --status done              # mark a plan task done so dependents unblock\nsyn ack BUILD --evidence \"pytest -q\"                 # post evidence and mark a board task done\nsynapse supervisor --idle-seconds 300 --history-multiplier 3  # re-offer stalled plan tasks\nsynapse manifest                                     # print capability cards, including contract counts\nsynapse directory                                    # print discovery-only agents/resources\nsynapse route-task BUILD --limit 3 --event-store ./synapse.db  # add observed evidence\nsynapse resource-bids BUILD --resource-kind gpu      # rank live resource offers without reserving capacity\nsynapse a2a-card --endpoint-url https://agent.example.com/a2a/v1  # emit A2A Agent Card JSON\nsynapse a2a-serve --endpoint-url http://127.0.0.1:8877             # run the HTTP+JSON A2A bridge\nsynapse doctor                                       # check for common misconfigs (identity, exposure, hub, waiter)\nsynapse demo                                         # installed self-check: local hub + planner/worker flow\nsynapse quickstart-coding                            # create a temporary coding fleet workspace and run it\nsynapse new coding-fleet ./demo-fleet                # scaffold a runnable two-agent coding demo workspace\nsynapse hub --host 0.0.0.0 --token s3cret            # require a shared secret when binding off-loopback\nsynapse hub --host 0.0.0.0 --token s3cret --tls-certfile ./hub.crt --tls-keyfile ./hub.key\nsynapse hub --max-connections-per-host 4             # cap simultaneous sockets from one remote host\nsynapse send --token s3cret --name USER \"hello\"      # agents present the token to a secured hub\n```\n\n### Use it with your coding agent\n\nSynapse coordinates the agents you already run; it does not replace them.\nIts MCP and A2A adapters are interop surfaces: they let Claude Code, Claude\nDesktop, Cursor, Codex, Copilot-style hosts, Aider, orchestration frameworks,\nand other agent tools participate in one local coordination bus while those\ntools still own prompting, model choice, tool use, and editor/runtime behavior.\nThe [integration demo matrix](docs/integration-demos.md) lists three narrow,\nrepeatable paths and the unsupported behavior that remains outside each demo.\n\n- **Claude Code / Claude Desktop / Cursor (MCP):** point the host at the MCP server\n  and every coordination verb shows up as a tool — no Synapse-specific code.\n\n  ```bash\n  pip install 'synapse-channel[mcp]'\n  synapse mcp --uri ws://localhost:8876        # add this to the host's MCP server config\n  ```\n\n- **Aider, or any non-MCP tool:** claim a file scope before editing and let a git\n  hook release it on commit, so two sessions never touch the same files.\n\n  ```bash\n  synapse quickstart-coding                    # optional: run a temporary no-collision coding demo\n  synapse new coding-fleet ./demo-fleet        # optional: keep the generated workspace\n  synapse git-init --name aider-1              # one step: install the hooks + write the conventions guide\n  synapse git-claim --task-id AUTH --paths src/auth --name aider-1\n  aider src/auth/*.py                          # ... edit; the post-commit hook releases the claim\n  ```\n\n- **Check the wiring:** `synapse doctor` reports the common setup mistakes — no live\n  waiter, a hub exposed without a token, an accidental identity, or a pressured\n  root filesystem — each with its fix. Use `--disk-path \u003cpath\u003e` to check the\n  filesystem that holds a specific workspace or cache.\n\n- **Inspect the live board:** `synapse dashboard --port 8765` opens a\n  loopback-only read-only HTML view of roster, claims, board tasks, progress,\n  fleet visibility, task-dependency graph edges, branch-conflict candidates,\n  release receipts, and advertised capabilities, with the same snapshot\n  available at `/snapshot.json` for local tooling. Pass `--a2a-state-file \u003cpath\u003e`\n  to add persisted A2A task and push-config counts to the fleet section. The\n  dashboard derives task dependencies from the blackboard snapshot and uses live\n  claim metadata for branch conflicts; run `synapse conflicts --check-diff` when\n  you need client-side git-diff refinement. The state snapshot also carries\n  `dead_letters` — directed chats that reached no live connection, per target\n  with counts — so a message nobody is listening for shows up on the page\n  instead of being discovered by a human relaying it. The dashboard is growing\n  into an operator [Studio](docs/studio.md) — open `/studio` for the\n  design-system reference — and ships a React cockpit under `clients/cockpit/`\n  (build instructions in [its README](clients/cockpit/README.md); serve the\n  built bundle with `synapse dashboard --cockpit-dist clients/cockpit/dist`).\n  If you deliberately expose the\n  dashboard with `--allow-non-loopback`, pass `--dashboard-token \u003ctoken\u003e` and\n  require clients to send `Authorization: Bearer \u003ctoken\u003e`; when omitted on an\n  exposed bind, Synapse generates and prints a startup token.\n\n- **Verify a release redeploy:** `synapse doctor --redeploy-checklist` prints\n  package, service, roster, durable-state, and git-hook checks for a post-release\n  local fleet restart. It does not restart services by itself; it gives the\n  operator copyable commands for the installed executable, hub service, presence\n  daemon, wake listener, event log, and git hook path.\n\n- **Install the always-on local services:** `synapse init` prints or installs the\n  hub, project presence, and non-LLM wake listener units. `doctor --fix` prints\n  the exact commands when a waiter is missing.\n\n  ```bash\n  synapse init --project myrepo --identity myrepo/worker --install-user-services\n  synapse init --project myrepo --identity myrepo/worker --start-user-services\n  synapse doctor --fix\n  ```\n\n- **Launch a provider command with Synapse identity:** `worker-session` exports\n  the identity variables before the provider starts. Interactive terminal\n  providers such as Codex, Claude, Kimi, and Grok run in a persistent tmux\n  session by default when launched from an interactive terminal, with a directed\n  waiter kept alive in the background. Non-terminal commands keep the temporary\n  `syn arm` sidecar path.\n\n  ```bash\n  synapse worker-session --identity myrepo/worker -- codex --sandbox danger-full-access\n  ```\n\n- **Inspect or control the tmux wake path manually:** `codex-tmux` is the\n  diagnostic/admin surface behind the automatic provider launch path. It keeps a\n  provider TUI in a named tmux session and injects a fixed wake prompt when\n  Synapse receives a directed message. It does not paste the Synapse payload into\n  the terminal; the provider reads the inbox itself after waking.\n\n  ```bash\n  synapse codex-tmux start --identity myrepo/codex-main --session myrepo-codex --cwd \"$PWD\"\n  synapse codex-tmux wait --identity myrepo/codex-main --session myrepo-codex --cwd \"$PWD\"\n  ```\n\n### Agent ergonomics — the `syn` commands\n\nFor the short loop an agent runs every session — arm a waiter, send a message,\nread the inbox, glance at the board — the package also ships `syn`, a thin,\nidentity-correct front end over the commands above:\n\n```bash\nsyn name                          # resolve and print this terminal's identity\nsyn arm                           # keep a directed-only waiter armed (named \u003cproject\u003e-rx, distinct from the sender)\nsyn say REMANENTIA,CEO \"ack\"      # send to one, several, or all\nsyn ask CEO \"status?\"             # send, require an online recipient, and wait for replies\nsyn inbox                         # print messages addressed to you since the cursor\nsyn board                         # the shared task/progress board\nsyn who --me                      # show whether this identity and its -rx waiter are online\nsyn reap                          # list this identity's shell-hook waiter pidfile\nsyn reap --pid 1234               # remove a dead pidfile or SIGTERM only the verified waiter PID\nsyn locks                         # list this project's active leases with release commands\nsyn ack BUILD --evidence \"pytest -q\" --artifact coverage.xml\nsyn commit README.md -m \"document the change\"\n```\n\nThe one thing it gets right that a hand-rolled shell alias does not is **identity**.\nThe project is resolved from `--project`, then `$SYN_PROJECT` (or `$SYN_IDENTITY`\nfor a `project/\u003ctype\u003e-\u003cid\u003e` multi-agent identity), and the working directory only\nas a last resort — so a command run from the wrong directory does not silently\ncoordinate as the wrong project, and an identity that looks accidental (the home\ndirectory, a system path) is flagged rather than used in silence. Set\n`$SYN_PROJECT` once per terminal and the identity is stable across tool calls. The\n`syn who --me` shortcut dispatches to `synapse who --me --name \u003cresolved identity\u003e`;\nit reports the identity's presence separately from its `-rx` waiter because\npresence is not a wake loop.\n\n`syn-name`/`syn-wait`/`syn-say`/`syn-ask`/`syn-inbox`/`syn-board`/`syn-reap`/`syn-locks`/`syn-ack`/`syn-commit`\naliases are installed too; `syn-wait` uses the same persistent auto-rearming path\nas `syn arm`. `syn reap` is the safe cleanup path for shell-hook waiter sidecars:\nit only inspects this resolved identity's pidfile, and it refuses to signal a PID\nunless the live command line verifies as that exact identity's `synapse arm`\nwaiter. It never pattern-kills processes. `syn locks` queries the live state\nsnapshot using the resolved identity and prints active leases for the project:\nholder, scope, age, remaining TTL, checkpoint/git context, and the explicit\n`synapse release \u003ctask\u003e --name \u003cowner\u003e` command. `syn ack \u003ctask\u003e` posts repeatable\n`--evidence` and `--artifact` values as an `assessment` progress note authored by\nthe resolved identity, waits for the hub confirmation, then marks the board task\n`done`. `synapse release` can also attach a hub-echoed receipt with evidence,\nartifacts, changed files, generated artifacts, approvals, known failures,\nconfidence, and evidence freshness. The receipt includes advisory\n`epistemic_status` metadata (`supported`, `needs_freshness`, `stale`,\n`degraded`, or `unsupported`) plus reasons derived from the submitted evidence;\n`--receipt-json` prints the receipt for automation, and the board records it as\nan assessment note. The `syn commit`\nworkflow holds the project git lease, stages only the requested paths, and\ncommits only those paths so unrelated staged or modified files stay out of the\ncommit.\n\nTo make fresh terminals connect automatically, install the shell hook once:\n\n```bash\nsynapse install-shell-hook --shell auto\n```\n\nNew Bash/Fish/Zsh terminals then export `SYN_PROJECT`/`SYN_IDENTITY` and keep a\ncheap `synapse arm` sidecar running. The hook does **not** silently join whatever\ngit checkout the terminal happens to start in. It joins the neutral\n`SYNAPSE_DEFAULT_PROJECT` lane, or `user` when unset, unless you explicitly set\n`SYN_PROJECT`/`SYN_IDENTITY` or opt a repository in with `.synapse/project`:\n\n```bash\nmkdir -p .synapse\nprintf '%s\\n' myrepo \u003e .synapse/project\n```\n\nFor legacy CWD-derived behavior, set `SYNAPSE_AUTO_PROJECT_FROM_CWD=1` in that\nterminal. The hook also wraps common provider commands (`codex`, `claude`,\n`kimi`, `grok`, `gemini`, `agent`, `ask`, `ollama`) through `synapse\nworker-session`, so cloud and local LLM sessions inherit the same Synapse\nidentity from process start. In an interactive terminal, Codex/Claude/Kimi/Grok\nlaunch through a persistent tmux session and directed wake bridge automatically;\nthe user still types only the provider command. Set `SYNAPSE_PROVIDER_TMUX=0` to\nkeep those providers on the direct execution path, or `SYNAPSE_AUTO_CONNECT=0` to\ndisable the hook for a terminal.\n\n### Durability\n\nPassing `--db` backs the hub with an append-only SQLite event log (standard\nlibrary, WAL mode). Every claim, release, task update, resource offer, and chat\nmessage is recorded, and the hub rebuilds its state by replaying the log on\nstart-up. The guarantee is split honestly by workload: the lease/claim path\ncommits at `synchronous=FULL` (durable across an OS crash); the high-volume\nchat/history path commits at `synchronous=NORMAL` (durable across an application\ncrash, may lose the last commit on power loss).\n\nUse `synapse compact` to bound the durable memory spine after every read-side\nconsumer has advanced past a floor sequence. Add `--archive-report` when the\nmaintenance run should leave an operator-readable HTML record of the\npre-compaction event snapshot:\n\n```bash\nsynapse compact ./synapse.db --all --max-checkpoints-per-task 3 \\\n  --archive-report ./compact-report.html\n```\n\nThe report is written owner-only and includes event counts, the compaction floor,\ncheckpoint/finding removal counts, board tasks, release receipt notes, and a\nbounded coordination timeline. It is an audit aid for a local event store; it\ndoes not certify that release evidence is sufficient.\n\n### Token-thrifty observation\n\n`--relay-log` mirrors every broadcast to a newline-delimited file in a compact\nshort-key form (`encode_lite`), so a token-budgeted agent can watch the channel\nby tailing a file instead of holding a socket. `synapse relay \u003cfile\u003e` decodes it\nback to readable lines and can resume from a saved `--cursor`. The lite form\nkeeps the seven core envelope fields and drops auxiliary ones; the file is bounded\nby `--relay-max-lines`. A committed benchmark measures the saving honestly —\nsee [`benchmarks/`](benchmarks/).\n\n### Exposure\n\nBy default the hub binds to loopback and runs with no authentication — the right\nposture for one operator on one machine. When that is not enough (a worker with\ntool-use, or a hub bound off-loopback), `--token` requires a shared secret that\nconnecting agents present with `--token`. Binding off loopback without a token is\n**refused** rather than silently exposed: the hub will not start unless you set a\ntoken (and `--metrics-token` when metrics are on), or explicitly pass\n`--insecure-off-loopback` to accept the risk. This is a proportionate gate, not a\ncryptographic identity system.\nFor native `wss://`, pass both `--tls-certfile` and `--tls-keyfile`. TLS protects\nthe transport but does not replace `--token`; an off-loopback hub still needs the\nshared secret unless you explicitly opt into `--insecure-off-loopback`.\n\n### MCP server face\n\nAny MCP-compatible agent — Claude Desktop, Claude Code, an editor assistant —\ncoordinates through Synapse with no Synapse-specific code. Install the optional\nextra and point the host at the command:\n\n```bash\npip install 'synapse-channel[mcp]'\nsynapse mcp --uri ws://localhost:8876\n```\n\n`synapse mcp` runs a Model Context Protocol server over stdio that is itself a hub\nclient, exposing the coordination verbs as MCP tools (claim, release, send, hand\noff, declare and update tasks) and the board, state, and manifest as live\nresources. It also exposes read-only MCP resource templates for a single board\ntask, one agent, and one resource kind. The hub stays MCP-agnostic and the core\ninstall keeps its single dependency — see the [MCP guide](docs/mcp.md).\n\nFor Agent2Agent discovery, `synapse a2a-card --endpoint-url ...` projects the\nlive capability manifest into an A2A Agent Card JSON document suitable for a\nthin HTTP edge to serve as `/.well-known/agent-card.json`.\nCapability cards can also carry declarative capability contracts: per-task-class\n`input_schema` and `output_schema` mappings plus optional preconditions and\npostconditions. These contracts are discovery metadata for routing and review;\nthey do not grant executable trust or certify that a remote peer conforms.\n`synapse directory` joins the live capability manifest with resource offers into\na discovery-only capability directory for agents and tools. Directory entries\nare routing hints and review evidence only; they do not reserve capacity,\nauthorize execution, or certify agent/tool trust.\n\n### Official Go client\n\n`clients/go/synapse` provides the official Go client for read-only ops and CI\ntools. It fetches HTTP JSON surfaces such as `synapse dashboard` `/snapshot.json`\nthrough `DashboardSnapshot` or `GetJSON`, with optional bearer authentication\nfor dashboard tokens on exposed HTTP surfaces.\nIt does not implement the WebSocket mutation protocol for claims, chat, board\nwrites, release receipts, or presence. See the [Go client guide](docs/go-client.md).\n\n### Official TypeScript/JavaScript client\n\n`clients/js` provides the official typed WebSocket client, published to npm as\n`@anulum/synapse-channel`. Unlike the read-only Go client it speaks the mutation\nprotocol — chat, claims, releases, board reads, presence, and receipts — and runs\nunchanged in the browser and in Node 20+ with no runtime dependencies. See the\n[TypeScript/JavaScript client guide](docs/js-client.md).\n\n`synapse route-task TASK-1` uses that live directory plus the shared board to\nrank candidate agents with deterministic local signals. With\n`--event-store ./synapse.db`, it also uses positive release-receipt assessment\nnotes as observed evidence and keeps each matched signal tied to its source task\nand durable event sequence. The recommendation is advisory only: it does not\nclaim work, mutate the board, reserve resources, grade agents, or turn a\ncapability card into executable trust.\n`synapse resource-bids TASK-1` uses the same live directory and board task to\nrank resource offers with deterministic local reasons: resource kind, capacity,\nprovider task-class/skill matches, description overlap, resource-name overlap,\nand matching metadata. It is an advisory marketplace-style view only; it does\nnot reserve capacity, authorize execution, mutate the board, or certify provider\ntrust.\n`synapse memory-recall ./synapse.db \"query\"` provides the first product slice of\nprovenance-preserving memory recall. It reads only the local SQLite event store,\nprojects findings, checkpoints, and handoffs into deterministic token matches,\nand returns the source sequence, event kind, task id, actor, and matched tokens.\nIt does not create external embeddings, contact a service, certify truth, or\nmutate hub state.\nTo run that edge directly, use `synapse a2a-serve --endpoint-url ...`; it serves\nthe public Agent Card, forwards `POST /message:send` text/data/file parts into\nSYNAPSE chat, supports immediate `POST /message:stream` Server-Sent Events,\nexposes bridge-local task list/get/cancel plus push-notification configuration\nroutes, accepts JSON-RPC 2.0 calls on `/rpc`, and can enforce Bearer auth plus\nrequest size/depth bounds, persist task state with `--state-file`, fail stale\nopen tasks with `--task-timeout`, and bound one subscription wait with\n`--subscribe-timeout`.\nThe bridge is intentionally a local-first HTTP+JSON edge: it stores bridge task\nstate locally in owner-only state/temp files, rejects unsafe caller ids and\nwebhook targets including delivery-time DNS or redirect targets that resolve to\nlocal networks, bounds stored tasks/history/artifacts/push configs/replay\nhistory with terminal-task retention GC, emits subscription replay only from the\ncurrent bridge process, and does not claim independent A2A conformance until\nremote CI, interoperability, and real webhook receiver validation have run. That\nindependent validation runs as a community track of reproducible\n[validation receipts](docs/a2a-validation-receipts.md) — discovery, task lifecycle,\nwebhook, proxy/TLS, replay, and threat-model — rather than a single pass/fail.\n\n### Git-native claims\n\nA claim can be scoped to the git branch it happens on, resolved client-side:\n\n```bash\nsynapse git-init                                 # one-step setup: install the hooks + write a .synapse/ guide\nsynapse git-claim TASK-1 --paths src/auth.py     # or: synapse git-claim --task-id TASK-1 ...\nsynapse git-hook install                         # (git-init already does this) auto-release on commit/merge\nsynapse conflicts --check-diff                   # predict cross-branch merge conflicts\n```\n\nThe planned [policy engine](docs/policy-engine.md) builds on git-native claims,\nrelease receipts, and event-log evidence so teams can evaluate required tests,\nstrict type checking, owner approval, evidence freshness, generated artifact\nparity, and no-merge-without-receipt rules before turning any advisory output\ninto a local hook or CI gate.\n\n[`synapse hub --paranoid`](docs/paranoid-mode.md) enforces a strict local hub\nprofile and prints an explicit missing-hook checklist: token-required hub access,\ndurable event logs, per-message authentication for selected mutating frames,\nmetrics bearer-token auth, disabled metrics query tokens, and clear gaps for\nencryption, signed events, identity, ACLs, private channels, A2A profiles, and\nexposed deployment review.\n\nThe planned [at-rest encryption](docs/at-rest-encryption.md) profile scopes\noptional protection for SQLite event stores, relay logs, A2A state, cursor files,\narchive reports, temporary files, and backups, with key storage, key derivation,\nrotation, backup recovery, and lost-key recovery boundaries documented before\nany encryption flag ships.\n\nThe [end-to-end encrypted channels](docs/end-to-end-encrypted-channels.md)\nruntime encrypts selected chat payloads with `synapse send --encrypt-key-file`\nand decrypts them locally with `synapse listen --decrypt-key-file`, while the\nbroader profile for private progress notes, handoff checkpoints, A2A artifacts,\nkey discovery, and rotation remains explicit follow-on work.\n\nThe [private channels](docs/private-channels.md) runtime scopes chat delivery to\nexplicit channel members, keeps a bounded member-only live history, mirrors\nchannel-tagged relay events for filtered export, and supports metadata-only\nevent-query channel filters. It does not encrypt payloads or create\ncryptographic identity.\n\nThe planned [differential-privacy blackboard](docs/differential-privacy-blackboard.md)\nprofile scopes redacted and noisy shared blackboard projections for\nmulti-organisation views. It is not implemented yet, keeps raw local board data\nexact for the operator, and does not encrypt payloads, replace private channels,\nreplace end-to-end encrypted channels, anonymize raw logs, or authorize board\nwrites.\n\nThe planned [signed events and mTLS](docs/signed-events-mtls.md) profile scopes\nevent signatures, key rotation, replay protection, verification results, trust\nbundles, certificate pinning, and trusted multi-host peers. It is not\nimplemented yet, does not encrypt payloads, does not replace per-agent identity,\nand does not certify external federation.\n\nThe [per-message authentication](docs/per-message-authentication.md) runtime\nenforces opt-in HMAC-SHA256 authentication for selected mutating WebSocket\nframes after connect authentication. It defines canonical frames, key ids,\nsender-bound CLI keys, nonces, signed sequence metadata, timestamp windows,\nbounded in-memory replay cache behavior, key rotation, revocation results, and\nverification results without claiming payload encryption, public-key signatures,\nsigned events, or identity enforcement.\n\nThe planned [identity and ACL](docs/identity-and-acl.md) profile scopes\nper-agent identity, identity-bound credentials, project namespaces, allowed\nverbs, target patterns, metrics/A2A/dashboard/release privileges,\ndeny-by-default authorization, credential rotation, revocation, and migration\nfrom shared-token mode without claiming runtime enforcement today.\n\nThe planned [signed capability cards](docs/signed-capability-cards.md) profile\nscopes tamper-evident capability advertisements for manifests, directories,\ndashboards, MCP resources, and A2A Agent Card projections. It is not implemented\nyet, keeps unsigned local cards as advisory discovery, and does not authorize\ntools, replace per-message authentication, replace signed events, or sandbox\nagents.\n\n`synapse git-init` bundles the hook install with a short `.synapse/git-claims.md`\nonboarding guide (branch convention + worktree workflow). `synapse state` shows\neach claim's branch; installed git hooks release a claim\nwhen its files are committed or merged; and `synapse conflicts` flags two agents\nabout to edit the same files on branches that merge into the same base.\n`--check-diff` narrows directory or whole-worktree claims to files both branches\nactually changed when both branch diffs are available. The hub stays\n**git-agnostic** — it stores the branch as opaque metadata and never runs git or\nreads a filesystem — so all git work is on the client. See the\n[git-native claims guide](docs/git-claims.md).\n\nFor a concise lease view while coordinating a session:\n\n```bash\nsyn locks              # current project only\nsyn locks --all        # every active lease\nsyn locks --owner api  # one owner or project namespace\n```\n\nWhen a manual release is also the closeout record, attach the evidence directly:\n\n```bash\nsynapse release BUILD --name api-dev \\\n  --evidence \"pytest tests/test_feature.py -q: passed\" \\\n  --changed-file src/synapse_channel/feature.py \\\n  --artifact coverage.xml \\\n  --receipt-json\n```\n\nWhen closeout evidence should be observed rather than hand-entered,\n`synapse verify-release` runs declared commands, records exit codes and\nstdout/stderr SHA-256 digests, hashes named artifacts, captures Git `HEAD`,\ntree, and changed files, then writes receipt JSON for `synapse release --receipt`:\n\n```bash\nsynapse verify-release BUILD --name api-dev \\\n  --run \".venv/bin/python -m pytest tests/test_feature.py -q\" \\\n  --artifact coverage.xml \\\n  --output verified-release.json\nsynapse release BUILD --name api-dev --receipt verified-release.json --receipt-json\n```\n\nThe resulting `supported` status remains advisory: it describes fresh submitted\nevidence, not independent proof that the checks or artifacts are sufficient.\n\nFor safer task selection and release receipts, the local test ownership map\nconnects source files to likely owning tests using AST imports plus a\nconservative filename fallback:\n\n```bash\npython tools/test_ownership_map.py --check \\\n  --source src/synapse_channel/core/receipts.py \\\n  --require-owned src/synapse_channel/core/receipts.py\n```\n\nIt is a deterministic local aid for choosing focused tests; it does not replace\nreview, coverage, or the release receipt evidence itself.\n\nWhen a source change can stale generated outputs, ask the generated-output\ndependency map which generated paths should be included in the same claim:\n\n```bash\npython tools/generated_dependency_claims.py --claim-args \\\n  --source src/synapse_channel/core/receipts.py\n```\n\nThe command prints `--paths ...` arguments for `synapse git-claim` and can also\nemit JSON for release tooling. It is a deterministic coordination aid; the\nowning generator, such as `python tools/capability_manifest.py --check`, remains\nthe freshness check for the generated artefact itself.\n\nFor semantic task scopes, resolve modules, public symbols, API surfaces, tests,\ngenerated artefacts, migrations, or source paths into ordinary claim paths:\n\n```bash\npython tools/semantic_claims.py --selector \\\n  symbol:synapse_channel.core.receipts.build_release_receipt \\\n  --claim-args\n```\n\nThe semantic claim resolver prints the source file, likely owning tests, and\ngenerated outputs that should share the same file-scope claim. It keeps the hub\npath-scope and local-first while giving agents a deterministic semantic planning\nstep before they call `synapse git-claim`.\n\nFor daily claims, `synapse git-claim` can resolve the same selectors directly:\n\n```bash\nsynapse git-claim TASK-RECEIPTS \\\n  --symbol synapse_channel.core.receipts.build_release_receipt \\\n  --semantic-evidence-json semantic-evidence.json\n```\n\nThe command resolves the current git root locally, expands the selector into\nordinary claim paths, and writes receipt-ready selector evidence when requested.\nThe hub still receives only file-scope paths.\n\nBefore merge or handoff, the import graph merge-risk radar compares changed\nfiles with claimed paths, package-local Python import neighbours, CODEOWNERS,\nand mapped test owners:\n\n```bash\npython tools/import_merge_risk.py --changed src/synapse_channel/core/receipts.py \\\n  --claimed src/synapse_channel/core/state.py --check\n```\n\nUse `--base main --head HEAD` instead of `--changed` to read a local branch diff,\nor `--claims-json claims.json` to feed paths from an external claim snapshot.\nThe radar is an advisory local planning check; it predicts likely contention but\ndoes not replace tests, review, or release receipt evidence.\n\nFor post-hoc coordination forensics, query the durable event log directly:\n\n```bash\nsynapse event-query ./synapse.db \"task TASK-1 timeline\"\nsynapse event-query ./synapse.db \"task TASK-1 at seq 120\" --json\nsynapse event-query ./synapse.db \"path src/auth.py between 0 9999999999\"\nsynapse event-query ./synapse.db \"conflicts at seq 120\"\nsynapse event-query ./synapse.db 'timeline(\"TASK-1\").'\nsynapse event-query ./synapse.db 'MATCH (task:TASK {id:\"TASK-1\"}) RETURN timeline'\nsynapse postmortem ./synapse.db TASK-1\nsynapse debug ./synapse.db --fork-at 142 --set status=blocked\nsynapse reproduce ./synapse.db TASK-1 --expect 9f2c…\nsynapse causality causes ./synapse.db 142\nsynapse causality causes ./hub.db peer:96 --peer peer=./peer-hub.db\nsynapse merkle root ./synapse.db\nsynapse reliability ./synapse.db\nsynapse accounting report ./synapse.db --pricing pricing.json --budget budget.json\nsynapse approval request --name dev --subject TASK-1 --reason \"needs sign-off\"\nsynapse approval status ./synapse.db --pending\nsynapse ttl-advice ./synapse.db\n```\n\nThis temporal event-log query path is read-only. It reconstructs task timelines,\ntask state at a sequence or timestamp, path-touch windows, and historical\nfile-scope conflicts from the SQLite event store created by `synapse hub --db`.\nThe Datalog-like and Cypher-like examples are prototype aliases for the same\nsmall query model, not a separate graph database or mutable policy engine.\n\nUse `synapse postmortem ./synapse.db TASK-1` when a task needs a replayable\npostmortem for a handover or incident note. The report includes the durable task\ntimeline, owners, releases, assessment evidence, reconstructed path-overlap\nconflicts, and candidate unanswered messages. Candidate unanswered messages mean\nthe log contains a directed chat mentioning the task id and no later matching\nchat reply; it is an audit signal, not proof of intent.\n\nUse `synapse debug ./synapse.db --fork-at 142` to rewind a task in the log and\ninspect a what-if. It reconstructs the exact claim state — owner, status, paths,\nand the saved resume checkpoint — that the task held at that sequence, then prints\nthe resume manifest an agent would pick up from there (with `--set FIELD=VALUE`\noverriding a resume field) next to the events that really followed. The hub runs\nno task, so this is read-only inspection, not re-execution; it exits `1` when the\ntask held no live claim at that point.\n\nUse `synapse reproduce ./synapse.db TASK-1` to fingerprint a task's authoritative\nhistory into a portable SHA-256 digest. Hub state is a pure fold of an append-only\nlog, so the same claim snapshots and releases replay to the same digest on every\nmachine; `--expect DIGEST` turns it into a gate that fails on any divergence, the\nway a release receipt is verified.\n\nUse `synapse causality causes ./synapse.db 142` to trace coordination causality\nover the log. It folds the durable events into a directed acyclic graph of three\nrecorded relations — a task's own lifecycle, a declared `depends_on` satisfied by\nthe dependency's completion, and a release that let a later, path-overlapping\nclaim proceed — and answers against an event sequence: `causes` for what preceded\nit, `effects` for what it enabled, and `counterfactual` for the downstream events\nthat would lose their recorded cause without it. This is coordination causality\ninferred from recorded scheduling semantics, not statistical causal discovery;\nevery edge is backed by a concrete event, and the counterfactual is a structural\nwhat-if over the inferred graph. With `--peer HUB=PATH` the same queries trace\ncausality *across federated hubs*: the logs merge in the deterministic\nmulti-hub order, events are addressed as `HUB:SEQ`, and an edge whose endpoints\ntwo different hubs authored is tagged `federation` — clock-ordered evidence,\nsince hubs share no sequence, and observe-only like the multi-hub read side;\n`--dot` renders the federated answer as a Graphviz digraph, one cluster per\nhub with federation edges coloured, so the cross-hub topology is visible at a\nglance.\n`synapse causality otel` projects the graph onto OpenTelemetry spans — one\ntrace per task, cross-task dependency/contention edges as span links, ids\ndeterministic — written as JSON (`--out`) or pushed as real OTLP over HTTP\n(`--endpoint`, optional extra: `pip install 'synapse-channel[otel]'`);\n`--service-name` distinguishes hubs sharing one observability tenant,\n`--filter TASK_ID` narrows the projection to named tasks without truncating\ntheir cross-task links, an event recording the lifecycle failure terminal\nprojects span status `ERROR`, and `--watch` re-exports on a fixed cadence —\nidempotent collector-side thanks to the deterministic ids. `synapse causality\nhealth` walks the same graph and flags orphaned claims (claimed, then\nsilence), declared dependencies that never completed, and unreleased claims\nsilent past a threshold — ages measured against the log's own final\ntimestamp, deterministic and replayable; exit `1` signals an anomaly.\n\nUse `synapse merkle root ./synapse.db` to commit the durable log to a single\nMerkle root — a 32-byte fingerprint of every event, so two operators or two\nfederated hubs holding the same log derive the same root and a mismatch proves\nthey differ. `synapse merkle prove ./synapse.db 142` emits an `O(log n)`\ninclusion proof for one event, and `synapse merkle verify proof.json` checks that\nproof offline against a trusted root with no event store — the light-client\nverification a follower runs. The tree follows RFC 6962 (Certificate\nTransparency), so a leaf hash cannot be forged as an interior node. It commits\nwhat the log contains — integrity and inclusion — complementing `reproduce` (a\nper-task digest) with a log-wide, incrementally provable commitment.\n\nUse `synapse reliability ./synapse.db` for evidence-only reliability memory. It\ntracks stale claims, declared failed-check evidence, broken handoff candidates,\nand merge-conflict frequency as audit signals, not scores. It does not rank\nagents, assign trust grades, or replace review of the underlying event rows.\n\nUse `synapse accounting` for opt-in model cost/token usage. Synapse never calls a\nmodel provider and collects no telemetry, so usage exists only when you record\nit: `synapse accounting record` posts a `usage`-kind progress note, and `synapse\naccounting report ./synapse.db` aggregates those notes into per-agent and\nper-model totals, with optional `--pricing` for cost estimates and `--budget` for\nbudget evidence. Budgets are evidence, not an enforcement gate.\n\nUse `synapse approval` for human-in-the-loop approval gates on held tasks or\npolicy-gated releases. `synapse approval request` puts a subject in\n`awaiting_approval`, `synapse approval decide --approve|--reject` records the\ndecision, and `synapse approval status ./synapse.db` replays the notes into the\ncurrent state per subject (the latest event wins, so a re-request re-opens the\ngate). It is advisory evidence and an audit trail, not a hard runtime gate; an\napproved subject can be cited in a release receipt via `synapse release\n--approval`.\n\nThe [agent trust graph](docs/agent-trust-graph.md) connects those reliability\nsignals, positive release receipts, handoff outcomes, and conflict history\ninto an inspectable evidence graph: `synapse trust-graph ./synapse.db` prints\ntyped evidence edges with event-log provenance, filtered by `--agent`,\n`--task`, or a `--since` decay window, as text, JSON, or Graphviz DOT. It does\nnot rank agents, assign trust grades, authorize execution, replace code\nreview, or replace identity and ACL; the routing integration and the\nowner-annotation workflow remain design targets.\n\nThe planned [federated trust model](docs/federated-trust-model.md) profile\ndesigns how independent operator-managed domains could peer — out-of-band,\ndeny-by-default bundle exchange composing identity, signed events, mutual TLS,\nACLs, and receipts across a domain boundary. It is not implemented yet, is not a\ncertificate authority, and does not change the local-first default.\n\nThe [Agent Air Traffic Control architecture](docs/agent-air-traffic-control.md)\nnames how the shipped parts compose into one control loop — separation (claims),\nmerge-risk radar (conflicts), evidence-gated completion (receipts, policy-check,\napproval), post-incident replay (postmortem, reliability), and memory (the ingest\nseam). It is an architecture, not a scheduler: only claims gate a mutation, and\neverything else is read-only or advisory.\n\nThe planned [cross-agent adapter kits](docs/cross-agent-adapter-kits.md) design\nspecifies a `synapse adapters` step that detects installed coding tools (Claude\nCode, Codex, Cursor, Aider, Copilot) and writes a thin claim-aware adapter into\neach tool's native config, plus thin client shims for Python frameworks. Adapters\ncarry only \"claim before edit, release on commit, reach the hub\" — Synapse stays\npersona-neutral and adds no new coordination primitive.\n\nThe [multi-hub sync (CRDT) research](docs/multi-hub-sync.md) asks whether several\nhubs could synchronise state while keeping claim safety and local-first. Its\nhonest core: most state (the append-only event log, presence, progress) merges\nconflict-free, but claims are mutual exclusion and **not** a CRDT — they are\nrouted by single-owner-per-namespace and fail closed on a partition. Not\nimplemented; it adds no cross-hub service to the local core.\n\nThe [sandboxed tools and marketplace research](docs/sandboxed-tools-and-marketplace.md)\nasks what it would take to run untrusted tool code safely — a capability-limited\nWebAssembly sandbox (deny-by-default filesystem, network, and resources) — and\nonly then a marketplace built on signed capability cards, an explicit permission\nmanifest, and run receipts. No untrusted code runs without the sandbox, and no\nexecutable marketplace ships before all the preconditions exist. The sandbox itself\nships today behind the optional `[wasm]` extra; the\n[WASM sandbox getting-started guide](docs/wasm-sandbox-getting-started.md) walks an\noperator from a tool's source through `validate`, `test`, and `run`. The marketplace\nremains a boundary specification — local-first and deny-by-default throughout.\n\nThe [managed GitHub App design](docs/managed-github-app.md) pins the boundary for\nhosted cross-PR conflict prediction: the prediction itself reuses the existing\nlocal-core conflict finder, while everything that makes it managed — webhooks,\nGitHub auth, checks API, hosting — stays out of the local core. Advisory only,\nnot implemented, and gated on a local adoption signal.\n\nUse `synapse ttl-advice ./synapse.db` for read-only adaptive lease TTL advice.\nIt derives completed-task duration samples, active live-claim counts, and stale\nclaim counts from the event log, then prints an advisory default. It never\nchanges the hub default and explicit manual TTL values still win.\n\n## Coordination model\n\n1. Claim before you work: an agent leases a task by id; a live lease blocks other\n   agents from claiming the same task.\n2. Declare a file scope on the claim (a `worktree` and `paths`); the hub refuses a\n   claim whose files overlap another agent's live claim — this is how two agents\n   are kept off the same files. Agents in different worktrees never contend.\n3. Leases auto-expire, so a crashed agent never holds a claim forever, and each\n   lease carries an epoch so a superseded agent cannot act on a dead claim. An\n   owner can save a durable checkpoint on the task; if its lease lapses, the next\n   agent to claim the task inherits that checkpoint and resumes rather than\n   restarting.\n4. Release on completion; status and an optional artefact reference can be\n   attached while the task is in progress. A held task can also be handed off\n   atomically to another online agent — keeping its scope, status, and context,\n   with no window for a third agent to grab it mid-transfer.\n5. Presence, `who`, full state snapshots, and chat history are queryable at any\n   time. After a reconnect to the same running hub, an agent can resume by\n   `idem_key` (retried claims are not applied twice while the hub retains its\n   idempotency cache) and a `resume` cursor (fetch exactly the messages it\n   missed).\n\nAlongside the lease registry, a **shared blackboard** holds the team's plan: a\ntask ledger of declared work with dependencies (the hub refuses dependency\ncycles, so `ready` tasks are well-defined) and an append-only progress ledger a\nsupervisor can read to spot stalls. A declared `LedgerTask` is the *plan*; a\nclaim is the *lease* on doing it — the two share a task id but stay independent,\nso the simple claim flow keeps working. The hub keeps the progress view bounded\nglobally, per author, and per task id (`--max-progress`,\n`--max-progress-per-author`, `--max-progress-per-task`), while the durable event\nlog remains append-only until explicit compaction. Durable findings also have a\nper-agent admission cap (`--max-findings-per-agent`) so one producer cannot fill\nthe shared memory spine. View the board with `synapse board`.\n\n`synapse supervisor` remains deterministic and LLM-free. It re-offers\n`in_progress` tasks after the fixed `--idle-seconds` ceiling, and, by default,\ncan lower that ceiling when completed-task progress cadence in the same board\nshows a faster local pattern. Use `--no-predictive-stall` to disable the\nhistorical-cadence supplement; it is an advisory local board heuristic, not a\nguarantee that work is actually abandoned.\n\nSee [`TEAM_PROTOCOL.md`](TEAM_PROTOCOL.md) for the working agreement and message\nreference.\n\n### Why not just git worktrees?\n\nWorktrees are a good tool and SYNAPSE composes with them rather than competing:\na claim declares its `worktree`, and agents in different worktrees never contend\non files. But worktrees alone solve only file *isolation*, and they solve it by\ndeferring the collision to merge time. What they do not give you:\n\n- **Work deduplication** — two agents in two worktrees can happily build the\n  same feature twice; a claimed task on the shared board cannot be claimed\n  again while its lease is live.\n- **Real-time conflict refusal** — inside one worktree (the common case for a\n  shared checkout), the hub refuses an overlapping file-scope claim *before*\n  the second agent edits, instead of surfacing the damage as a merge conflict\n  hours later.\n- **Visibility** — presence, live claims, a task board with dependencies, and\n  progress you can query, instead of discovering what each agent did from its\n  branch diff.\n- **Continuity** — leases expire, checkpoints survive crashes, tasks hand off\n  atomically; a worktree left behind by a dead agent is just a stale directory.\n- **A durable record** — an append-only event log of who claimed, did, and\n  released what, replayable after an incident (`synapse causality`,\n  `synapse debug`), which no branch topology records.\n\nIf per-agent worktrees already work for you, keep them — and let the hub carry\nthe claims, the plan, and the audit trail across them.\n\n## Library use\n\n```python\nimport asyncio\nfrom synapse_channel import SynapseHub, SynapseAgent\n\nasync def main() -\u003e None:\n    hub = SynapseHub()\n    asyncio.create_task(hub.serve(\"localhost\", 8876))\n    agent = SynapseAgent(\"ALPHA\", uri=\"ws://localhost:8876\")\n    # ... drive the agent: claim, chat, request state ...\n```\n\nTwo self-contained, runnable demos live in [`examples/`](examples/):\n`coordination_demo.py` narrates a full task through the bus (declare, block,\nclaim, refuse an overlap, unblock, hand off), and `llm_team_demo.py` asks an\non-channel model worker a question. Each starts its own in-process hub, so\n`python examples/coordination_demo.py` runs with nothing else set up.\n\n## Architecture\n\n| Module | Responsibility |\n| --- | --- |\n| `state` | Presence, scoped task-claim leases, epochs/versions, and resource offers (transport-agnostic). |\n| `ledger` | Shared blackboard: the declared task plan (with dependencies) and a bounded progress stream. |\n| `scoping` | Worktree- and path-overlap detection that keeps two agents off the same files. |\n| `lifecycle` | Typed task-status states and the legal transitions the hub enforces. |\n| `deadlock` | Wait-for cycle detection so circular hold-and-wait claims are refused. |\n| `protocol` | The on-wire message envelope and message-type constants. |\n| `relay` | Lite/heavy codec (`encode_lite`/`decode_lite`) and append-only NDJSON log helpers for file-based observers. |\n| `archive_report` | Static HTML archive reports for compacted event-store history and release receipt notes. |\n| `hub` | The routing core: connections, names, history, broadcast. |\n| `client` | The reusable async agent connection and coordination helpers. |\n| `persistence` | Append-only SQLite event store (WAL) giving the hub a crash-durable spine. |\n| `journal` | Records mutations as events and replays them to rebuild state on restart. |\n| `ratelimit` | Per-agent and per-host token-bucket limiters, plus per-host connection caps, so one runaway source cannot swamp the hub. |\n| `auth` | Optional shared-secret connect token (proportionate, not a cryptographic identity). |\n| `chat_backends` | Pluggable reply backends (OpenAI-compatible HTTP, rule-based). |\n| `routing` | Classify a request into a task class and route it to a tiered backend. |\n| `llm_worker` | An on-channel agent that answers addressed messages via a backend. |\n| `stall` | Deterministic fixed-threshold and historical-cadence stall policy. |\n| `supervisor` | LLM-free watcher that spots stalled plan tasks and re-offers them. |\n| `capability` | Agent capability cards (A2A-shaped) and the hub-aggregated manifest. |\n| `capability_contracts` | Declarative input/output capability contracts carried by manifest cards. |\n| `capability_directory` | Discovery-only directory joining capability cards and resource offers. |\n| `semantic_routing` | Advisory local task-to-agent recommendations over board tasks and capability cards. |\n| `capability_observations` | Provenance-preserving observed release-receipt evidence for advisory routing. |\n| `resource_bidding` | Advisory resource-offer bids over the live capability directory. |\n| `memory_projection` | Deterministic local recall over durable findings, checkpoints, and handoffs. |\n| `launcher` | One-command local hub + worker startup. |\n| `cli` | The unified `synapse` command. |\n\n## Capability inventory\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eModule and surface inventory\u003c/strong\u003e — counts kept in sync with the source tree by CI.\u003c/summary\u003e\n\n\u003c!-- capability-snapshot:start --\u003e\n\u003c!-- Generated by tools/capability_manifest.py; do not edit counts by hand. --\u003e\n\n### SYNAPSE CHANNEL capability inventory\n\n| Surface | Current inventory |\n|---|---:|\n| Package version | 0.96.0 |\n| Public API exports | 70 |\n| Package modules | 292 |\n| Classes | 412 |\n| Wire message types | 67 |\n| CLI subcommands | 127 |\n| Test functions | 4432 |\n| Benchmark harnesses | 6 |\n| Documentation pages | 48 |\n| GitHub Actions workflows | 12 |\n| Optional-dependency groups | 7 |\n\nThis snapshot is a static inventory generated from the source tree. Performance and coverage claims have their own committed evidence — see `VALIDATION.md` and `benchmarks/`.\n\u003c!-- capability-snapshot:end --\u003e\n\n\u003c/details\u003e\n\n## Documentation and project\n\n- New here? [Use cases](https://anulum.github.io/synapse-channel/use-cases/) · [How it compares](https://anulum.github.io/synapse-channel/comparison/) · [FAQ](https://anulum.github.io/synapse-channel/faq/) · [Troubleshooting](https://anulum.github.io/synapse-channel/troubleshooting/) · [Glossary](https://anulum.github.io/synapse-channel/glossary/)\n- [`ARCHITECTURE.md`](ARCHITECTURE.md) — the module map and coordination model.\n- [`TEAM_PROTOCOL.md`](TEAM_PROTOCOL.md) — the working agreement and wire reference.\n- [`VALIDATION.md`](VALIDATION.md) — how it is tested and the gates a change clears.\n- [`CONTRIBUTING.md`](CONTRIBUTING.md) · [`SECURITY.md`](SECURITY.md) · [`GOVERNANCE.md`](GOVERNANCE.md) · [`ROADMAP.md`](ROADMAP.md)\n- Full documentation site: \u003chttps://anulum.github.io/synapse-channel\u003e\n\n## Security posture\n\nLocal-first by default: the hub binds to loopback, and it refuses a non-loopback bind\nunless a token is configured (or the operator explicitly accepts the exposure with\n`--insecure-off-loopback`). When a deployment crosses that boundary, every control is\nopt-in and deny-by-default:\n\n- **Connect authentication** — a shared-secret token compared in constant time\n  (`--token-file` or `SYNAPSE_TOKEN` preferred over `--token`, which is visible in the\n  process list).\n- **Per-message authentication** — `--require-message-auth` demands authentication on\n  selected mutating frames, with an Ed25519 event-signature trust bundle and mTLS\n  certificate pins for multi-hub pulls and federation peerings; an unresolvable or\n  unpinnable peer is denied, never handled locally.\n- **Deny-by-default ACL** — `--acl-policy` with `--require-acl` rejects mutating frames\n  from identities the policy does not grant.\n- **Bounded resources** — connection, frame-size, JSON-depth, rate, and history caps\n  keep one runaway agent from exhausting the hub.\n- **One-flag strict mode** — [`synapse hub --paranoid`](https://anulum.github.io/synapse-channel/paranoid-mode/)\n  turns the strict set on together.\n\nThe supply chain is gated the same way: a gitleaks pre-commit hook on staged changes\nplus a digest-pinned full-tree gitleaks sweep in CI; a hash-locked CI toolchain\n(uv-compiled with `--generate-hashes`, installed with `--require-hashes`) with GitHub\nActions pinned to full commit SHAs and Docker base images pinned to digests; and\n`pip-audit` on every push alongside the CodeQL and OpenSSF Scorecard workflows. The\nthreat model and how to report a vulnerability are in [`SECURITY.md`](SECURITY.md).\n\n## Known limitations\n\n- **Single hub, single machine.** There is no built-in failover or horizontal\n  scale; the hub is one process and the design is deliberately local-first. A\n  hub restart resumes from the durable log, but it is not a high-availability\n  cluster.\n- **Connect authentication is a proportionate shared secret**, not a\n  cryptographic identity system. Opt-in per-message authentication, Ed25519\n  event-signature trust, mTLS certificate pins, and a deny-by-default ACL policy\n  exist for exposed or multi-hub deployments (see\n  [Security posture](#security-posture)), but every peering is an out-of-band\n  trust decision — bundle bytes can move over the wire\n  (`synapse federation offer`/`fetch`, fingerprint-compared, never\n  trust-on-first-use), yet there is no automatic trust distribution — and an\n  agent's identity is a declared name, not a per-agent credential. Do not expose\n  the hub on an untrusted network and rely on the token alone.\n- **Graceful shutdown is bounded, not transactional.** `SIGTERM`/`SIGINT` stop\n  accepting new sockets, close active WebSocket sessions within\n  `--shutdown-close-timeout`, and rely on per-mutation persistence for durable\n  state already accepted by the hub.\n- **Takeover is a local recovery tool, not authentication.** The hub rate-limits\n  repeated takeovers with `--takeover-cooldown` and logs takeover/conflict\n  outcomes with sender, remote host, and close reason, but agents remain trusted\n  local processes.\n- **Agents are trusted.** The bus coordinates agents; it does not sandbox them.\n  An agent is trusted to the extent the operator trusts the process it runs in.\n- **Task-class routing is heuristic.** The classifier sorts a request by length\n  and a keyword set; tune the thresholds for your workload. Per-tier model\n  latency is not benchmarked offline (it needs a live model server).\n- **File-scope claims are advisory, not filesystem access.** The hub never reads\n  a filesystem; a claim's `paths` are opaque strings compared only for overlap.\n  Normal relative paths stay narrow, while absolute or traversal-like declarations\n  such as `../../etc/passwd` widen to the whole worktree so they cannot\n  underclaim and miss a conflict. They do not grant filesystem access. See\n  [`SECURITY.md`](SECURITY.md).\n- **Metrics are opt-in and off by default.** `synapse hub --metrics` exposes a\n  Prometheus `/metrics` and a JSON `/health` endpoint on the hub's port; without\n  the flag the hub serves no HTTP. The endpoint carries operational metadata, so\n  keep it on a loopback bind, or require `--metrics-token` before exposing it.\n  The header form, `Authorization: Bearer \u003ctoken\u003e`, is the default token\n  presentation. The query-string form `?token=\u003ctoken\u003e` is disabled by default and\n  is accepted only with `--metrics-query-token-ok`, because query tokens leak\n  easily into logs and history. The live board, state, and manifest also remain\n  available over the CLI and the MCP resources.\n- **`synapse --version` is network-silent by default.** Set\n  `SYNAPSE_UPDATE_CHECK=1` to opt in to a best-effort PyPI newer-release check\n  (once a day, cached, no payload beyond the request itself). Set\n  `SYNAPSE_NO_UPDATE_CHECK=1` to suppress the check even when opt-in is present.\n\n## Commercial use\n\nSYNAPSE CHANNEL is **dual-licensed**, and there is **no feature difference between the\nopen-source and the commercial build** — the package on PyPI *is* the full product. A\ncommercial licence changes the terms, not the code.\n\n- **Use it free under the AGPL-3.0** for open-source, research, internal, or personal\n  work — including inside a company — as long as you do not expose a closed-source or\n  hosted derivative over a network to third parties.\n- **Buy a commercial licence** to ship a **closed-source** product or a **SaaS** without\n  the AGPL's network-copyleft obligation.\n\n| Plan | For | Grant |\n| --- | --- | --- |\n| **Community** — free (AGPL-3.0) | open source, research, personal | the full feature set; copyleft applies |\n| **Indie** — pay-what-you-want, from CHF\u0026nbsp;9.99 | a solo developer or one closed-source project | copyleft exemption for **one** product, perpetual for the purchased version line |\n| **Team** | a company shipping closed-source or SaaS | exemption for **unlimited** projects in one legal entity, with email support |\n| **Managed / Enterprise** | hosted multi-tenant coordination, SLAs, compliance | bespoke terms |\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://anulum.li/synapse/pricing.html\"\u003e\u003cimg src=\"https://img.shields.io/badge/View_plans_%26_buy-anulum.li%2Fsynapse-0a7d3c?style=for-the-badge\" alt=\"View plans and buy a commercial licence\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nPlans and checkout are at **[anulum.li/synapse/pricing.html](https://anulum.li/synapse/pricing.html)** (Polar.sh, CHF). For enterprise, OEM, academic, non-profit, managed-hosting, or co-ownership terms, write to [protoscience@anulum.li](mailto:protoscience@anulum.li) with the evaluation details listed in [`docs/commercial.md`](docs/commercial.md). The full terms are in [`COMMERCIAL-LICENSE.md`](COMMERCIAL-LICENSE.md).\n\n## How to cite\n\nIf you use SYNAPSE CHANNEL in your work, please cite it. Metadata is in\n[`CITATION.cff`](CITATION.cff); a BibTeX entry:\n\n```bibtex\n@software{sotek_synapse_channel,\n  author  = {Šotek, Miroslav},\n  title   = {SYNAPSE CHANNEL: Local-first multi-agent coordination bus},\n  url      = {https://github.com/anulum/synapse-channel},\n  doi      = {10.5281/zenodo.20801559},\n  version = {0.96.0},\n  year     = {2026}\n}\n```\n\n## Licence\n\nDual-licensed: **AGPL-3.0-or-later**, with a commercial licence available — see\n[Commercial use](#commercial-use) for the plans and\n[pricing](https://anulum.li/synapse/pricing.html). [`LICENSE`](LICENSE) holds the full\nAGPL text, [`COMMERCIAL-LICENSE.md`](COMMERCIAL-LICENSE.md) the commercial terms, and\n[`NOTICE.md`](NOTICE.md) the licensing boundary. The repository is\n[REUSE](https://reuse.software/) 3.x compliant.\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.anulum.li\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/anulum/synapse-channel/main/docs/assets/anulum_logo_company.jpg\" width=\"170\" alt=\"ANULUM\"\u003e\u003c/a\u003e\n  \u0026nbsp;\u0026nbsp;\u0026nbsp;\n  \u003cimg src=\"https://raw.githubusercontent.com/anulum/synapse-channel/main/docs/assets/fortis_studio_logo.jpg\" width=\"170\" alt=\"Fortis Studio\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u0026copy; 1998–2026 Miroslav Šotek \u0026middot; \u003ca href=\"https://www.anulum.li\"\u003eanulum.li\u003c/a\u003e \u0026middot; \u003ccode\u003eprotoscience@anulum.li\u003c/code\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanulum%2Fsynapse-channel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanulum%2Fsynapse-channel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanulum%2Fsynapse-channel/lists"}