An enforced file-lock for parallel coding agents. Cross-CLI. · 中文 · Getting Started guide
Two agent windows on the same repo: the moment one is editing a file, the other's edit to it is blocked until it's released. (single-terminal walkthrough)
When several coding-agent windows (Claude Code, Cursor, Codex, Aider, …) edit the same repo at once, two of them touch the same file and clobber each other. callcall makes that mechanically impossible, with no discipline required:
- auto-guard — the moment an agent edits a file, callcall holds it; a second agent's edit to that file is blocked until the first is done. Nobody has to remember to register anything.
claim/check— explicit sticky locks, and a scriptablecheck <path>primitive so any CLI (or a git hook) can gate its own edits.msg/inbox— a cross-CLI back-channel to coordinate when blocked.
Zero dependencies, just python3. Plain files under .callcall/.
If you already keep a shared AGENTS.md / board / PRD that agents update by
convention — keep it. That's your task tracker and shared memory, and it's
better at rich context than callcall. But a convention only works if every agent
remembers to read and update it; the moment one forgets, two edits collide.
callcall is the enforcement layer underneath that convention: it doesn't track
tasks, it just guarantees two agents can't write the same file at the same time —
and it does it across different CLIs, where a Claude-Code-only "board + native
messages" setup stops working. Use both.
git clone https://github.com/william19307/callcall.git
cd your-project
/path/to/callcall/callcall init --claude # set up this project (+ Claude Code hooks)Or install it globally so callcall works in any repo:
/path/to/callcall/install.sh # symlinks `callcall` onto your PATHWith --claude, that's it — the guard is automatic. Open two Claude Code windows
and try to edit the same file from both; the second is blocked.
On Claude Code with hooks installed you don't need any of these — editing is
guarded automatically. They're for other CLIs, scripts, and explicit locks. Each
window uses a short id (--id auth, or export CALLCALL_ID=auth).
callcall status # which files are held + who's active
callcall check src/auth/login.ts # safe for me to edit? (exit 3 if taken)
callcall claim --id auth "src/auth/**" # explicit sticky lock over a glob
callcall msg --id auth ui "grabbing auth for ~20 min" # coordinate
callcall inbox --id ui # read messages
callcall release --id auth # drop your locksWrap a non-Claude CLI's edits (or a pre-commit hook) around callcall check --id <you> --hold <path>: it exits non-zero when another agent owns the file, and
holds it for you when it's free — the same guard the Claude Code hook applies.
callcall init --claude adds three hooks to .claude/settings.json:
| Hook | What it does |
|---|---|
| SessionStart | auto-registers the window and injects which files are currently held, so it opens knowing what not to touch |
| PreToolUse (Edit/Write) | editing a free file auto-holds it; editing a file another active agent holds is blocked with a reason (never blocks the holder itself) |
| SessionEnd | removes the window and releases everything it held |
Other CLIs don't get hooks, but they follow the same board via the instruction
snippet init drops into your rules file — so a mixed Claude-Code-plus-Cursor
setup still coordinates.
For CLIs without hooks, paste into the agent's rules file (.cursorrules, …) —
init does this for you:
Other agent windows may be editing this repo in parallel. Before editing a file, run
callcall check --id <you> --hold <path>; if it exits non-zero the file is taken —callcall msg --id <you> <owner> "..."to coordinate, or wait. Read replies withcallcall inbox --id <you>.callcall statusshows which files are held.
All state lives in <project>/.callcall/state.json — plain JSON any tool or human
can read. Writes go through a file lock (fcntl.flock) with atomic replace, so
concurrent windows never corrupt it. A file is "held" either by an explicit
claim (sticky until released) or by a recent auto-edit (for CALLCALL_EDIT_TTL
seconds, default 1800); a held file is only enforced while its owner is still
active (CALLCALL_STALE seconds, default 600). File keys are realpath-normalized
so every agent identifies the same file identically. .callcall/ is gitignored.
Running each agent in its own git worktree is a great way to isolate the
filesystem — no two agents overwrite the same working-tree file. But worktrees
don't prevent merge conflicts (two branches editing the same file), don't
communicate interface changes (agent A changes a function signature agent B
depends on), and don't stop duplicated work or contention over shared
resources (the same dev database, port, .env, migrations, API quota). callcall
covers exactly those.
All worktrees of a repo automatically share one board: callcall anchors it at
the repo's main worktree (via git rev-parse --git-common-dir), so agents in
different worktrees still see each other, claim across branches, and message. Run
callcall init --claude once per worktree to get hooks there; the board is shared
regardless. To point unrelated checkouts at one board, set CALLCALL_HOME=/shared/dir.
./tests/test_callcall.sh # end-to-end tests, no dependenciesMIT licensed. Contributions welcome.
给并行的 AI coding agent 加一把"强制文件锁",跨 CLI。
同一个仓库里开多个 agent 窗口(Claude Code、Cursor、Codex、Aider……)并行改代码时, 两个 agent 会同时改同一个文件、互相覆盖。callcall 让这件事机械上不可能发生,且不靠自觉:
- 自动上锁——一个 agent 一开始编辑某文件,callcall 就把它锁住;另一个 agent 想改同一 文件会被直接拦下,直到前者结束。谁都不用记得去登记。
claim/check——显式的粘性锁,以及一个可脚本化的check <路径>原语,让任意 CLI(或 git hook)也能在改文件前自查。msg/inbox——被拦下时用来沟通的跨 CLI 通道。
零依赖,只要 python3,状态就是 .callcall/ 下的纯文本。
如果你已经有一个大家按约定更新的 AGENTS.md / 看板 / PRD——留着它,那是你的任务
追踪和共享记忆,论上下文丰富度它比 callcall 强。但约定只有在每个 agent 都记得读和写时
才有效,一旦有人忘了,就撞车。callcall 是压在这套约定下面的强制层:它不管任务,只
保证两个 agent 不会同时写同一个文件——而且跨不同 CLI 都管用,这正是"看板 + 原生消息"
那套(只在全 Claude Code 时才成立)失效的地方。两者一起用。
cd 你的项目
/路径/callcall/callcall init --claude # 初始化(接入 Claude Code hooks,之后强制自动生效)
# 或全局安装: /路径/callcall/install.sh装好 --claude 后就不用管了——开两个 Claude Code 窗口去改同一个文件,第二个会被拦下。
callcall status # 哪些文件被占、谁在线
callcall check src/auth/login.ts # 我能改这个文件吗?(被占则退出码 3)
callcall claim --id auth "src/auth/**" # 对一批文件上粘性锁
callcall msg --id auth ui "auth 我占 20 分钟" ; callcall inbox --id ui
callcall release --id authMIT 协议,欢迎贡献。
