ashmoonori-afk/between

Between — a local terminal broker for AI pair development (observable diff-driven review loop; developer + reviewer agents never talk directly)

TypeScript

0

137 commits

updated Sep 27, 2026

See the code

See what people are saying

SourceMessageScoreDate

Between - two AI coding agents that only talk through git diff (r/SideProject)

Most two-agent coding setups either share one transcript or make you copy-paste messages between them. I wanted neither, so I built a broker. Between watches the repo, not the chats. When a diff settles, it hashes it and starts a review. The reviewer reads the real tree and writes a structured…

2

Sep 28, 2026

README

 ____  _____ _______        _______ _____ _   _
| __ )| ____|_   _\ \      / / ____| ____| \ | |
|  _ \|  _|   | |  \ \ /\ / /|  _| |  _| |  \| |
| |_) | |___  | |   \ V  V / | |___| |___| |\  |
|____/|_____| |_|    \_/\_/  |_____|_____|_| \_|

A local IDE broker for AI pair development.

Between watches the repository, not private agent chats. A developer agent and a reviewer agent coordinate through git diff, durable JSON state, review files, and short broker signals while the human keeps final authority over merge, deploy, and rule promotion.

CI Node TypeScript License


What Between Is

Most AI pair-programming setups put two agents in one transcript or make the human relay messages between them. Between takes a stricter shape:

  • The broker watches git diff, hashes stable changes, and starts review cycles.
  • Agents never talk directly to each other.
  • The reviewer reads the real tree and writes structured review output.
  • The developer receives only the broker's short "reflect this review" signal.
  • State, events, acks, reviews, verification, and approvals are plain local files under .between/.
  • The loop can recover after restarts and will not approve a diff that changed under review.
  • The human is the only actor allowed to approve merge, deploy, or promote_rule.

Think of it as a local, file-shaped protocol for controlled AI collaboration: IDE-native, restartable, inspectable, and conservative about trust.

Legacy Terminal Diagnostic Capture

Captured from the built CLI with node dist/cli.js dash --once after between init --agent fake in a temporary git repository.

+------------------------------------------------------------------------------------------+
| B BETWEEN session:readme-tui-capture | 15:58:01                                          |
| PHASE IDLE | WAIT - | CYCLE 0 | GOAL 0 | TRUST simulated                                 |
+------------------------------------------------------------------------------------------+
| BROKER stable | DIFF 0 files +0 -0 | HASH - | BUNDLE -                                   |
| REVIEW - | SIGNAL -                                                                      |
+------------------------------------------------------------------------------------------+
| DEVELOPER fake status idle | snap -                                                      |
| REVIEWER fake status idle | review - | trust simulated                                   |
+------------------------------------------------------------------------------------------+
| RECENT EVENTS                                                                            |
| no events yet                                                                            |
| COMMANDS r review now (off) | esc abort agents (off) | p pause | s stop broker | q qu... |
+------------------------------------------------------------------------------------------+

This terminal frame remains as a diagnostic and fallback surface. The product surface is the IDE cockpit below.

VS Code IDE Cockpit

Between ships a local VS Code IDE surface as the primary operator view. It keeps the broker-first contract: the human types into the broker input, while developer and reviewer panes stay read-only status surfaces. Builder and Reviewer counts are project-local topology, stored in .between/config.yaml, and rendered as stable tmux-like targets such as builder:1 and reviewer:2.

cd extensions/vscode-between
npm run check

Open the command palette and run Between: Open IDE. The IDE reads the same .between/state.json, sealed bundles, review files, and command bus as the terminal workflow. It does not create a second conversation channel between agents.

Use between ide to inspect or set the IDE control profile from the target project:

between ide
between ide --builder-agents 3 --reviewer-agents 2
between ide --rules-mode project_only --permission-mode guard --working-folder . --followup-mode steer --print-cli reviewer:1
between ide --json

ide_cli_rules_mode: project_only is the default IDE-only local CLI profile. It isolates IDE-launched agent CLIs from global agent rules, but it does not bypass Between broker policy, evidence gates, approvals, or sandbox decisions. When the selected invocation is Codex-based, either direct codex ... or the generated .between/agents/codex-agent.mjs wrapper, between ide --print-cli ... includes CODEX_HOME=<repo>/.between/ide-profile/codex so the IDE profile is project-local and does not read or mutate the user's global Codex home.

Aside-inspired task controls are project-local IDE defaults, not a new security boundary. ide_permission_mode names the IDE-launched agent intent (read_only, guard, or full_access), ide_working_folder is a project-local folder hint, and ide_followup_mode is the operator's follow-up intent (steer now, queue after the current run when a durable queue exists). They are exported to IDE-launched agents as BETWEEN_IDE_* environment values and never change bypasses_broker_policy: false.

