claude-agent-sync 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_agent_sync-0.2.1/LICENSE +21 -0
- claude_agent_sync-0.2.1/PKG-INFO +417 -0
- claude_agent_sync-0.2.1/README.md +381 -0
- claude_agent_sync-0.2.1/pyproject.toml +99 -0
- claude_agent_sync-0.2.1/setup.cfg +4 -0
- claude_agent_sync-0.2.1/src/agent_sync/__init__.py +13 -0
- claude_agent_sync-0.2.1/src/agent_sync/__main__.py +8 -0
- claude_agent_sync-0.2.1/src/agent_sync/cli.py +520 -0
- claude_agent_sync-0.2.1/src/agent_sync/console.py +454 -0
- claude_agent_sync-0.2.1/src/agent_sync/db.py +401 -0
- claude_agent_sync-0.2.1/src/agent_sync/errors.py +51 -0
- claude_agent_sync-0.2.1/src/agent_sync/git_utils.py +59 -0
- claude_agent_sync-0.2.1/src/agent_sync/hooks.py +309 -0
- claude_agent_sync-0.2.1/src/agent_sync/locks.py +158 -0
- claude_agent_sync-0.2.1/src/agent_sync/messages.py +203 -0
- claude_agent_sync-0.2.1/src/agent_sync/models.py +172 -0
- claude_agent_sync-0.2.1/src/agent_sync/paths.py +105 -0
- claude_agent_sync-0.2.1/src/agent_sync/render.py +280 -0
- claude_agent_sync-0.2.1/src/agent_sync/tasks.py +229 -0
- claude_agent_sync-0.2.1/src/claude_agent_sync.egg-info/PKG-INFO +417 -0
- claude_agent_sync-0.2.1/src/claude_agent_sync.egg-info/SOURCES.txt +35 -0
- claude_agent_sync-0.2.1/src/claude_agent_sync.egg-info/dependency_links.txt +1 -0
- claude_agent_sync-0.2.1/src/claude_agent_sync.egg-info/entry_points.txt +2 -0
- claude_agent_sync-0.2.1/src/claude_agent_sync.egg-info/requires.txt +8 -0
- claude_agent_sync-0.2.1/src/claude_agent_sync.egg-info/top_level.txt +1 -0
- claude_agent_sync-0.2.1/tests/test_benchmark_comparison.py +78 -0
- claude_agent_sync-0.2.1/tests/test_cli_status.py +56 -0
- claude_agent_sync-0.2.1/tests/test_console.py +178 -0
- claude_agent_sync-0.2.1/tests/test_db.py +79 -0
- claude_agent_sync-0.2.1/tests/test_hooks_post_edit.py +29 -0
- claude_agent_sync-0.2.1/tests/test_hooks_pre_edit.py +60 -0
- claude_agent_sync-0.2.1/tests/test_hooks_stop.py +76 -0
- claude_agent_sync-0.2.1/tests/test_hooks_user_prompt_submit.py +67 -0
- claude_agent_sync-0.2.1/tests/test_locks.py +85 -0
- claude_agent_sync-0.2.1/tests/test_messages.py +146 -0
- claude_agent_sync-0.2.1/tests/test_render.py +100 -0
- claude_agent_sync-0.2.1/tests/test_tasks.py +136 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 agent-sync contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claude-agent-sync
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Coordinate multiple AI coding-agent sessions in one repo: file locks, task board, presence, and messaging over shared SQLite. Claude Code skill + hooks included.
|
|
5
|
+
Author: agent-sync contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/denfry/agent-sync
|
|
8
|
+
Project-URL: Repository, https://github.com/denfry/agent-sync
|
|
9
|
+
Project-URL: Documentation, https://github.com/denfry/agent-sync#readme
|
|
10
|
+
Project-URL: Issues, https://github.com/denfry/agent-sync/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/denfry/agent-sync/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: claude,claude-code,ai-agents,agents,multi-agent,agentic,coordination,file-locking,concurrency,cli,sqlite,hooks,cursor,codex,developer-tools
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
24
|
+
Classifier: Topic :: Software Development :: Version Control
|
|
25
|
+
Classifier: Topic :: Utilities
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Provides-Extra: tui
|
|
30
|
+
Requires-Dist: prompt_toolkit>=3.0; extra == "tui"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.8; extra == "dev"
|
|
34
|
+
Requires-Dist: prompt_toolkit>=3.0; extra == "dev"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# agent-sync
|
|
38
|
+
|
|
39
|
+
[](https://github.com/denfry/agent-sync/actions/workflows/release.yml)
|
|
40
|
+
[](https://github.com/denfry/agent-sync/releases)
|
|
41
|
+
[](LICENSE)
|
|
42
|
+
[](pyproject.toml)
|
|
43
|
+
|
|
44
|
+
**Coordinate multiple AI coding-agent sessions running in the same repository.**
|
|
45
|
+
|
|
46
|
+
`agent-sync` gives independent CLI coding-agent sessions — Claude Code, and any
|
|
47
|
+
other agent or shell — a shared, local coordination layer so they can *see each
|
|
48
|
+
other, claim tasks, lock files, exchange messages, log activity, and avoid edit
|
|
49
|
+
conflicts* — with no server and no network access. It ships as a small
|
|
50
|
+
stdlib-only Python CLI (`agent-sync`), a Claude Code **skill** (`/agent-sync`),
|
|
51
|
+
and a set of Claude Code **hooks** — and the agent-agnostic CLI works from any
|
|
52
|
+
tool.
|
|
53
|
+
|
|
54
|
+
> **Works with:** Claude Code (skill + hooks today) · any other CLI agent or
|
|
55
|
+
> shell via the `agent-sync` command · Python 3.10+ · macOS · Linux · Windows.
|
|
56
|
+
|
|
57
|
+
## Contents
|
|
58
|
+
|
|
59
|
+
[Problem](#the-problem) · [Solution](#the-solution) · [Features](#features) ·
|
|
60
|
+
[Install](#install) · [Quickstart](#quickstart) · [Example](#example-three-agents) ·
|
|
61
|
+
[Commands](#commands) · [Hooks](#hook-setup) · [Storage](#data-storage) ·
|
|
62
|
+
[Safety](#safety-model) · [Limitations](#limitations) · [Roadmap](#roadmap) ·
|
|
63
|
+
[Comparison](#comparison) · [FAQ](#faq) · [Contributing](#contributing)
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## The problem
|
|
68
|
+
|
|
69
|
+
You open three Claude Code sessions on the same project — one on the frontend,
|
|
70
|
+
one on the backend, one writing tests. Each is its own process with its own
|
|
71
|
+
context. They have **no idea the others exist**. So:
|
|
72
|
+
|
|
73
|
+
- Two sessions edit the same file and silently clobber each other.
|
|
74
|
+
- One renames an API while another is still coding against the old shape.
|
|
75
|
+
- Nobody knows who is doing what, or what was already decided.
|
|
76
|
+
|
|
77
|
+
`CLAUDE.md` is static. A human relaying messages between windows doesn't scale.
|
|
78
|
+
There is no shared operational state.
|
|
79
|
+
|
|
80
|
+
## The solution
|
|
81
|
+
|
|
82
|
+
A single SQLite database inside your repo (`.claude/coordination/state.sqlite`)
|
|
83
|
+
acts as shared memory for every session, exposed through:
|
|
84
|
+
|
|
85
|
+
1. **A CLI** — `agent-sync` — for agents (and humans) to read and update state.
|
|
86
|
+
2. **A skill** — `/agent-sync` — that teaches Claude *when and how* to coordinate.
|
|
87
|
+
3. **Hooks** — a `PreToolUse` hook that **blocks an edit to a file another active
|
|
88
|
+
agent has locked** (exit code 2), `UserPromptSubmit`/`Stop` hooks that **push
|
|
89
|
+
messages from other agents into this session's context** (so they can't be
|
|
90
|
+
ignored), plus `SessionStart`/`PostToolUse`/`SessionEnd` hooks for presence,
|
|
91
|
+
activity logging, and cleanup.
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
┌────────────┐ ┌────────────┐ ┌────────────┐
|
|
95
|
+
│ frontend │ │ backend │ │ tests │ Claude Code sessions
|
|
96
|
+
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘
|
|
97
|
+
│ agent-sync │ agent-sync │ agent-sync (CLI + hooks)
|
|
98
|
+
└────────────────┼────────────────┘
|
|
99
|
+
▼
|
|
100
|
+
.claude/coordination/state.sqlite (shared state, no server)
|
|
101
|
+
agents · tasks · locks · messages · decisions · activity
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Features
|
|
105
|
+
|
|
106
|
+
- 🔒 **File locks with TTL** — claim a file before editing; locks auto-expire
|
|
107
|
+
after 60 minutes so a crashed session never blocks others forever.
|
|
108
|
+
- ✅ **Task board** — create / claim / complete / block tasks; a task owned by an
|
|
109
|
+
active agent can't be stolen.
|
|
110
|
+
- 👥 **Presence** — agents register and heartbeat; stale and offline agents decay
|
|
111
|
+
automatically and stop holding locks.
|
|
112
|
+
- ✉️ **Messaging that reaches busy agents** — send to an agent, a name, a role,
|
|
113
|
+
or `all`. With the hooks installed, messages are **pushed into other sessions'
|
|
114
|
+
context**: injected on every prompt (`UserPromptSubmit`), and a message aimed
|
|
115
|
+
at a *specific* agent even blocks that agent's turn-end (`Stop`) until it reacts
|
|
116
|
+
— so a session deep in a task can't silently ignore it. Still a polled inbox
|
|
117
|
+
(`agent-sync inbox`) for everything else.
|
|
118
|
+
- 🧠 **Decisions & activity log** — record architecture decisions and an audit
|
|
119
|
+
trail of edits.
|
|
120
|
+
- 🪝 **Hooks that actually enforce** — `PreToolUse` fails *closed* on a real lock
|
|
121
|
+
conflict; everything else fails *open* so it never gets in your way.
|
|
122
|
+
- 📺 **Live operator console** — `agent-sync console` streams who's doing what,
|
|
123
|
+
how agents talk to each other, and lets a human steer in real time (send
|
|
124
|
+
messages/directives, lock files to stop edits, drive the task board).
|
|
125
|
+
- 🧰 **Zero runtime dependencies for the core** — the CLI and hooks are pure
|
|
126
|
+
Python standard library + SQLite. Only the live console needs an extra
|
|
127
|
+
(`pip install "claude-agent-sync[tui]"`).
|
|
128
|
+
|
|
129
|
+
## Install
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Once released to PyPI:
|
|
133
|
+
pip install claude-agent-sync
|
|
134
|
+
# Until then, install from source:
|
|
135
|
+
pip install "git+https://github.com/denfry/agent-sync"
|
|
136
|
+
# …or from a clone of this repo:
|
|
137
|
+
pip install -e .
|
|
138
|
+
|
|
139
|
+
# Optional: the live operator console (`agent-sync console`) needs the TUI extra:
|
|
140
|
+
pip install "claude-agent-sync[tui]" # or: pip install -e ".[tui]"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Then install the skill and hooks into a repository:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# from a clone of this project, run inside your target repo:
|
|
147
|
+
python /path/to/agent-sync/skills/agent-sync/scripts/install.py --write-settings
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Or, working straight from a checkout without installing the package:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python scripts/install-local.py --write-settings
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This copies the skill into `<repo>/.claude/skills/agent-sync/`, creates
|
|
157
|
+
`<repo>/.claude/coordination/`, and (with `--write-settings`) merges the hooks
|
|
158
|
+
into `<repo>/.claude/settings.json`.
|
|
159
|
+
|
|
160
|
+
## Quickstart
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
agent-sync init # create the database (optional; auto-runs)
|
|
164
|
+
agent-sync register --name frontend --role "React UI"
|
|
165
|
+
agent-sync create-task "Update login UI" --file src/login.tsx
|
|
166
|
+
agent-sync claim-task "Update login UI"
|
|
167
|
+
agent-sync lock src/login.tsx --reason "editing login page"
|
|
168
|
+
agent-sync status # full view
|
|
169
|
+
agent-sync status --compact # terse Markdown for Claude's context
|
|
170
|
+
agent-sync send --to all --message "Login UI task started"
|
|
171
|
+
agent-sync decision "Use SQLite for coordination state"
|
|
172
|
+
agent-sync complete-task "Update login UI"
|
|
173
|
+
agent-sync unlock src/login.tsx
|
|
174
|
+
agent-sync gc # drop expired locks, re-status agents
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Example: three agents
|
|
178
|
+
|
|
179
|
+
In real use each agent is a separate Claude Code window. To simulate them in one
|
|
180
|
+
shell, set `AGENT_SYNC_ID` per command (in Claude Code, identity is derived
|
|
181
|
+
automatically from the session).
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# everyone registers
|
|
185
|
+
AGENT_SYNC_ID=frontend agent-sync register --name frontend --role "React UI"
|
|
186
|
+
AGENT_SYNC_ID=backend agent-sync register --name backend --role "API + DB"
|
|
187
|
+
AGENT_SYNC_ID=tests agent-sync register --name tests --role "pytest + e2e"
|
|
188
|
+
|
|
189
|
+
# backend claims a task and locks its files
|
|
190
|
+
AGENT_SYNC_ID=backend agent-sync create-task "Add /login endpoint" --file src/api/auth.py
|
|
191
|
+
AGENT_SYNC_ID=backend agent-sync claim-task "Add /login endpoint"
|
|
192
|
+
AGENT_SYNC_ID=backend agent-sync lock src/api/auth.py --reason "writing /login"
|
|
193
|
+
|
|
194
|
+
# tests tries to edit the locked file -> the PreToolUse hook blocks it (exit 2)
|
|
195
|
+
printf '{"tool_name":"Edit","tool_input":{"file_path":"src/api/auth.py"}}' \
|
|
196
|
+
| AGENT_SYNC_ID=tests agent-sync hook pre-tool-use
|
|
197
|
+
# [agent-sync] BLOCKED: src/api/auth.py is locked by backend ...
|
|
198
|
+
|
|
199
|
+
# backend announces the contract and finishes
|
|
200
|
+
AGENT_SYNC_ID=backend agent-sync send --to all --message "/login returns {token,user} in body"
|
|
201
|
+
AGENT_SYNC_ID=backend agent-sync complete-task "Add /login endpoint"
|
|
202
|
+
AGENT_SYNC_ID=backend agent-sync unlock src/api/auth.py
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
See [`examples/workflow.md`](examples/workflow.md) for the full narrative.
|
|
206
|
+
|
|
207
|
+
## Live console
|
|
208
|
+
|
|
209
|
+
Besides the agent sessions, a human can open a live, interactive view of the
|
|
210
|
+
whole coordination layer and steer it as it happens:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
pip install "claude-agent-sync[tui]" # one-time: the console needs this extra
|
|
214
|
+
agent-sync console
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
agent-sync console — live coordination view. Type 'help', 'quit' to leave.
|
|
219
|
+
agents (2 active / 2 total):
|
|
220
|
+
backend [active] API + DB
|
|
221
|
+
tests [active] pytest + e2e
|
|
222
|
+
locks (1):
|
|
223
|
+
src/api/auth.py → backend — writing /login
|
|
224
|
+
------------------------------------------------------------
|
|
225
|
+
12:01:03 act backend Edit src/api/auth.py
|
|
226
|
+
12:01:04 msg backend →all: /login returns {token,user}
|
|
227
|
+
12:01:06 who frontend joined [active]
|
|
228
|
+
12:01:09 lock backend released src/api/auth.py
|
|
229
|
+
operator> directive all "freeze feature work — hotfix on main"
|
|
230
|
+
directive -> 3 active agent(s)
|
|
231
|
+
operator> lock src/api/auth.py refactor incoming
|
|
232
|
+
locked src/api/auth.py (until 2026-06-14T13:01:00+00:00)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
The feed tails new activity, inter-agent messages, presence changes, and lock
|
|
236
|
+
events; the `operator>` prompt lets you act as a first-class participant:
|
|
237
|
+
|
|
238
|
+
| Operator command | Effect |
|
|
239
|
+
| --- | --- |
|
|
240
|
+
| `send <to> <msg>` | Message an id/name/role/`all`. A **directed** message is pushed forcefully (the `Stop` hook makes that agent react before it can end its turn). |
|
|
241
|
+
| `directive <to> <msg>` | Like `send`, but `directive all` fans out a *directed* copy to every active agent, so each is forced to react this turn. |
|
|
242
|
+
| `lock <path> [reason]` | Lock a file — the `PreToolUse` hook blocks other agents' edits to it **immediately**, on their next attempt. The one truly real-time lever. |
|
|
243
|
+
| `unlock <path>` | Release a lock (the operator can break anyone's). |
|
|
244
|
+
| `task new\|done\|block` | Drive the task board (`task block <ref> :: <reason>`). |
|
|
245
|
+
| `decision <text>` | Record a shared decision. |
|
|
246
|
+
| `status` · `msgs` | Print a snapshot / recent messages. `help` lists everything. |
|
|
247
|
+
|
|
248
|
+
The console acts as a reserved `operator` identity: it registers as active so
|
|
249
|
+
its locks are enforced and its messages reach agents like any other, but it is
|
|
250
|
+
kept out of the "active agents" count so it never looks like a code-editing peer.
|
|
251
|
+
When you quit, the operator goes idle and its locks stop holding the repo.
|
|
252
|
+
Influence reaches a *running* agent at its next turn (messages) or on its next
|
|
253
|
+
edit (locks); there is no mid-tool-call interrupt — see [Limitations](#limitations).
|
|
254
|
+
|
|
255
|
+
## Commands
|
|
256
|
+
|
|
257
|
+
| Command | What it does |
|
|
258
|
+
| --- | --- |
|
|
259
|
+
| `agent-sync init` | Create the database and tables (auto-runs on any command). |
|
|
260
|
+
| `agent-sync register --name N [--role R]` | Register / update the current agent. |
|
|
261
|
+
| `agent-sync heartbeat` | Mark the current agent active now. |
|
|
262
|
+
| `agent-sync status [--compact]` | Show agents, tasks, locks, messages, activity. |
|
|
263
|
+
| `agent-sync tasks` | List all tasks. |
|
|
264
|
+
| `agent-sync create-task "T" [--description D] [--file P ...] [--priority N]` | Create a task. |
|
|
265
|
+
| `agent-sync claim-task T` | Claim a task by id or title. |
|
|
266
|
+
| `agent-sync claim-next` | Auto-claim the next available task (highest priority first; reclaims tasks abandoned by crashed sessions). |
|
|
267
|
+
| `agent-sync complete-task T` | Mark a task done. |
|
|
268
|
+
| `agent-sync block-task T --reason R` | Mark a task blocked. |
|
|
269
|
+
| `agent-sync lock FILE [--reason R] [--ttl MIN]` | Lock a file (default TTL 60 min). |
|
|
270
|
+
| `agent-sync unlock FILE [--force]` | Release a lock (owner only, unless `--force`). |
|
|
271
|
+
| `agent-sync locks [--all]` | List live locks (`--all` includes expired). |
|
|
272
|
+
| `agent-sync send --to R --message M` | Send to an id, name, role, or `all`. |
|
|
273
|
+
| `agent-sync inbox [--all]` | Show unread (or all) messages addressed to you. |
|
|
274
|
+
| `agent-sync read-message ID` | Show a message and mark it read. |
|
|
275
|
+
| `agent-sync decision "..."` | Record a shared decision. |
|
|
276
|
+
| `agent-sync log --type T --message M [--file P]` | Append an activity entry. |
|
|
277
|
+
| `agent-sync gc` | Re-status stale agents and drop expired locks. |
|
|
278
|
+
| `agent-sync console [--interval S] [--name N]` | Live operator console: stream activity and steer agents (needs the `tui` extra). |
|
|
279
|
+
| `agent-sync hook {session-start,user-prompt-submit,pre-tool-use,post-tool-use,stop,session-end}` | Hook entry points (read JSON from stdin). |
|
|
280
|
+
|
|
281
|
+
Run `agent-sync --help` or `agent-sync <command> --help` for details.
|
|
282
|
+
|
|
283
|
+
## Hook setup
|
|
284
|
+
|
|
285
|
+
Merge the `hooks` block from [`examples/settings.json`](examples/settings.json)
|
|
286
|
+
into your repo's `.claude/settings.json` (or run an installer with
|
|
287
|
+
`--write-settings`):
|
|
288
|
+
|
|
289
|
+
| Event | Matcher | Behaviour |
|
|
290
|
+
| --- | --- | --- |
|
|
291
|
+
| `SessionStart` | (all) | Register/heartbeat the agent; inject compact status into context. |
|
|
292
|
+
| `UserPromptSubmit` | (all) | Push any undelivered messages (directed + broadcast) into context for this turn. |
|
|
293
|
+
| `PreToolUse` | `Edit\|Write\|MultiEdit` | **Block (exit 2)** if the target file is locked by another active agent. |
|
|
294
|
+
| `PostToolUse` | `Edit\|Write\|MultiEdit` | Log the successful edit to the activity feed. |
|
|
295
|
+
| `Stop` | (all) | **Block turn-end** (`decision: block`) while a message addressed to *this* agent is still undelivered, so it reacts before stopping. |
|
|
296
|
+
| `SessionEnd` | (all) | Mark the agent idle (locks are left to expire by default). |
|
|
297
|
+
|
|
298
|
+
If `agent-sync` isn't on `PATH`, use
|
|
299
|
+
[`examples/settings.skill-path.json`](examples/settings.skill-path.json), which
|
|
300
|
+
calls the bundled launcher: `python .claude/skills/agent-sync/scripts/agent-sync ...`.
|
|
301
|
+
|
|
302
|
+
## Data storage
|
|
303
|
+
|
|
304
|
+
All state lives in **`.claude/coordination/state.sqlite`** inside the target
|
|
305
|
+
repo, created automatically on first use. Tables:
|
|
306
|
+
|
|
307
|
+
- `agents` — id, name, role, session, cwd, status, current task, timestamps.
|
|
308
|
+
- `tasks` + `task_files` — the task board and the files each task touches.
|
|
309
|
+
- `locks` — one row per locked path, with owner and `expires_at` (TTL).
|
|
310
|
+
- `messages` — sender, recipient (id/name/role/`all`), body, read state.
|
|
311
|
+
- `message_deliveries` — per-(message, agent) record of which messages have been
|
|
312
|
+
pushed into which agent's context (so a broadcast reaches each agent once).
|
|
313
|
+
- `decisions` — recorded decisions.
|
|
314
|
+
- `activity` — an append-only audit log of edits and events.
|
|
315
|
+
|
|
316
|
+
SQLite runs in WAL mode with a busy timeout, and every write uses a short
|
|
317
|
+
`BEGIN IMMEDIATE` transaction, so several Claude Code processes can hit the same
|
|
318
|
+
database concurrently. Add `.claude/coordination/` to your `.gitignore`
|
|
319
|
+
(this project's `.gitignore` already does).
|
|
320
|
+
|
|
321
|
+
## Safety model
|
|
322
|
+
|
|
323
|
+
- **Local-only.** No network calls, no telemetry, no external service. State is a
|
|
324
|
+
file in your repo.
|
|
325
|
+
- **Fail open, except for locks.** Hooks tolerate malformed/empty input and never
|
|
326
|
+
crash your session — the *one* deliberate exception is `PreToolUse`, which fails
|
|
327
|
+
**closed** (exit 2) on a genuine lock conflict, which is exactly when you want
|
|
328
|
+
the edit blocked.
|
|
329
|
+
- **TTLs prevent deadlock.** Locks expire (60 min default) and locks held by
|
|
330
|
+
stale/offline agents are ignored, so a crashed session can't wedge the repo.
|
|
331
|
+
- **Owner-only unlock.** Releasing someone else's lock requires `--force` (the
|
|
332
|
+
operator console always uses force — the human is in charge).
|
|
333
|
+
- **Untrusted text stays data.** State injected into an agent's LLM context is
|
|
334
|
+
wrapped in an `<agent-sync-state trust="untrusted">` frame; the live console
|
|
335
|
+
additionally strips control/ANSI bytes from agent-authored values before
|
|
336
|
+
printing them, so a hostile name or message can't hijack your terminal.
|
|
337
|
+
- **No secrets.** Tasks, messages, and decisions are plaintext shared state — do
|
|
338
|
+
not put tokens, passwords, or keys in them. See [SECURITY.md](SECURITY.md).
|
|
339
|
+
|
|
340
|
+
## Limitations
|
|
341
|
+
|
|
342
|
+
- Coordination is **advisory**. The `PreToolUse` hook enforces locks for
|
|
343
|
+
`Edit`/`Write`/`MultiEdit`, but a shell command (`sed`, `>`) can still bypass
|
|
344
|
+
it. Locks are a cooperation tool, not OS-level file locking.
|
|
345
|
+
- Identity is auto-detected per Claude Code session: it's `AGENT_SYNC_ID` if set,
|
|
346
|
+
else a hash of the session id (from a hook payload or the
|
|
347
|
+
`CLAUDE_CODE_SESSION_ID` env var Claude Code exports into every shell), else a
|
|
348
|
+
per-repo local id. Because hooks and the skill both key off the same session
|
|
349
|
+
id, they resolve to the same agent — so you never get blocked from editing a
|
|
350
|
+
file *you* locked. Outside Claude Code with none of those set, all sessions in
|
|
351
|
+
a repo share the local id and look like one agent.
|
|
352
|
+
- Single-repo scope. There's no cross-repo or cross-machine coordination.
|
|
353
|
+
- Messaging is **pushed** by the `UserPromptSubmit`/`Stop` hooks (so a message
|
|
354
|
+
lands in another agent's context at its next prompt or turn-end), but it is not
|
|
355
|
+
a real-time bus: there's no mid-tool-call interrupt, and locks/tasks/presence
|
|
356
|
+
are still observed by polling `status`. Without the hooks installed (e.g. a bare
|
|
357
|
+
CLI agent), messaging falls back to a polled `inbox`.
|
|
358
|
+
|
|
359
|
+
## Roadmap
|
|
360
|
+
|
|
361
|
+
- [ ] An MCP server exposing the same state as tools/resources (no hooks needed).
|
|
362
|
+
- [ ] First-class adapters for other CLI agents (Cursor, Codex CLI, Gemini CLI).
|
|
363
|
+
- [ ] Richer presence (per-agent current file, progress %).
|
|
364
|
+
- [ ] Optional auto-release of locks on `SessionEnd`.
|
|
365
|
+
- [x] A live console for watching and steering agents — shipped as
|
|
366
|
+
[`agent-sync console`](#live-console).
|
|
367
|
+
- [ ] Lock leases with renewal and configurable policies.
|
|
368
|
+
|
|
369
|
+
## Comparison
|
|
370
|
+
|
|
371
|
+
| Approach | Shared live state? | Blocks conflicting edits? | Setup | Best for |
|
|
372
|
+
| --- | --- | --- | --- | --- |
|
|
373
|
+
| **Plain `CLAUDE.md`** | No (static text) | No | Trivial | Conventions, not coordination |
|
|
374
|
+
| **Human relays chat** | In your head | No | None | 2 windows, low traffic |
|
|
375
|
+
| **Git worktrees** | No (isolated trees) | Avoids conflicts by isolation | Medium | Big independent features |
|
|
376
|
+
| **agent-sync** | Yes (SQLite) | Yes (PreToolUse hook) | One install | Several agents, one repo |
|
|
377
|
+
| **Future MCP version** | Yes | Yes (tool-mediated) | MCP config | Same, server-mediated |
|
|
378
|
+
|
|
379
|
+
`agent-sync` composes with git worktrees: use worktrees to isolate big
|
|
380
|
+
features and `agent-sync` to lock the shared/generated files they still touch.
|
|
381
|
+
|
|
382
|
+
## FAQ
|
|
383
|
+
|
|
384
|
+
**Do I need a server or database engine?** No. It's a single SQLite file managed
|
|
385
|
+
by Python's stdlib `sqlite3`. Nothing to run.
|
|
386
|
+
|
|
387
|
+
**What if two agents start at the same time?** Writes use `BEGIN IMMEDIATE` and a
|
|
388
|
+
busy timeout, so they serialize. Claiming a task or lock is atomic; the loser
|
|
389
|
+
gets a clear conflict error.
|
|
390
|
+
|
|
391
|
+
**A session crashed and left a lock.** Locks expire after their TTL, and locks
|
|
392
|
+
owned by stale/offline agents are ignored immediately. Run `agent-sync gc` to
|
|
393
|
+
clean up now.
|
|
394
|
+
|
|
395
|
+
**Does this work with agents other than Claude Code?** Yes. The `agent-sync` CLI
|
|
396
|
+
works anywhere Python runs, so any CLI agent or shell can read and update the
|
|
397
|
+
shared state. The bundled skill and hooks are Claude Code-specific today (other
|
|
398
|
+
agents are on the [roadmap](#roadmap)), but the coordination database isn't tied
|
|
399
|
+
to any one tool.
|
|
400
|
+
|
|
401
|
+
**Will the hook block my own edits?** No — you can always edit files *you* have
|
|
402
|
+
locked. It only blocks edits to files locked by *other active* agents.
|
|
403
|
+
|
|
404
|
+
## Contributing
|
|
405
|
+
|
|
406
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, running tests, coding
|
|
407
|
+
conventions, and how to add commands and hooks. Security policy:
|
|
408
|
+
[SECURITY.md](SECURITY.md). Changes are tracked in [CHANGELOG.md](CHANGELOG.md).
|
|
409
|
+
|
|
410
|
+
## Maintainer
|
|
411
|
+
|
|
412
|
+
Built and maintained by [@denfry](https://github.com/denfry). Issues and pull
|
|
413
|
+
requests welcome — start with [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
414
|
+
|
|
415
|
+
## License
|
|
416
|
+
|
|
417
|
+
[MIT](LICENSE).
|