Table of contents
- See it in one command
- The problem Overlap solves
- How Overlap works
- Architecture
- Engineering decisions — the hard problems
- What's real vs pending — the honesty table
- Tests
- Run it locally
- Configuration
- Deploy
- Project layout
- Tech stack
- Roadmap
- License
▶ See it in one command
git clone https://github.com/subheeksh5599/overlap.git
cd overlap
npm install && npm run build && npm test
Then, with an AO daemon running, point the radar at it:
$ npm run cli -- status
=== Overlap ===
Daemon: http://127.0.0.1:3001
Projects: overlap
Active sessions with worktrees: 2
--- engine-cli (overlap-17) ---
branch: ao/overlap-17/root
files: packages/overlap-core/src/cli.ts
--- dash-json (overlap-18) ---
branch: ao/overlap-18/root
files: packages/overlap-core/src/cli.ts
Overlap alerts: 1
[HIGH] SAME FILE: packages/overlap-core/src/cli.ts (sessions: overlap-17, overlap-18)
Two parallel agents edited the same file — the radar caught it live during the build, the reviewer session confirmed it, and the merge followed the advised order.
The problem Overlap solves
Running agents in parallel is the point of AO — each session gets an isolated git worktree. But parallelism has a coordination cost:
- Two sessions touch the same file — the second PR arrives with a conflict you have to untangle by hand
- No visibility into who is editing what — you find out at merge time, not before
- Merge order matters — merging the wrong PR first turns a clean sequence into a conflict cascade
- No post-mortem — after a collision you don't know which sessions collided, on what, or why
Existing tools work after the merge: git's conflict markers, GitHub's mergeability check. Overlap works before — it watches the live worktrees and flags the overlap while the agents are still editing.
How Overlap works
Five stages, all deterministic, all local.
1 · Read — sessions from the AO daemon
The daemon exposes GET /api/v1/sessions?active=true and GET /api/v1/projects on loopback (no auth). Overlap reads both:
const projects = await listProjects();
const raw = await listSessions();
2 · Diff — changed-file sets per worktree
Session JSON does not carry a worktree path, so Overlap derives it from the AO data layout — <AO_DATA_DIR>/data/worktrees/<projectId>/<sessionId> — then computes the file set with git:
git diff --name-only <merge-base>..HEAD # committed changes
git status --porcelain # uncommitted: modified, untracked, renames
3 · Detect — overlap alerts
Deterministic rules, no LLM:
| Severity | Kind | Rule |
|---|---|---|
| high | same-file | the same path is touched by 2+ sessions |
| medium | same-dir | 2+ sessions touch files in the same directory, no same-file alert there |
| low | same-module | the same basename appears in 2+ sessions in different directories, no same-file alert on it |
4 · Plan — merge order
A greedy planner repeatedly picks the remaining session whose file set shares the fewest files with the others, so shared-file merges happen last:
const order = planMergeOrder(sessions);
// 1. engine-cli — touches cli.ts alone
// 2. dash-json — touches cli.ts + package-lock.json (shared)
5 · Report — post-merge collisions
$ npm run cli -- report merges.json
Post-merge report:
branch-a: no conflicting files
branch-b: src/x.ts
Architecture
┌──────────────┐ GET /api/v1/sessions?active=true ┌──────────────────┐
│ AO daemon │──────────────────────────────────────▶│ @overlap/core │
│ 127.0.0.1 │◀─── worktrees under ~/.ao/data/ ──────│ ao.ts · git.ts │
└──────────────┘ │ engine.ts · cli │
└────────┬─────────┘
│ sessions + files
▼
┌──────────────────────────────────────────────────────────────┐
│ apps/dashboard (Next.js) │
│ landing + radar on one URL · /api/state · live refresh │
└──────────────────────────────────────────────────────────────┘
Component by component
| Component | Technology | Responsibility |
|---|---|---|
| ao.ts | TypeScript, fetch | AO daemon client: sessions, projects, worktree derivation |
| git.ts | Node child_process (execFile) | merge-base, changed-file sets, worktree list — no shell |
| engine.ts | TypeScript, pure functions | detectOverlaps, planMergeOrder, buildReport |
| cli.ts | Node | overlap status / watch / report with --json |
| apps/dashboard | Next.js 15, React 19 | landing + radar UI; /api/state composes live daemon data |
Engineering decisions — the hard problems
1. Session JSON has no worktree path. The daemon's session object exposes id, branch, status — but not where the worktree lives. Overlap derives it deterministically from the AO data layout (AO_DATA_DIR/data/worktrees/{projectId}/{sessionId}) and verifies it with git rev-parse before reading. This pins Overlap to the default layout, stated in the README's limitations.
2. git status --porcelain parsing is not a regex. Untracked files (?? path), renames (R old -> new), and ignored entries (!!) each have different shapes. A naive regex drops untracked files — the most common source of agent collisions. The parser handles all four shapes explicitly.
3. Alert dedup must not over-suppress. Early versions suppressed the low (same-module) alert whenever any session in it had a higher-severity alert elsewhere — so an unrelated collision hid a real one. The final rules suppress only within the same file/directory: same-file subsumes same-dir on that file; a same-module alert survives unless a same-file alert exists on that basename. A unit test locks this in.
4. Merge-order planning is greedy and deterministic. Ties are broken by iteration order, which is stable for a given session list — the planner's output is reproducible, which matters when the dashboard renders it.
5. Headless operation. The AO desktop app (Electron) is heavy on low-RAM machines and can die under load, taking agent sessions with it. Overlap's daemon client works against the headless Go daemon, so the radar keeps working while the app is closed. The build itself ran headless with three parallel agents.
What's real vs pending — the honesty table
| Feature | Status | Detail |
|---|---|---|
| Overlap detection | ✅ Real | high/medium/low rules, 11 unit tests |
CLI (status/watch/report, --json) |
✅ Real | verified live against the daemon |
| Merge-order planner | ✅ Real | used for the real merge sequence in the build |
| Reviewer confirmation | ✅ Real | a reviewer session confirmed the cli.ts collision the radar predicted |
| Live dashboard | ✅ Real | deployed; /api/state reads the real daemon (honest error when it's down) |
| Fresh-clone build | ✅ Real | npm install && npm run build && npm test verified on a clean clone |
| Conflict prediction | ⚠️ File-level | overlap detection is path heuristics, not semantic analysis — two agents editing different parts of the same file still count as a collision |
| Daemon API stability | ⚠️ Internal | the AO /api/v1 surface may change between AO releases |
| Screenshots in README | ❌ None | kept out on purpose; the dashboard is live to verify against |
Tests
11/11 passing — node:test over the engine (detection rules, dedup, planner, report builder). Full output:
✔ detectOverlaps: same file touched by two sessions -> high same-file
✔ detectOverlaps: same directory, different files -> medium same-dir
✔ detectOverlaps: same basename in different dirs -> low same-module
✔ detectOverlaps: same-file suppresses same-dir for the same directory
✔ detectOverlaps: unrelated low alert not suppressed by a different high alert
✔ detectOverlaps: sessions with no files produce no alerts
✔ detectOverlaps: output is deterministically ordered
✔ planMergeOrder: disjoint session first (least shared files)
✔ planMergeOrder: single session
✔ planMergeOrder: empty input
✔ buildReport: lists conflicting files per merged branch
Run it locally
git clone https://github.com/subheeksh5599/overlap.git
cd overlap
npm install
npm run build
npm test
CLI (requires an AO daemon running):
npm run cli -- status # per-session file sets + alerts + suggested merge order
npm run cli -- watch # poll every 5s, print new alerts
npm run cli -- report m.json # post-merge report from a merge-records file
npm run cli -- status --json # machine-readable output
Dashboard:
npm run dev:dashboard # http://localhost:3000 — landing + radar
Configuration
| Variable | Default | Description |
|---|---|---|
AO_DAEMON_URL |
http://127.0.0.1:3001 |
AO daemon base URL |
AO_DATA_DIR |
~/.ao |
AO data directory (worktrees live under <data>/data/worktrees) |
Deploy
vercel --prod --yes # repo root; build runs core + dashboard
The project is configured as a monorepo: buildCommand: npm run build, outputDirectory: apps/dashboard/.next. The deployed /api/state reports an explicit daemon-unreachable error when no local AO daemon exists — it never fabricates data.
Project layout
overlap/
├── packages/overlap-core/
│ ├── src/ # ao.ts, git.ts, engine.ts, cli.ts, index.ts, types.ts
│ └── test/ # engine.test.js (node:test, 11 tests)
├── apps/dashboard/
│ └── src/
│ ├── app/ # page.tsx (landing + radar), api/state/route.ts
│ └── components/ # Dashboard.tsx (radar UI)
├── README.md
└── package.json # npm workspaces: packages/*, apps/*
Tech stack
| Layer | Technology |
|---|---|
| Core | Node.js, TypeScript 5, node:test |
| Git access | child_process.execFile (no shell) |
| Dashboard | Next.js 15, React 19, App Router |
| Deploy | Vercel (monorepo build, free tier) |
| Target | Agent Orchestrator daemon /api/v1 (loopback, no auth) |
Roadmap
- Semantic overlap — module-level analysis beyond paths (import graph) to catch same-file edits that don't collide and module edits that do
- Automated fix routing — when the radar flags a collision, hand the resolution task back to the least-loaded session automatically
- CI-aware alerts — pair overlap alerts with check-run state so "collides AND failing" outranks "collides but green"
- Multi-project view — aggregate the radar across every registered AO project
License
Apache-2.0 — built for The Orchestra, Agent Orchestrator's first online hackathon, August 2026.
Built With
- agent
- node.js
- orchestrator
- react
- typescript
Log in or sign up for Devpost to join the conversation.