Relevant project-local config fields:

builder_agent_count: 1
reviewer_agent_count: 1
ide_cli_rules_mode: project_only
ide_cli_profile_dir: .between/ide-profile
ide_permission_mode: guard
ide_working_folder: .
ide_followup_mode: steer

Why This Shape

Between is designed around a few non-negotiables:

  1. git diff is the shared truth. The reviewer inspects code changes, not a chat summary.
  2. Files are the protocol. JSON and Markdown make the workflow easy to audit, replay, and adapt to different CLIs.
  3. The broker owns timing. Polling, debounce, stale-diff detection, signal resend, pause, abort, and steer all belong to the broker.
  4. Agent work stays bounded. Agents receive short signals and read the current repo state themselves.
  5. Human gates stay explicit. Agents can propose and verify; they cannot silently merge, deploy, or promote project rules.

Quick Start

Requires Node.js >=22.12 and git.

Run it with npx (the npm package is between-dev; the command is between):

cd path/to/target-repo
npx -y between-dev init --agent fake
npx -y between-dev status

# before the package is published to npm, run straight from GitHub (builds on install)
npx -y github:ashmoonori-afk/between status

Or install it: npm install -g between-dev, then use between ....

From source:

git clone https://github.com/ashmoonori-afk/between
cd between
npm install
npm run build
node dist/cli.js --help

When you broker the Between repo itself during development, node dist/cli.js is enough. When you broker another repository, either link/install the CLI or call the built CLI by absolute path while your current directory is the target repo. The examples below assume the between binary is on PATH.

cd path/to/target-repo
between onboard
between goal "refresh tokens without leaking secrets"
between start --headless --max-ticks 6
between status
between dash --once

Demo the full loop with the bundled fake agent. The default agent_mode: file waits for you to run the agents yourself, so switch the demo to oneshot and Between runs the fake developer and reviewer for you:

between init --agent fake
# in .between/config.yaml set:  agent_mode: oneshot
between goal "demo change"
# edit a file in the target repo
between start          # the loop reaches human_gate; see `between status`

For real agents, initialize with explicit roles (they use oneshot mode). Re-running init does not change the agents of an existing workspace; to switch, delete .between/ first:

between init --developer claude --reviewer codex

The generated wrappers and file contract are documented in docs/AGENT-CONTRACT.md.

Broker Cycle

flowchart LR
    Goal["goal locked"] --> Develop["developing"]
    Develop --> Debounce["debouncing"]
    Debounce --> ReviewRequested["review requested"]
    ReviewRequested --> Reviewing["reviewing"]
    Reviewing --> ReviewWritten["review written"]
    ReviewWritten --> Blocking{"blocking findings?"}
    Blocking -->|yes| Applying["applying review"]
    Applying --> Develop
    Blocking -->|no| Verify["verify passed"]
    Verify --> HumanGate["human gate"]
    HumanGate --> Done["approved by human"]

Important cycle rules:

  • The broker persists the new cycle before signaling an agent.
  • The same diff hash is not reviewed twice.
  • A diff that changes while a review is outstanding supersedes the stale review.
  • A missing signal after restart is resent.
  • Hosted-agent failures are surfaced in broker state.
  • With BETWEEN_APPROVAL_SECRET configured, approval is signed and human-owned.

Agent Modes

Between exposes one SignalTransport interface with three operating modes.

ModeWhat it doesNative dependencyUse when
fileWrites signal files; agents or scripts reply through .between/.noneYou want the most portable baseline.
oneshotSpawns developer_command or reviewer_command once per signal.noneYou want CLI automation without a live PTY.
ptyHosts live ConPTY/forkpty terminals through optional @lydell/node-pty.optionalYou want visible agent panes and live terminal control.

All modes reuse the same ack-file gate, so reviewing only advances after a real acknowledgement.

Between And cmux

cmux is a terminal/session cockpit. Between is a broker workflow engine with a terminal cockpit. They overlap visually, but the product center is different.

AreaWhere Between is strongerWhere cmux is stronger
Workflow ownershipDiff-driven broker cycles, debounce, review state, approval gates, and evidence bundles are first-class.General terminal multiplexing is broader and more mature.
Agent separationDeveloper and reviewer never share a transcript; the repo, diff, JSON state, and review files are the contract.cmux is better when you primarily want multiple live terminal panes under direct human control.
Restartability.between/state.json, .between/events.jsonl, acks, reviews, and snapshots make the broker loop inspectable after a crash.A multiplexer session is more ergonomic for long-running interactive shells.
Human controlWith BETWEEN_APPROVAL_SECRET, signed approvals and verify-push protect merge/deploy/promotion from forged local protocol writes.cmux is not trying to be an approval or policy gate.
Automation surfacestatus, goal, steer, abort, review-now, evidence, policy, verify, and chat gateways can drive the broker.cmux has the advantage when the needed primitive is session navigation, split management, or shell ergonomics.
PortabilityThe file and oneshot paths have no native dependency and can run headless.cmux-style live pane richness depends on the terminal/session runtime.

