They write the same file and break it Nobody knows who is touching what Integration turns into chaos With only one workspace, changes Overlapping work goes unnoticed Results built separately can’t be overwrite each other until it is finished brought together at the end lockage 02
a boat’s passage through a canal lock. Boats are kept apart in the chamber, the water level is watched, and they pass one at a time. 01 They write the same file and break it → Separate the workspaces physically 02 Nobody knows who is touching what → Show ownership and changes in a ledger 03 Integration turns into chaos → Pass one at a time through a single gate Give each agent its own git worktree claim, dirty set, board. It warns, but never blocks A serial merge gate. Likely conflicts are sent back, not auto-resolved Agents never talk directly. Everything goes through one SQLite ledger. lockage 03
2 · SQLite Claims, the dirty set and the board share who owns what. It warns, Coordination layer but never blocks. LAYER 1 · git worktree Each agent gets its own workspace, so two agents cannot write the Physical isolation same file at the same time. lockage 04
same task Claims are serialized with SQLite’s Agent A claim_task(v=3) ok → v=4 Agent B claim_task(v=3) conflict BEGIN IMMEDIATE and a version CAS The later agent just gets a conflict. It is not kept waiting and can move on to another task. Two agents with the same version: only one succeeds lockage 06
meet actual changes claim_files(glob) dirty set Where you will work e.g. src/auth/** What you actually changed Overlapping someone only warns Published by publish_dirty + Also computed from git by heartbeat and others Compared, they return overlaps You overlap someone’s claims or dirty files The peer gets an overlap wake → unclaimed You changed files outside your claim Call claim_files again lockage 07
ledger kind Written by Meaning Wakes the peer? note Agents Naming yourself, notes If unread question Agents Why you are stuck, questions If unread handoff Agents / system Handovers and send-backs If unread ticket_ready Server All of a ticket’s tasks are done No pr_opened / pr_updated / pr_merged lockage-publish Records of the PR’s state No to_agent makes it directed; without it, it goes to everyone lockage A read cursor per agent tracks what is unread heartbeat reports the count; read_board reads them 08
gate 1-B · serial merge gate 1-C · immediate merge Tasks under a ticket (even just one) Minor tasks with no ticket Collected into the ticket’s integration branch With no divergence, merged into base on the spot lockage/ticket/<short-id> main needs_review lockage A 3-way pre-check finds likely conflicts and sends them back, without auto-resolving 09
long-poll wait_for_unblock(agent_id) Dependency ready A message for you An overlap Timeout A task you were waiting on is ready An unread board post to you or to everyone Another agent stepped into your area If nothing happens, it returns on time lockage 10
the exit 01 02 03 04 05 06 07 File Claim Isolate Work Merge Open PR Review open_ticket create_task claim_task assign_ worktree claim_files publish_ dirty task_done lockagepublish Check and merge the PR When every task is done, ticket_ready is raised and an agent Changes reach the mainline (the PR merge) only with runs lockage-publish to open the PR human approval lockage 11
Set Who uses it Tools core Agents (always on) 28 publisher Only on the server lockage-publish starts 6 maintenance Humans, for upkeep (enable with LOCKAGE_TOOLSETS) 3 The publisher set does cleanup such as closing tickets, so agents never see it lockage 12
and the rules Only two things to line up For Claude Code Point to the same ledger claude plugin marketplace add <path> claude plugin install lockage@lockage Everyone uses the same LOCKAGE_DB Use a unique agent_id Kiro installs it as a Power, Antigravity with agy plugin install. No clone or build needed. lockage Pick it at startup; check the board for duplicates Requires Node.js 22.5 or later, and git 13
together Nothing breaks Nothing hides It comes together worktrees keep the workspaces physically apart A SQLite ledger shows who owns what. It warns, but never blocks A serial merge gate integrates; a human decides on the PR merge github.com/tacck/lockage
1 Naming and liveness 2 Dividing the work board · lease tasks · deps · tickets unread note 4 Visible changes claims · dirty set task_ready 5 The merge gate overlap 7 Waiting and waking wait_for_unblock 3 Separate workspaces receives merge queue worktree ledger no wake 6 Messages (board) unread handoff board · cursor 8 Pausing and handoff 9 Opening the PR tasks · board board · publish lock unread handoff unread post no wake What wakes a peer: wakes (task_ready, overlap) and unread board posts. Only the orange ones do. lockage 15
agent_id board read_board Check names (kind: note) Agent A list_claims Check owners too Just joining Almost any tool call Extends the lease 15 min lockage Wakes: unread note Unread note Wakes a waiting B kind:"note" records the name Broadcast unread counts from here claims Agent B Who owns which area Already at work tasks · 15-min lease Not extended by post_board, task_done blocked tasks stay put Lease lapses → open Anyone can claim it ━━ Information flow ━━ Wakes the peer (wake / unread) 16
and deps Wakes: task_ready tasks list_tasks(ready_only) Only what can start now Holds status and version claim_task(version) The loser gets conflict Agent A add_dependency Add a dependency later dependency DAG Agent B add_dependency rejects cycles Comes to take work Makes the plan link_task_to_ticket Group into a ticket tickets Groups filed with open_ticket wake queue task_ready Wakes downstream owners Upstream done, deps all clear lockage ━━ Information flow ━━ Wakes the peer (wake / unread) 17
own space worktree_path / branch Work only in here No wake worktree ledger Who got which worktree list_worktrees lists them assign_worktree B asks for its own too Its own path, branch Never overlaps A git worktree add Agent A Works in its own space git repository Agent B Works in its own space A folder and a branch per agent release_worktree Release when done cleanup reclaim_orphan_worktrees release_ticket_worktrees lockage ━━ Information flow ━━ Wakes the peer (wake / unread) 18
area Wakes: overlap list_claims / list_dirty Who touches what claims Areas you will touch (glob) Warns on overlap Never blocks Agent A About to change files publish_dirty Publish changed files overlaps / unclaimed Overlaps and strays claim_files Claimed the area first dirty set Agent B Files actually changed Recomputed from git by heartbeat Owned the area first Overlap found wake queue overlap Wakes the other owner To: the overlapping peer lockage ━━ Information flow ━━ Wakes the peer (wake / unread) 19
task_done Hand the work to the gate needs_review in result Yours returns only here merge gate 3-way pre-check, one at a time No conflict → integration / base Agent B Others’ items Agent A Called task_done Unread handoff Wakes B on its next wait board A handoff from system (to: B) Owns another task sent back in the same run Posts them all process_merge_queue Maintenance: posts every send-back lockage ━━ Information flow ━━ Wakes the peer (wake / unread) 20
Wakes: unread post Unread post B wakes on its next wait board kind: note / handoff / question ticket_ready / pr_* Agent A Sender resolve_question Close a question to_agent set → directed no to_agent → everyone else heartbeat Reports unread_count Agent B A read cursor per agent Unread for the recipient read_board(unread_only) Read unread, mark read Recipient ticket_ready server / lockage-publish Records, never counted as unread lockage ━━ Information flow ━━ Wakes the peer (wake / unread) 21
task finishes tasks post_board Unread for the peer board Other agents Cause events The side that is woken Deps clear, overlaps A wake is queued A task you wait on is ready Unread posts to you or to all wake queue task_ready, overlap timeout 60 seconds by default lockage ① Ready All dependencies clear ② Unread board post Returned posts are read Agent B ③ A wake arrives task_ready, overlap Waiting in wait_for_unblock Checks the DB every 500 ms ④ Timeout Returns even if idle ━━ Information flow ━━ Wakes the peer (wake / unread) 22
you work is lost B’s state Working (not waiting) heartbeat reports the count Board post Counts from lockage board_cursors Waiting in wait_for_unblock It stays unread; the next wait wakes at once Returned posts are read: no double wake note (to B) Posts to you Posts to everyone Counted from the start (seq 0) Even a handoff sent before launch Counted from your first call as yourself Old history does not flood in ━━ Information flow ━━ Wakes the peer (wake / unread) 23
the reason first board Wakes: unread handoff Unread handoff Arrives even pre-launch question and handoff posts block_task Pause, keep ownership Agent A The stuck owner resume_task The same A resumes tasks Agent B in_progress ⇄ blocked Takes over the assignment owner, worktree, claims, dirty moved in one CAS transaction lockage list_tasks(blocked) Find orphans by silence handoff_task Moves it all at once ━━ Information flow ━━ Wakes the peer (wake / unread) 24
PRs The last task_done ticket_ready is raised No wake board ticket_ready, pr_opened pr_updated, pr_merged Agent A Marks the last task done, then runs lockagepublish publish lock Per ticket, TTL 300 seconds ticket / branch close_ticket_on_merge clear_integration_branch release_ticket_claims lockage read_board Picks up ticket_ready post_board pr_opened, pr_merged … acquire_publish_lock No double processing lockagepublish release_publish_lock Release when finished A one-shot command that opens PRs Cleanup after merge Close the ticket ━━ Information flow ━━ Wakes the peer (wake / unread) 25