← All posts
Changelog context-bridge · 7 min read

context-bridge 0.11 and 0.12: OpenCode, safer handoffs, and lanes

Adding OpenCode exposed several problems in how context-bridge delivered a handoff. Then lanes made it possible to keep more than one independent conversation inside the same project.

context-bridge lets terminal coding agents hand an active session to one another.

It does not create a new chat and paste in a summary. It carries the conversation, decisions, open questions, and current Git state into the receiving agent’s own native session.

Versions 0.11 and 0.12 were released close together. One added a fifth agent and forced me to rethink parts of the delivery system. The other changed a basic assumption: one project directory no longer has to mean one line of work.

0.11.0: OpenCode and the problems it exposed

OpenCode is now supported alongside Claude Code, Codex, Grok, and Antigravity.

It was also the agent that did not fit the existing handoff model.

OpenCode stores its sessions in a local SQLite database and does not provide a hook for delivering a message into an already running TUI.

My first implementation used opencode run.

It worked, but I removed it.

That path can require authentication and trigger a paid model call. A local session switch that can stop at a login prompt is not a reliable switch. It also makes no sense to call a model just to place context into a session.

context-bridge now writes the delta directly into OpenCode’s database when resuming a session. The operation is transactional, idempotent, requires no authentication, and makes no model call.

When context-bridge needs to read the session for the next delta, it uses opencode export.

The only external dependency is the sqlite3 CLI, and bridge doctor now reports whether it is installed.

Supporting OpenCode was the planned feature. The more interesting work came from everything it exposed.

Delivering context is not the same as starting a turn

Claude Code and Codex receive their delta through a SessionStart hook.

That is the cleanest way to deliver context because nothing has to be pasted in front of the conversation. The receiving agent starts with the missing context already available.

But there was a problem.

The agent received everything it needed and had nothing to answer. It simply waited until I typed something.

Claude Code and Codex now receive a short opening prompt when delivery happens through a hook. That prompt does not contain the delta. It only starts the turn, which means the actual handoff cannot be delivered twice.

The first switch was the only unbounded one

Later handoffs were already clipped to fit within safe limits.

The first handoff was not.

It attempted to inline the entire conversation into a single CLI argument. With a large enough session, that becomes a multi-megabyte argument and the process fails with E2BIG before the agent even starts.

That is exactly what happened during my first real switch to OpenCode.

The first handoff is now bounded like every other handoff. It includes a summary first, then as much recent conversation as safely fits. The remaining context is stored in a full-context checkpoint referenced by the delta.

The receiving agent still has access to everything without requiring the entire session to fit inside one process argument.

A handoff is not delivered just because the process started

context-bridge previously recorded delivery as soon as the target process spawned.

That turned out to be the wrong boundary.

A CLI that receives and processes its prompt looks exactly like one that starts but ignores it. Both processes launch successfully.

I lost a real Claude-to-Codex handoff this way. context-bridge marked the delta as delivered, but Codex never saw it.

Delivery now commits only after the target shows its first activity.

If the agent starts and does nothing, the delta remains pending and can be retried. Starting a process is no longer treated as proof that the context reached the agent.

OpenCode session discovery was leaking servers

The original OpenCode session discovery started opencode serve, listed the sessions, then stopped the server.

That worked until discovery timed out.

A timeout could leave the server running in the background. The TUI could later connect to the stale server and confidently display old session state.

Discovery no longer requires a server. The fallback path also guarantees that its temporary server is stopped, including when the operation times out.

Agent flags now come from one source

Grok declares seven flags that cannot be used while resuming a session. Antigravity declares four.

The filter responsible for removing those flags read from a separate table. Over time, that table drifted away from the adapters that actually declared the rules.

The filter now reads each adapter’s own conflictFlags value, and a test verifies that a flag declared by an adapter is the same flag removed during launch.

If a rule is declared in one place and enforced from another, those two places will eventually disagree.

0.12.0: lanes

Before 0.12.0, one project directory effectively meant one active line of work.

Lanes remove that restriction.

Each lane has its own agent links, switch history, checkpoints, and pending context. Lanes cannot see one another, so I can keep two sessions open in separate terminals without their conversation state colliding.

The basic commands are:

  • bridge lane lists lanes, with the most recently active one first.
  • bridge lane new <name> creates an empty lane and switches to it.
  • bridge lane switch <name> moves to another lane.
  • bridge lane rm <name> --yes removes a lane.
  • bridge lane rm <name> --dry-run shows what would be removed first.

Running bridge without a lane argument resumes the last active lane.

That keeps the feature out of the way when it is not needed. A project with only one lane can continue working exactly as before.

What lanes isolate, and what they do not

Lanes isolate context. They do not isolate the working tree.

Every lane still uses the same checkout and sees the same files.

This means lanes support parallel conversations, not parallel code changes. Two agents editing the same working tree can still interfere with one another.

Worktree-backed lanes may come later. They are not part of this release, and context-bridge does not pretend otherwise.

Resuming and seeding lanes

bridge <agent> --resume can now open a lane directly. Without an argument, it shows a lane picker.

A new lane can also start with context from an existing one:

bridge lane new <name> --seed <source>

A seed is a briefing, not a copied session.

It carries the source lane’s decisions, open questions, Git state, and touched files. It does not carry the conversation or any agent session links.

The seed is delivered to the first agent that opens the new lane. If that launch fails, the seed remains available for the next agent instead of being lost.

Cleaning one lane without damaging another

The --lane option now scopes clean and inspect to a specific lane.

Protection still checks every lane before removing shared checkpoints. A checkpoint cannot be pruned while another lane still depends on it.

This distinction matters because lane-local cleanup still operates inside project-level storage.

Unlinking one agent safely

Previously, relinking could mean removing the entire .bridge/ directory and starting again.

Version 0.12 adds:

bridge unlink <agent>

This removes one agent’s link without affecting the others.

Unlinking also leaves a tombstone behind. If that agent is later started directly, its stale hooks become complete no-ops. They cannot silently reconnect the old session or consume a delta intended for an active one.

The tombstones are cumulative.

That detail came from a bug found during the final review. Storing only one tombstone meant unlinking a new session could erase the marker for an older one, allowing the older session to become active again.

Unlinking one session must never revive another session that was unlinked earlier.

Reviewing the trust boundaries

The final review focused heavily on file and lifecycle safety.

Every place that reads, writes, lists, or deletes a checkpoint now rejects paths that escape .bridge. The same checks reject paths that pass through symlinked directories.

Pruning validates every lane before deleting anything.

The lane seed and unlink flows received the same treatment, including:

  • Concurrent binding attempts
  • Partially created lanes
  • Oversized seeds
  • Failed agent launches
  • Seed recovery after a launch failure
  • Stale hooks from unlinked agents
  • Cumulative tombstones across multiple sessions

Most of this work was not visible in the original feature list.

I planned to add OpenCode. Supporting it under real usage exposed assumptions that had survived because the first four agents happened to fit them.

The fifth agent did more than expand compatibility. It forced the handoff machinery to become safer for every agent already supported.