Practical takeaway: run Between when you need a durable review protocol around AI coding work. Use cmux, tmux, or another multiplexer when the main job is rich interactive terminal management. They can coexist: Between can run inside a cmux pane while still owning the broker protocol.

Current Limits

Between is alpha. It is useful now, but it is not pretending to be finished.

  • It is not a general-purpose terminal multiplexer.
  • PTY hosting is optional and platform-sensitive; the file path is the baseline.
  • Real Claude/Codex wrapper behavior depends on the target machine, CLI version, login state, and terminal capabilities.
  • Abort and steer are broker-level controls; downstream agent compliance depends on the wrapper and hosted process behavior.
  • .between/ is a cooperative local protocol, not a sandbox.
  • Terminal dashboards are compatibility and diagnostic surfaces; the VS Code IDE cockpit is the primary app surface over the local protocol.

Forward Vision

The long-term goal is a verifiable AI change cockpit:

  • Obsidian/project-wiki memory as the durable design-rule layer.
  • Repeated review findings promoted into project rules after human approval.
  • Stronger agent-control adapters for abort, steer, interrupt, resume, and session recovery.
  • A real-agent compatibility matrix for Claude, Codex, and other CLI agents.
  • tmux-grade topology and target clarity without giving up the broker's file protocol.
  • IDE and chat surfaces that drive the same command bus instead of inventing a second workflow.
  • Policy-as-code gates for risk, approvals, evidence bundles, and verification.
  • Portable review packets that let a reviewer inspect the exact cycle without reading agent transcripts.

The direction is simple: less chat theater, more observable change control.

CLI Cheat Sheet

between onboard [--channel echo|telegram|discord] [--agent ...] [--chat-id <id>] [--yes]
between init [--vault <path>] [--agent fake|claude|codex] [--developer ...] [--reviewer ...]
between goal "<text>"
between start [--embed] [--headless] [--max-ticks <n>]
between status [--json]
between dash [--once] [--interval <ms>]
between gateway [--max-seconds <n>]
between review-now
between pause
between resume
between interrupt|abort
between steer "<text>"
between stop
between ack
between approve merge|deploy|promote_rule
between verify-push [--stdin]
between doctor
between summarize
between evidence
between review-worktree
between policy
between verify
between journal
between replay
between cockpit
between mcp [--root <path>] [--allow-control] [--allow-exec]
between ide [--builder-agents <n>] [--reviewer-agents <n>] [--rules-mode project_only|inherit_global] [--permission-mode read_only|guard|full_access] [--working-folder <relative-path>] [--followup-mode steer|queue] [--print-cli builder|reviewer|builder:n|reviewer:n] [--json]

MCP Server

Between also runs as a stdio MCP server, so MCP clients (Claude Code, Claude Desktop, Codex CLI, Cursor) can read broker state and, when a human allows it, steer the broker. It is a second thin front end over the same core API as the CLI.

# Claude Code, from the target repository
claude mcp add between -- npx -y --package=between-dev@0.1.0 between-mcp

Other clients use the same command in their MCP config, for example:

{
  "mcpServers": {
    "between": {
      "command": "npx",
      "args": ["-y", "--package=between-dev@0.1.0", "between-mcp", "--root", "/abs/path/to/repo"]
    }
  }
}

By default only read tools are exposed (between_status, between_summarize, between_doctor, between_journal, between_replay, between_evidence). --allow-exec adds between_verify and between_policy, and --allow-control adds pause, resume, interrupt, review-now, stop, goal, and steer. Approval, ack, init, and verify-push are never exposed. Tool reference, security notes, and per-client configs (including Codex CLI and Cursor) are in docs/MCP.md.

Forge Lifecycle

Between also includes a PWSForge-style app-build lifecycle:

between forge init "<idea>" [--platform ios,android,web]
between forge status
between forge approve
between forge advance
between forge block P0|P1|P2|P3 "<description>"
between forge unblock <index>
between forge build "<task>"

between forge build does not code inline. It routes build work back through the developer/reviewer broker loop.

Runtime Files

between init creates .between/ inside the target repository and adds it to the target .gitignore so broker writes do not self-trigger review cycles.

