Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
{
"name": "contextrelay",
"description": "ContextRelay bridge for Claude Code and Codex through a shared daemon, push channel delivery, durable queueing, and reply/get_messages/wait_for_messages tools.",
"version": "1.1.4",
"version": "1.2.0",
"author": {
"name": "ProofOfWork / Danillo Felix",
"email": "danillo@proofofwork.agency"
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ codex-plugin-cc/
/.mcp.json
.contextrelay/config.json
.contextrelay/current
.contextrelay/rooms.json
.contextrelay/sessions.json
.contextrelay/sessions/
.contextrelay/*.lock
.contextrelay/state/
Expand Down
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,38 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.2.0] — 2026-05-20

### Added
- Added mesh-worker startup prompts so `ctxrelay mesh start` launches default
and named Codex/Claude lanes with an explicit first task instead of relying
on project instructions alone.
- Added state-scoped room and runtime-session registries for port-base and
named-runtime launches, while retaining legacy registry helpers for
compatibility.
- Added strict live daemon identity matching for port-base status reuse, using
daemon identity, pid, instance id, control port, project root, and state dir.

### Changed
- Changed Claude channel arguments to `--channels=<value>` and
`--dangerously-load-development-channels=<value>` so variadic channel flags
cannot consume the mesh startup prompt.
- Defaulted mesh Claude launches to approved-channel loading when
`CONTEXTRELAY_ENABLE_MESH=1` is set, without changing non-mesh launch
behavior.
- Allowed named runtime sessions to auto-enable for read-only mesh lanes, so
read-only workers can start without requiring
`CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1`.
- Allowed read-only mesh lanes to share a worktree with another active runtime
while preserving the existing conflict guard for write-capable lanes.

### Fixed
- Fixed mesh bootstrap flows that could leave workers attached but idle by
making startup work explicit and preserving prompt quoting through the
instance-env shell wrapper.
- Fixed state reuse for alternate port-base launches so live status adoption
cannot accidentally bind to a foreign daemon or project state directory.

## [1.1.4] — 2026-05-19

### Added
Expand Down
88 changes: 83 additions & 5 deletions README.md

Large diffs are not rendered by default.

61 changes: 51 additions & 10 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ For user-facing setup and command details, see [README.md](../README.md). For op

ContextRelay is a local Claude Code + Codex coordination layer. It provides:

- A CLI for setup, launch, diagnostics, coordination policy, viewer, release checks, and shutdown.
- A CLI and native TUI for setup, launch, diagnostics, coordination policy, mesh room/lane control, viewer, release checks, and shutdown.
- A local daemon with loopback-only control endpoints.
- A Claude Code plugin that exposes Claude-side MCP tools and slash commands.
- A Codex MCP server registered explicitly with `ctxrelay codex-mcp install`.
- A Codex app-server proxy for the live Codex TUI bridge.
- A shared session ledger in `.contextrelay/sessions/<sessionId>.jsonl`.
- Opt-in room/lane orchestration with bounded coordinator-worker DAGs behind
the mesh-mode gate.
- A persistent Claude-bound message queue backed by SQLite.
- A local browser viewer for session state, task lanes, artifacts, policy, and timeline. It cannot send agent work, but it can clear the current shared session history through its authenticated history endpoint.
- A local browser viewer for session state, mesh rooms/lanes, task lanes, artifacts, policy, and timeline. It cannot send agent work or mutate room/lane state, but it can clear the current shared session history through its authenticated history endpoint.
- Manual coordinator policy for git ownership: `claude`, `codex`, or `human`.
- Explicit read-only backup-agent requests when autonomy is enabled.

Expand All @@ -39,6 +41,10 @@ ctxrelay permissions status|readonly on|off|allow <capability>|deny <capability>
ctxrelay detach-claude
ctxrelay status [--json]
ctxrelay session list [--archived] | create <id> [--label <text>] [--worktree <path>] | select <id> | archive <id> | rebind <id> [--worktree <path>] [--json]
ctxrelay worktree plan|create|status|remove
ctxrelay mesh status|start|enable|disable
ctxrelay room list|create|view|select|archive|add-member|remove-member|assign-coordinator
ctxrelay lane list|create|view|enter|assign|remove-participant|complete|archive
ctxrelay recover [--json]
ctxrelay instances
ctxrelay viewer [--no-open]
Expand Down Expand Up @@ -77,6 +83,10 @@ backup_status
propose_final
```

Claude-side mesh control tools are intentionally not exposed by default in
v1.2.0 because ContextRelay cannot yet verify whether a call came from a parent
Claude session, a subagent, or a hook.

### Codex MCP Tools

Codex receives these tools after `ctxrelay codex-mcp install`:
Expand All @@ -98,6 +108,21 @@ record_artifact
ask_claude_backup
backup_status
propose_final
mesh_status
create_room
select_room
room_info
archive_room
add_room_member
remove_room_member
assign_room_coordinator
create_lane
enter_lane
lane_info
complete_lane
archive_lane
assign_participant_to_lane
remove_participant_from_lane
```

### Claude Slash Commands
Expand Down Expand Up @@ -139,6 +164,16 @@ Claude Code
-> Codex TUI
```

Mesh-enabled mode adds a gated room/lane control layer above runtime sessions:

```text
Human / coordinator
-> ContextRelay room
-> lane frontend -> runtime session(s)
-> lane review -> runtime session(s)
-> ContextRelay daemon
```

The daemon currently owns several responsibilities:

- Claude foreground attachment tracking.
Expand All @@ -151,10 +186,10 @@ The daemon currently owns several responsibilities:
- Runtime state and liveness reporting.

This is a practical pair-oriented architecture with opt-in named runtime
sessions. v1.1 can launch independent named Claude+Codex pairs inside one
daemon when `CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1`, but transcript ledger,
viewer, backup, and finality state remain mostly global/default-biased. It is
not yet a general room/lane router or unrestricted mesh.
sessions and optional room/lane orchestration. v1.1 can launch independent
named Claude+Codex pairs inside one daemon when
`CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1`. v1.2.0 adds gated room/lane registry and
control surfaces, but unrestricted peer mesh remains out of scope.

## Implemented Messaging Behavior

Expand Down Expand Up @@ -189,6 +224,7 @@ Project state lives under `.contextrelay/`:
```text
.contextrelay/config.json
.contextrelay/sessions.json
.contextrelay/rooms.json
.contextrelay/state/
.contextrelay/current
.contextrelay/sessions/<sessionId>.jsonl
Expand All @@ -203,6 +239,7 @@ The shared ledger stores:
- handoffs
- artifacts
- runtime events
- route decisions
- backup requests and results
- errors
- finality proposals and finality decisions
Expand Down Expand Up @@ -235,8 +272,9 @@ Known limits in the current implementation:
- Named Claude+Codex runtime pairs are opt-in and require
`CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1`.
- The daemon is still tightly coupled to Codex lifecycle/proxy management.
- General room/lane routing, peer mesh, and arbitrary multi-agent routing are
not implemented.
- Room/lane routing is opt-in, single-host, and bounded to coordinator-worker
DAGs. Unrestricted peer mesh and arbitrary multi-host routing are out of
scope.
- Named runtime routing does not yet provide fully isolated transcript ledger,
viewer, backup, or finality state.
- Third-agent adapters and API-backed reviewer workers are not implemented.
Expand Down Expand Up @@ -268,10 +306,12 @@ Improve the implemented architecture without changing the mental model:

### Architecture Direction

The current daemon works for the default Claude + Codex pair plus opt-in named runtime pairs. If ContextRelay grows beyond that into general room/lane routing, the likely architecture is `Instance -> Session(s) -> Participants`:
The current daemon works for the default Claude + Codex pair, opt-in named
runtime pairs, and gated room/lane orchestration. The architecture direction is
`Instance -> Session(s) -> Participants -> Room/Lane scopes`:

- Move toward explicit agent identity instead of singleton Claude/Codex assumptions.
- Add session-scoped routing before adding additional agent types.
- Keep room/lane routing bounded before adding additional agent types.
- Separate runtime adapters from daemon routing responsibilities.
- Keep runtime-specific behavior in adapters, not in the router.
- Make delivery acknowledgments, retry behavior, and offline queue semantics explicit.
Expand Down Expand Up @@ -315,3 +355,4 @@ Before publishing or tagging a release:
6. Run `ctxrelay release-gate --json` when a ContextRelay session is active.
7. Verify README and this roadmap list every public CLI command and MCP tool.
8. Remove stale future-tense claims unless they are explicitly marked as planned or open.
9. Verify `ctxrelay mesh status` reports the expected enabled/disabled state for the release configuration.
80 changes: 75 additions & 5 deletions docs/SESSION-LIFECYCLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

This document defines ContextRelay's runtime-session lifecycle. v1.1.4 implements
registry-backed named sessions plus explicit first-use named Codex/Claude runtime routing
behind `CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1`. General rooms, lanes, mesh
routing, and fully isolated ledger/finality/viewer state remain future work.
behind `CONTEXTRELAY_ALLOW_NAMED_SESSIONS=1`. v1.2.0 adds optional room/lane
orchestration behind the mesh-mode gate. Fully isolated viewer, backup, and
finality state remain future work.

## Model

Expand Down Expand Up @@ -172,9 +173,9 @@ Rules:
- Target finality is per session: one session can be complete while another
remains active.

Open question for implementation: whether the existing `.contextrelay/current`
file remains the active ledger pointer or becomes a compatibility alias for
`activeSessionId`.
The existing `.contextrelay/current` file remains the legacy transcript pointer
in v1.2.0. Mesh active-lane state is tracked in the room/lane registry, not by
repointing `current`.

## Readiness

Expand Down Expand Up @@ -230,6 +231,69 @@ recreated or rediscovered after restart.
Sessions inherit the local instance auth boundary. Session IDs do not create a
separate trust boundary inside one instance.

## Room/Lane Registry

Mesh mode is built on top of runtime sessions. It does not replace
`activeSessionId`, `sessions.default`, `defaultSession`, or the legacy top-level
status fields; those compatibility fields remain until `v2.0`.

Runtime session entries in `.contextrelay/sessions.json` may include
`transcriptSessionId?: string`. When present, it points to the canonical
transcript ledger id for that runtime session. Missing values preserve the
v1.1.4 compatibility path. Friendly runtime, room, and lane names are registry
ids only; transcript files still use canonical ids such as
`session_<timestamp>_<suffix>`.

The mesh registry lives at `.contextrelay/rooms.json` and is written atomically
under a lock, mirroring the session registry pattern. Its top-level shape is:

```json
{
"schemaVersion": 1,
"instanceId": "project-instance-id",
"activeRoomId": "review",
"activeLaneByParticipant": {
"default:codex": { "roomId": "review", "laneId": "frontend" }
},
"rooms": {
"review": {
"id": "review",
"instanceId": "project-instance-id",
"status": "open",
"coordinatorParticipantId": "default:codex",
"reviewerParticipantId": "default:claude",
"createdAt": "2026-05-19T00:00:00.000Z",
"members": [],
"lanes": {
"frontend": {
"id": "frontend",
"status": "open",
"assignedParticipantIds": ["default:claude"],
"permissions": ["read", "write", "git"]
}
}
}
}
}
```

Rooms use `status: "open" | "paused" | "archived"`. Lanes use
`status: "open" | "complete" | "archived"`. Write-capable lanes require an
assigned worktree and cannot share that worktree with another open
write-capable lane.

Coordinator drop semantics are fail-closed: when a room's coordinator
participant disconnects or is removed, the target state is `status: "paused"`
with `pausedReason: "coordinator-dropped"`, pending approvals are rejected, and
no silent re-election happens. v1.2.0 includes the manual room-pause registry
primitive; automatic coordinator-disconnect detection and approval rejection are
follow-up hardening work. A human or coordinator-authorized CLI action must
resume or reassign.

Unknown routing fails closed. Messages targeting unknown room or lane IDs on
write paths are rejected. Missing room/lane scope remains the N=1 compatibility
path and targets the default runtime lane.

## Migration Order

1. Keep N=1 behavior and expose `sessions.default`.
Expand Down Expand Up @@ -307,6 +371,12 @@ separate trust boundary inside one instance.
default session bypasses the guard in both directions, archived sessions are
ignored, and killed runtimes stop blocking once removed from daemon runtime
state. Override semantics remain a later slice.
17. Add the room/lane layer above runtime sessions. `ctxrelay mesh`, `ctxrelay
room`, and `ctxrelay lane` manage gated room/lane registry state in
`.contextrelay/rooms.json`. When mesh is disabled, all existing N=1 and
named-session behavior is unchanged. When mesh is enabled, room/lane tools
resolve friendly registry IDs to canonical transcript session IDs through
`sessions.json.transcriptSessionId` and explicit lane scope.

Each step must preserve the top-level status fields until a major-version break.

Expand Down
Loading
Loading