.between/
|-- config.yaml          # watch/debounce/cycle config and agent mode
|-- state.json           # phase, cycle, hash, reviewed hashes, approval
|-- state.json.bak       # recovery fallback
|-- events.jsonl         # append-only event log
|-- commands/            # CLI to daemon command bus
|-- signals/             # broker to agent pointers
|-- acks/                # agent to broker receipts
|-- reviews/             # structured review findings
|-- verify/              # verification reports
|-- snapshots/           # bounded, scrubbed diff snapshots
|-- cycles/              # per-cycle evidence
|-- usage/               # local usage telemetry
`-- agents/              # fake agent and generated wrappers

Architecture

flowchart LR
    Human["Human"] --> CLI["between CLI"]
    CLI --> Commands[".between/commands"]
    Commands --> Daemon["Broker daemon"]
    Daemon --> Git["git diff HEAD"]
    Daemon --> State["state.json"]
    Daemon --> Events["events.jsonl"]
    Daemon --> Signals["SignalTransport"]
    Signals --> Reviewer["Reviewer agent"]
    Reviewer --> Acks["acks"]
    Reviewer --> Reviews["reviews and verify"]
    Reviews --> Daemon
    Acks --> Daemon
    Daemon --> Developer["Developer agent"]
    Developer --> Git
    Daemon --> Gate["human gate"]
    Gate --> Human

Source map:

  • src/api/: the shared core API used by both front ends (status, broker control, checks, journal, evidence). No printing; typed results and errors. Also the library entry (import ... from 'between-dev'); human-only approval lives in between-dev/human.
  • src/cli/: CLI front end (commander wiring and output formatting).
  • src/mcp/: MCP front end (stdio server, tool registration).
  • src/core/: pure broker logic, FSM, diff hashing, debounce, findings, redaction, and state projection.
  • src/adapters/: git, atomic state, event log, locks, command bus, signal transports, agent hosts, and snapshots.
  • src/daemon/: tick loop, commands, phase transitions, context, reconciliation, and reviewer-signal recovery.
  • src/ui/: legacy terminal dashboard, cockpit frame, agent panes, and theme.
  • src/ide/: IDE bridge and project-local topology profile.
  • src/gateway/: echo, Telegram, and Discord chat transports.
  • src/onboard/: first-run wizard and credential smoke tests.
  • src/forge/: app-build phase machine and broker handoff.
  • src/cli.ts: command registration.

Trust Boundary

.between/ is a cooperative local protocol, not a complete security boundary. Any local process that can write .between/ can try to forge ack, review, or verify files.

Approval has stronger protection when BETWEEN_APPROVAL_SECRET is configured: between approve signs approval records with that human-owned secret, and the daemon requires a valid signature. The signature also covers the git tree of the approved working tree.

between init installs a pre-push hook. Pushes to protected branches (protected_branches in .between/config.yaml, default [main]) need a signed, fresh merge approval whose tree equals the pushed commit's tree: approve, commit exactly that tree, then push. Deleting a protected branch is refused. Pushes to any other branch are not gated. between verify-push checks the current branch the same way (--stdin reads git's pre-push lines). Without the env secret, protected pushes stay blocked. The hook is client-side (git push --no-verify skips it), so pair it with server-side branch protection.

The MCP server never exposes approval. It scrubs BETWEEN_APPROVAL_SECRET and other credential-looking variables from its own environment, is pinned to one project root, and only registers command-running or broker-steering tools when a human starts it with --allow-exec or --allow-control. See docs/MCP.md.

Do not run Between with untrusted agents in a repository where unapproved merge or deploy would be harmful.

Verification

Recommended local gate:

npm run typecheck
npm run lint
npm test
npm run build
npm run smoke:pack   # packs the package, runs it via npx (CLI + MCP stdio) and as a library
npm run test:vscode
npm audit --omit=dev

The CI workflow runs the gate on GitHub Actions across Ubuntu and Windows with Node 22/24, plus a non-blocking node-pty prebuilt probe.

Documentation

FilePurpose
BETWEEN-BROKER-BLUEPRINT.mdOriginal product concept and broker architecture.
DEVELOPMENT-PLAN.mdNode/TypeScript implementation plan and acceptance map.
IMPROVEMENTS.mdAdversarial design review backlog.
TASKS.mdPhase and task build tracker.
DESIGN.mdIDE-first cockpit design rules.
docs/AGENT-CONTRACT.mdAgent signal, ack, review, and wrapper contract.
docs/MCP.mdMCP server: tools, flags, security notes, client configs.
docs/IDE-DOGFOOD-PIPELINE.mdRepeatable IDE dogfood gate for CLI, VS Code webview, tests, and build.
docs/adr/Architecture decision records.

Status

Between is alpha. The file-signal loop is the verified baseline. The VS Code IDE surface is now the primary app path; one-shot, PTY, and terminal dashboards are additive compatibility paths. The next meaningful frontier is stronger evidence, stronger steering, and less room for invisible agent drift.

License

MIT. See LICENSE.

Contributors

ashmoonori-afk

109 commits

ashmoonori

28 commits

ashmoonori-afk/between

Between — a local terminal broker for AI pair development (observable diff-driven review loop; developer + reviewer agents never talk directly)

TypeScript

0

137 commits

updated Sep 27, 2026

See the code

See what people are saying

SourceMessageScoreDate

Between - two AI coding agents that only talk through git diff (r/SideProject)

Most two-agent coding setups either share one transcript or make you copy-paste messages between them. I wanted neither, so I built a broker. Between watches the repo, not the chats. When a diff settles, it hashes it and starts a review. The reviewer reads the real tree and writes a structured…

2

Sep 28, 2026

README

 ____  _____ _______        _______ _____ _   _
| __ )| ____|_   _\ \      / / ____| ____| \ | |
|  _ \|  _|   | |  \ \ /\ / /|  _| |  _| |  \| |
| |_) | |___  | |   \ V  V / | |___| |___| |\  |
|____/|_____| |_|    \_/\_/  |_____|_____|_| \_|

A local IDE broker for AI pair development.

Between watches the repository, not private agent chats. A developer agent and a reviewer agent coordinate through git diff, durable JSON state, review files, and short broker signals while the human keeps final authority over merge, deploy, and rule promotion.

CI Node TypeScript License


What Between Is

Most AI pair-programming setups put two agents in one transcript or make the human relay messages between them. Between takes a stricter shape:

  • The broker watches git diff, hashes stable changes, and starts review cycles.
  • Agents never talk directly to each other.
  • The reviewer reads the real tree and writes structured review output.
  • The developer receives only the broker's short "reflect this review" signal.
  • State, events, acks, reviews, verification, and approvals are plain local files under .between/.
  • The loop can recover after restarts and will not approve a diff that changed under review.
  • The human is the only actor allowed to approve merge, deploy, or promote_rule.

Think of it as a local, file-shaped protocol for controlled AI collaboration: IDE-native, restartable, inspectable, and conservative about trust.

Legacy Terminal Diagnostic Capture

Captured from the built CLI with node dist/cli.js dash --once after between init --agent fake in a temporary git repository.

+------------------------------------------------------------------------------------------+
| B BETWEEN session:readme-tui-capture | 15:58:01                                          |
| PHASE IDLE | WAIT - | CYCLE 0 | GOAL 0 | TRUST simulated                                 |
+------------------------------------------------------------------------------------------+
| BROKER stable | DIFF 0 files +0 -0 | HASH - | BUNDLE -                                   |
| REVIEW - | SIGNAL -                                                                      |
+------------------------------------------------------------------------------------------+
| DEVELOPER fake status idle | snap -                                                      |
| REVIEWER fake status idle | review - | trust simulated                                   |
+------------------------------------------------------------------------------------------+
| RECENT EVENTS                                                                            |
| no events yet                                                                            |
| COMMANDS r review now (off) | esc abort agents (off) | p pause | s stop broker | q qu... |
+------------------------------------------------------------------------------------------+

This terminal frame remains as a diagnostic and fallback surface. The product surface is the IDE cockpit below.

VS Code IDE Cockpit

Between ships a local VS Code IDE surface as the primary operator view. It keeps the broker-first contract: the human types into the broker input, while developer and reviewer panes stay read-only status surfaces. Builder and Reviewer counts are project-local topology, stored in .between/config.yaml, and rendered as stable tmux-like targets such as builder:1 and reviewer:2.

cd extensions/vscode-between
npm run check

Open the command palette and run Between: Open IDE. The IDE reads the same .between/state.json, sealed bundles, review files, and command bus as the terminal workflow. It does not create a second conversation channel between agents.

Use between ide to inspect or set the IDE control profile from the target project:

between ide
between ide --builder-agents 3 --reviewer-agents 2
between ide --rules-mode project_only --permission-mode guard --working-folder . --followup-mode steer --print-cli reviewer:1
between ide --json

ide_cli_rules_mode: project_only is the default IDE-only local CLI profile. It isolates IDE-launched agent CLIs from global agent rules, but it does not bypass Between broker policy, evidence gates, approvals, or sandbox decisions. When the selected invocation is Codex-based, either direct codex ... or the generated .between/agents/codex-agent.mjs wrapper, between ide --print-cli ... includes CODEX_HOME=<repo>/.between/ide-profile/codex so the IDE profile is project-local and does not read or mutate the user's global Codex home.

Aside-inspired task controls are project-local IDE defaults, not a new security boundary. ide_permission_mode names the IDE-launched agent intent (read_only, guard, or full_access), ide_working_folder is a project-local folder hint, and ide_followup_mode is the operator's follow-up intent (steer now, queue after the current run when a durable queue exists). They are exported to IDE-launched agents as BETWEEN_IDE_* environment values and never change bypasses_broker_policy: false.

Relevant project-local config fields:

builder_agent_count: 1
reviewer_agent_count: 1
ide_cli_rules_mode: project_only
ide_cli_profile_dir: .between/ide-profile
ide_permission_mode: guard
ide_working_folder: .
ide_followup_mode: steer

Why This Shape

Between is designed around a few non-negotiables:

  1. git diff is the shared truth. The reviewer inspects code changes, not a chat summary.
  2. Files are the protocol. JSON and Markdown make the workflow easy to audit, replay, and adapt to different CLIs.
  3. The broker owns timing. Polling, debounce, stale-diff detection, signal resend, pause, abort, and steer all belong to the broker.
  4. Agent work stays bounded. Agents receive short signals and read the current repo state themselves.
  5. Human gates stay explicit. Agents can propose and verify; they cannot silently merge, deploy, or promote project rules.

Quick Start

Requires Node.js >=22.12 and git.

Run it with npx (the npm package is between-dev; the command is between):

cd path/to/target-repo
npx -y between-dev init --agent fake
npx -y between-dev status

# before the package is published to npm, run straight from GitHub (builds on install)
npx -y github:ashmoonori-afk/between status

Or install it: npm install -g between-dev, then use between ....

From source:

git clone https://github.com/ashmoonori-afk/between
cd between
npm install
npm run build
node dist/cli.js --help

When you broker the Between repo itself during development, node dist/cli.js is enough. When you broker another repository, either link/install the CLI or call the built CLI by absolute path while your current directory is the target repo. The examples below assume the between binary is on PATH.

cd path/to/target-repo
between onboard
between goal "refresh tokens without leaking secrets"
between start --headless --max-ticks 6
between status
between dash --once

Demo the full loop with the bundled fake agent. The default agent_mode: file waits for you to run the agents yourself, so switch the demo to oneshot and Between runs the fake developer and reviewer for you:

between init --agent fake
# in .between/config.yaml set:  agent_mode: oneshot
between goal "demo change"
# edit a file in the target repo
between start          # the loop reaches human_gate; see `between status`

For real agents, initialize with explicit roles (they use oneshot mode). Re-running init does not change the agents of an existing workspace; to switch, delete .between/ first:

between init --developer claude --reviewer codex

The generated wrappers and file contract are documented in docs/AGENT-CONTRACT.md.

Broker Cycle

flowchart LR
    Goal["goal locked"] --> Develop["developing"]
    Develop --> Debounce["debouncing"]
    Debounce --> ReviewRequested["review requested"]
    ReviewRequested --> Reviewing["reviewing"]
    Reviewing --> ReviewWritten["review written"]
    ReviewWritten --> Blocking{"blocking findings?"}
    Blocking -->|yes| Applying["applying review"]
    Applying --> Develop
    Blocking -->|no| Verify["verify passed"]
    Verify --> HumanGate["human gate"]
    HumanGate --> Done["approved by human"]

Important cycle rules:

  • The broker persists the new cycle before signaling an agent.
  • The same diff hash is not reviewed twice.
  • A diff that changes while a review is outstanding supersedes the stale review.
  • A missing signal after restart is resent.
  • Hosted-agent failures are surfaced in broker state.
  • With BETWEEN_APPROVAL_SECRET configured, approval is signed and human-owned.

Agent Modes

Between exposes one SignalTransport interface with three operating modes.

ModeWhat it doesNative dependencyUse when
fileWrites signal files; agents or scripts reply through .between/.noneYou want the most portable baseline.
oneshotSpawns developer_command or reviewer_command once per signal.noneYou want CLI automation without a live PTY.
ptyHosts live ConPTY/forkpty terminals through optional @lydell/node-pty.optionalYou want visible agent panes and live terminal control.

All modes reuse the same ack-file gate, so reviewing only advances after a real acknowledgement.

Between And cmux

cmux is a terminal/session cockpit. Between is a broker workflow engine with a terminal cockpit. They overlap visually, but the product center is different.

AreaWhere Between is strongerWhere cmux is stronger
Workflow ownershipDiff-driven broker cycles, debounce, review state, approval gates, and evidence bundles are first-class.General terminal multiplexing is broader and more mature.
Agent separationDeveloper and reviewer never share a transcript; the repo, diff, JSON state, and review files are the contract.cmux is better when you primarily want multiple live terminal panes under direct human control.
Restartability.between/state.json, .between/events.jsonl, acks, reviews, and snapshots make the broker loop inspectable after a crash.A multiplexer session is more ergonomic for long-running interactive shells.
Human controlWith BETWEEN_APPROVAL_SECRET, signed approvals and verify-push protect merge/deploy/promotion from forged local protocol writes.cmux is not trying to be an approval or policy gate.
Automation surfacestatus, goal, steer, abort, review-now, evidence, policy, verify, and chat gateways can drive the broker.cmux has the advantage when the needed primitive is session navigation, split management, or shell ergonomics.
PortabilityThe file and oneshot paths have no native dependency and can run headless.cmux-style live pane richness depends on the terminal/session runtime.

Practical takeaway: run Between when you need a durable review protocol around AI coding work. Use cmux, tmux, or another multiplexer when the main job is rich interactive terminal management. They can coexist: Between can run inside a cmux pane while still owning the broker protocol.

Current Limits

Between is alpha. It is useful now, but it is not pretending to be finished.

  • It is not a general-purpose terminal multiplexer.
  • PTY hosting is optional and platform-sensitive; the file path is the baseline.
  • Real Claude/Codex wrapper behavior depends on the target machine, CLI version, login state, and terminal capabilities.
  • Abort and steer are broker-level controls; downstream agent compliance depends on the wrapper and hosted process behavior.
  • .between/ is a cooperative local protocol, not a sandbox.
  • Terminal dashboards are compatibility and diagnostic surfaces; the VS Code IDE cockpit is the primary app surface over the local protocol.

Forward Vision

The long-term goal is a verifiable AI change cockpit:

  • Obsidian/project-wiki memory as the durable design-rule layer.
  • Repeated review findings promoted into project rules after human approval.
  • Stronger agent-control adapters for abort, steer, interrupt, resume, and session recovery.
  • A real-agent compatibility matrix for Claude, Codex, and other CLI agents.
  • tmux-grade topology and target clarity without giving up the broker's file protocol.
  • IDE and chat surfaces that drive the same command bus instead of inventing a second workflow.
  • Policy-as-code gates for risk, approvals, evidence bundles, and verification.
  • Portable review packets that let a reviewer inspect the exact cycle without reading agent transcripts.

The direction is simple: less chat theater, more observable change control.

CLI Cheat Sheet

between onboard [--channel echo|telegram|discord] [--agent ...] [--chat-id <id>] [--yes]
between init [--vault <path>] [--agent fake|claude|codex] [--developer ...] [--reviewer ...]
between goal "<text>"
between start [--embed] [--headless] [--max-ticks <n>]
between status [--json]
between dash [--once] [--interval <ms>]
between gateway [--max-seconds <n>]
between review-now
between pause
between resume
between interrupt|abort
between steer "<text>"
between stop
between ack
between approve merge|deploy|promote_rule
between verify-push [--stdin]
between doctor
between summarize
between evidence
between review-worktree
between policy
between verify
between journal
between replay
between cockpit
between mcp [--root <path>] [--allow-control] [--allow-exec]
between ide [--builder-agents <n>] [--reviewer-agents <n>] [--rules-mode project_only|inherit_global] [--permission-mode read_only|guard|full_access] [--working-folder <relative-path>] [--followup-mode steer|queue] [--print-cli builder|reviewer|builder:n|reviewer:n] [--json]

MCP Server

Between also runs as a stdio MCP server, so MCP clients (Claude Code, Claude Desktop, Codex CLI, Cursor) can read broker state and, when a human allows it, steer the broker. It is a second thin front end over the same core API as the CLI.

# Claude Code, from the target repository
claude mcp add between -- npx -y --package=between-dev@0.1.0 between-mcp

Other clients use the same command in their MCP config, for example:

{
  "mcpServers": {
    "between": {
      "command": "npx",
      "args": ["-y", "--package=between-dev@0.1.0", "between-mcp", "--root", "/abs/path/to/repo"]
    }
  }
}

By default only read tools are exposed (between_status, between_summarize, between_doctor, between_journal, between_replay, between_evidence). --allow-exec adds between_verify and between_policy, and --allow-control adds pause, resume, interrupt, review-now, stop, goal, and steer. Approval, ack, init, and verify-push are never exposed. Tool reference, security notes, and per-client configs (including Codex CLI and Cursor) are in docs/MCP.md.

Forge Lifecycle

Between also includes a PWSForge-style app-build lifecycle:

between forge init "<idea>" [--platform ios,android,web]
between forge status
between forge approve
between forge advance
between forge block P0|P1|P2|P3 "<description>"
between forge unblock <index>
between forge build "<task>"

between forge build does not code inline. It routes build work back through the developer/reviewer broker loop.

Runtime Files

between init creates .between/ inside the target repository and adds it to the target .gitignore so broker writes do not self-trigger review cycles.

.between/
|-- config.yaml          # watch/debounce/cycle config and agent mode
|-- state.json           # phase, cycle, hash, reviewed hashes, approval
|-- state.json.bak       # recovery fallback
|-- events.jsonl         # append-only event log
|-- commands/            # CLI to daemon command bus
|-- signals/             # broker to agent pointers
|-- acks/                # agent to broker receipts
|-- reviews/             # structured review findings
|-- verify/              # verification reports
|-- snapshots/           # bounded, scrubbed diff snapshots
|-- cycles/              # per-cycle evidence
|-- usage/               # local usage telemetry
`-- agents/              # fake agent and generated wrappers

Architecture

flowchart LR
    Human["Human"] --> CLI["between CLI"]
    CLI --> Commands[".between/commands"]
    Commands --> Daemon["Broker daemon"]
    Daemon --> Git["git diff HEAD"]
    Daemon --> State["state.json"]
    Daemon --> Events["events.jsonl"]
    Daemon --> Signals["SignalTransport"]
    Signals --> Reviewer["Reviewer agent"]
    Reviewer --> Acks["acks"]
    Reviewer --> Reviews["reviews and verify"]
    Reviews --> Daemon
    Acks --> Daemon
    Daemon --> Developer["Developer agent"]
    Developer --> Git
    Daemon --> Gate["human gate"]
    Gate --> Human

Source map:

  • src/api/: the shared core API used by both front ends (status, broker control, checks, journal, evidence). No printing; typed results and errors. Also the library entry (import ... from 'between-dev'); human-only approval lives in between-dev/human.
  • src/cli/: CLI front end (commander wiring and output formatting).
  • src/mcp/: MCP front end (stdio server, tool registration).
  • src/core/: pure broker logic, FSM, diff hashing, debounce, findings, redaction, and state projection.
  • src/adapters/: git, atomic state, event log, locks, command bus, signal transports, agent hosts, and snapshots.
  • src/daemon/: tick loop, commands, phase transitions, context, reconciliation, and reviewer-signal recovery.
  • src/ui/: legacy terminal dashboard, cockpit frame, agent panes, and theme.
  • src/ide/: IDE bridge and project-local topology profile.
  • src/gateway/: echo, Telegram, and Discord chat transports.
  • src/onboard/: first-run wizard and credential smoke tests.
  • src/forge/: app-build phase machine and broker handoff.
  • src/cli.ts: command registration.

Trust Boundary

.between/ is a cooperative local protocol, not a complete security boundary. Any local process that can write .between/ can try to forge ack, review, or verify files.

Approval has stronger protection when BETWEEN_APPROVAL_SECRET is configured: between approve signs approval records with that human-owned secret, and the daemon requires a valid signature. The signature also covers the git tree of the approved working tree.

between init installs a pre-push hook. Pushes to protected branches (protected_branches in .between/config.yaml, default [main]) need a signed, fresh merge approval whose tree equals the pushed commit's tree: approve, commit exactly that tree, then push. Deleting a protected branch is refused. Pushes to any other branch are not gated. between verify-push checks the current branch the same way (--stdin reads git's pre-push lines). Without the env secret, protected pushes stay blocked. The hook is client-side (git push --no-verify skips it), so pair it with server-side branch protection.

The MCP server never exposes approval. It scrubs BETWEEN_APPROVAL_SECRET and other credential-looking variables from its own environment, is pinned to one project root, and only registers command-running or broker-steering tools when a human starts it with --allow-exec or --allow-control. See docs/MCP.md.

Do not run Between with untrusted agents in a repository where unapproved merge or deploy would be harmful.

Verification

Recommended local gate:

npm run typecheck
npm run lint
npm test
npm run build
npm run smoke:pack   # packs the package, runs it via npx (CLI + MCP stdio) and as a library
npm run test:vscode
npm audit --omit=dev

The CI workflow runs the gate on GitHub Actions across Ubuntu and Windows with Node 22/24, plus a non-blocking node-pty prebuilt probe.

Documentation

FilePurpose
BETWEEN-BROKER-BLUEPRINT.mdOriginal product concept and broker architecture.
DEVELOPMENT-PLAN.mdNode/TypeScript implementation plan and acceptance map.
IMPROVEMENTS.mdAdversarial design review backlog.
TASKS.mdPhase and task build tracker.
DESIGN.mdIDE-first cockpit design rules.
docs/AGENT-CONTRACT.mdAgent signal, ack, review, and wrapper contract.
docs/MCP.mdMCP server: tools, flags, security notes, client configs.
docs/IDE-DOGFOOD-PIPELINE.mdRepeatable IDE dogfood gate for CLI, VS Code webview, tests, and build.
docs/adr/Architecture decision records.

Status

Between is alpha. The file-signal loop is the verified baseline. The VS Code IDE surface is now the primary app path; one-shot, PTY, and terminal dashboards are additive compatibility paths. The next meaningful frontier is stronger evidence, stronger steering, and less room for invisible agent drift.

License

MIT. See LICENSE.

Contributors

ashmoonori-afk

109 commits

ashmoonori

28 commits

Languages

TypeScript

93.1%

JavaScript

6.5%