Skip to main content
Glama
README.md
# OMP Tandem

**Give your coding agent an independent AI peer.**

Consult, design, implement, and review together through [Oh My Pi](https://github.com/can1357/oh-my-pi), with persistent conversations and project-isolated MCP tools.

**English** · [Русский](README.ru.md) · [简体中文](README.zh-CN.md)

[![CI](https://github.com/Flyozzzz/omp-tandem-public/actions/workflows/ci.yml/badge.svg)](https://github.com/Flyozzzz/omp-tandem-public/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Python 3.12+](https://img.shields.io/badge/Python-3.12%2B-blue.svg)](pyproject.toml)

[Quick start](#quick-start) · [Jev assistance](#jev) · [Full guide](docs/guide.md) · [Releases](https://github.com/Flyozzzz/omp-tandem-public/releases) · [Contributing](CONTRIBUTING.md)

## Why OMP Tandem?

A second agent should do more than approve the first agent's work. OMP Tandem lets your coordinator ask for independent reasoning, explore alternatives, delegate a separate implementation slice, and compare findings against evidence.

- **Real OMP, your provider.** Uses the official `omp_rpc` client and `omp --mode rpc`, not a substitute direct-API wrapper.
- **Proportional planning.** Independent assessment, one comparison, a concrete plan, then implementation and cross-checking—not a fresh whole-project audit for every local fix.
- **Persistent conversations.** Continue a discussion while replacing the current goal and preserving its base constraints.
- **Scoped knowledge.** Separate project histories, optional versioned product rules, and explicit cross-project sharing.
- **Honest results.** Structured outcomes, questions with deadlines, and recoverable intermediate artifacts.
- **Version-bound reviews.** Choose worktree or staged-only material, then use independent-first comparison, stale-result detection and finding history. [Review workflow](docs/guide.md#immutable-review-bundles).
- **Bounded waiting and visible usage.** Claude watchdog with polling fallback, explicit live diagnostics, and depth/budget settings separate from permissions. [Profiles and usage](docs/guide.md#computation-profiles-and-usage).
- **Portable integration.** Claude Code plugin, Agent Plugins package for Codex, and ordinary local stdio MCP for other hosts.
- **Optional Desktop QA handoff.** Send UI tests to an already authorized desktop session; wait in server code and receive terminal events without model polling. Requires an external queue backend, not an autonomous GUI launcher. [Setup and limits](docs/guide.md#desktop-session-qa-handoff).
- **Optional Jev assistance.** Report audits, candidate suggestions, shadow model routing and reversible context/tool/output focus. Explicit export approval; no automatic acceptance or model switching. [Availability and setup](#jev).

No company-specific policies or hardcoded project paths are bundled.

## Quick start

### 1. Install the prerequisites

Requires **macOS/Linux**, or **WSL with Linux tools**, plus `uv` and OMP on `PATH`.

With Homebrew:

```sh
brew install uv
brew install can1357/tap/omp
omp setup
```

Use OMP's setup flow to authenticate your own supported provider and select a tool-capable model. The host agent has its own separate login. For Linux/standalone installation, API keys, OAuth, and local models, see the [setup guide](docs/guide.md#install-omp-and-configure-a-provider).

### 2. Install for your host

**Claude Code**

```sh
claude plugin marketplace add Flyozzzz/omp-tandem-public
claude plugin install omp-tandem@omp-tandem
```

**Codex CLI**

```sh
codex plugin marketplace add Flyozzzz/omp-tandem-public
codex plugin add omp-tandem@omp-tandem --json
```

Start a new session from your project's directory. Do not keep an old standalone registration enabled alongside the plugin. This repository is public; no invitation is required.

Python dependencies are prepared automatically in a private cache. OMP installation and provider authentication remain explicit user setup. Other clients can use the [standard MCP configuration](docs/guide.md#other-mcp-clients).

### 3. Check this project's setup

In Claude, run `/omp-tandem:setup` and ask for **local diagnosis only**. Confirm that Tandem is bound to your project, not the plugin/cache directory, and inspect runtime and delivery prerequisites. This does not call a model or prove provider authentication; a separate live diagnostic is optional and needs your approval.

### 4. Review your prepared commit

Stage the intended changes, then use `/omp-tandem:tandem` or ask in natural language:

> Use OMP Tandem to review my prepared commit, using staged changes only. Use this task's requirements and acceptance criteria; ask me if they are missing. Do not edit files. Report correctness risks with evidence and identify missing context.

The agent uses `tandem_review_run`: a saved staged/index snapshot, one independent read-only assessment and at most one comparison with separately supplied author rationale. It does not edit files or run supplied test commands. Missing source context requires a fresh expanded snapshot, not live files added to an old review. [Review details](docs/guide.md#one-read-only-review-scenario).

### 5. Give both agents one shared task

> Use OMP Tandem to agree a shared task for this feature. Record the goal, constraints, acceptance criteria, module owners and distinct reviewers. Split independent modules, add a final integration step, and keep the checklist and blockers current. Do not launch unattended work until I grant its limits.

`tandem_work` exposes the same durable card to both participants, including a readable Markdown view. Work survives a conversation ending; **a saved task is not a running agent**. Existing-client work is manual; opt-in unattended execution uses a separate bounded controller, dedicated Claude/OMP attempts and isolated Git worktrees. Accepted results are not silently merged into your current branch. [Shared-task workflow and operator commands](docs/guide.md#shared-tasks).

## Two entry paths

- [Staged review](docs/guide.md#one-read-only-review-scenario): independent assessment of a saved snapshot.
- [Shared development and operator grants](docs/guide.md#shared-tasks): plan, ownership, exact submissions and distinct review. Claim/submit require the bound Git root with HEAD; task `cwd` cannot repair that boundary. Unattended launches need explicit operator authorization. Shell is arbitrary execution, not a sandbox; reports are not acceptance.
- [Migration and disabled helpers](docs/helper-compatibility.md): no migration restarts work or retroactively makes a review independent.

## Compact state and recovery

See [compact views, runtime identity and recovery](docs/guide.md#compact-contracts) and [operator blocker resolution](docs/guide.md#operator-unblock). Hints and notifications grant no authority; resolving a blocker never resumes or authorizes work. Independent acceptance is separate from operator application and publication.

Latest published release: **[3.21.1](https://github.com/Flyozzzz/omp-tandem-public/releases/tag/v3.21.1)**. Long tasks stop dying when OMP compacts context with the provider.

**New in 3.21.1:** OMP can compact a long conversation on the provider side and reports it as an `auto_compaction_start` event with the action `remote`. The pinned OMP RPC SDK accepted only `context-full`, `handoff`, `shake` and `snapcompact`, raised `RpcError` on the new value, and the worker exited right after the compaction was written, losing the work and leaving a held `tandem_work` step in `recovery_required`. The SDK pin moves to OMP 18.18.3, whose wire schema accepts `remote`, and a regression test now rejects any pin that does not. Tasks already failed this way are recovered through the usual operator path (`pause`, `reconcile --resolution retry --confirm-stopped`, `resume`).


**New in 3.21.0:** answers recorded on a blocker now reach the next implementation attempt. The briefing contained no blockers at all, and the card a worker reads lists only unresolved ones, so an operator's answer was stored and invisible on every route the worker took: in one measured card three consecutive attempts asked the same question and blocked, spending over $4 for no output. `resolved_decisions` delivers the question, the answer, its evidence and who gave it, for the attempt's own plan revision, attributed as a record and never as permission; an independent review stage still receives none of it. A heartbeat no longer increments the card's CAS revision or writes a history event, so `revision_conflict` stops being the normal outcome of a slow request and a long bounded wait stops waking with nothing to read. An attempt that stopped on a question it recorded now settles as a cooperative block even when the operator answered first, instead of falling into `recovery_required`. The `unblock` operator template carries the `--operation-id` the CLI requires, derived rather than random so a paged read does not stale its own cursor. The shell-grant refusal names the authority for the condition that actually refused, channel status no longer reads as though it could attest wake coverage, and who attested that an attempt stopped is recorded rather than always credited to the supervisor.

**New in 3.20.0:** `tandem_review_run(action="start")` takes `request_file`, a path inside the launch project holding the same `ReviewRequest` as JSON, with a required `request_sha256`; the contract is assembled by ordinary code and only its locator passes through the model. Measured on one 21-hour pipeline run, the request serialized to 102,598 characters of tool input, the coordinator spent 4m20s and 5m45s emitting it twice, and it had shortened its own requirements to a literal `[cut: 20986 more characters]` although the field accepts 200,000. Transport is not identity: the materialized request, the capture and every fingerprint match the inline form, and editing the file afterwards cannot change an accepted run. `blocked_on` now projects the clarifications an independent stage could not accept — stored text, `requested_paths`, `requested_material` and a `parse_status` — with its core and `findings_counts` protected from response compaction, so a partial result stops reading as though it produced nothing and names its own repair. A capture equivalent to an earlier run that ended still needing context is refused before any reviewer starts; any other equivalent one is allowed and only reports `prior_equivalent_run`, because identical bytes are not a cached verdict.

**New in 3.19.0:** `WorkPlan.repository` names the card's Git working tree as a directory relative to the launch project root; `null` is the launch root, which is what every card was before. A session opened at a parent directory can keep a card in a checkout below it — `_repos/main-pipeline` under a WBS root — without moving its data namespace, which is still bound by the client launch project. Owned files, declared-path observation, the pinned HEAD of a manual claim, submitted commits, review capture and `apply --expected-head` all follow that choice. It changes through the ordinary propose/activate path while the card is open, and is fixed permanently at the first claim or authorization; the lock never clears, and an older card with execution history counts as locked. This release supports the manual path only — claim, commit there, submit that hash, have the reviewer accept it, apply with the operator CLI; unattended authorization, managed worktrees, automatic capture, native dispatch and team execution of such a card are refused by name rather than half-done.

**New in 3.18.0:** a managed work grant already bounded itself with `max_launches`, but nothing bounded the other paths: a new task ID, a recapture without a declared `corrective` link, or an MCP restart each began again from zero. The automation ledger spends one admission per newly admitted unit — a review run with its capture, independent stage and any comparison; a native task; a team step; a managed attempt — and refuses the next when the grant is used up. Turning it on requires an explicit finite `--max-admissions`, with no default: one measured project spent 81 review runs in a week, so any shipped number would refuse honest work somewhere else. Exhaustion stops only *new* admissions; admitted work finishes and saves. Operator-only via `work_daemon … budget`, never reachable from a worker or MCP tool. It bounds this plugin's entry points, not arbitrary processes, and being default-off it does not by itself stop a spiral — it provides the mechanism.

**New in 3.17.0:** `WorkPlan.project_context_id`. `TeamPlan` has carried a pinned context for several releases; a shared plan could not, so an implementer received only free-text `context`. The ID must already exist in this project — no `latest` resolution, and an unknown ID is refused at `create`/`propose` before any work is admitted. An independent snapshot review never receives the binding, because `require_review_context_capture` refuses product context for an independent stage. Plans that pin nothing keep their stored operation receipts unchanged.

**New in 3.16.0:** rounds of discussion were already bounded ("after two rounds decide") while verification was bounded by nothing, so more checks always looked free and always looked safer. Coordinator instructions and the tandem skill now state that the declared ladder is the ceiling as well as the floor: a finding does not widen it by itself, mutation and fuzzing are a choice justified by a named risk rather than every task's ritual, and a fix round rechecks changed behaviour instead of everything. `correction_round` on a review run and its summary gives the depth of the declared correction chain. Only declared links count, so a recapture without `corrective` starts again at 1 — a low round is not proof of little rework, and a high one is not proof of waste.

**New in 3.15.0:** `comparison_requested`/`comparison_skipped` on review runs, so a comparison that was asked for and never ran is no longer reported as a plain one-stage success; and `result.verification.plan_deviation`, which reads the already-stored check runs the ladder assessment discards and names unmapped and repeated executions with the seconds actually recorded. Both are added fields over unchanged behaviour: they report, and refuse nothing.

Version 3.13.0 introduced long bounded waits, server-enforced handling of unanswered clarifications, operator cleanup of abandoned managed worktrees, and the opt-in [whole-brief protocol](docs/guide.md#carry-a-whole-brief). See the [changelog](CHANGELOG.md). Updating the repository does not restart existing work or authorize new execution.

**New in 3.14.0:** bounded task/review readers, a reserved think-only coordination lane, current-evidence coverage for local/global shared-work requirements, durable pinned-brief decisions, a read-only recovery inbox and source-bound review-context suggestions. [Reader/inbox/capacity contracts](docs/guide.md#compact-contracts), [work coverage](docs/guide.md#declared-acceptance-evidence), [decision workflow](docs/guide.md#carry-a-whole-brief). Stop incompatible MCP processes and back up state before upgrading to schema 2. Updating files does not replace a running server, restart work or grant authority; old compatibility reports remain historical.

<a id="team-mode"></a>
## Team mode

Ask the coordinator to split development, research or review into a team. `tandem_team`
runs 2–16 planned steps followed by a final integration step. Since 3.14.0,
three ordinary slots run work; the fourth is reserved for explicit read-only coordination.
It queues file conflicts, preserves partial results and cancels pending and active work
without replaying uncertain execution. Work stays in the live project; this is not a sandbox.
Assigned workers no longer wait for unrelated model choices. Read-only research can
opt its final `think` step into `dependency_policy="reported_evidence"` to summarize
structured partial evidence while retaining an overall `partial` outcome. Development
dependencies remain success-only. Status replies are bounded, with lossless paged recovery.

The model pool is **only OMP-available `openai-codex` subscription models**.
OpenRouter, ordinary OpenAI API and other providers are excluded. With an
`OPENROUTER_API_KEY`, Jev automatically advises on roles and model assignments;
that key is for Jev, not a source of worker models. Each assignment includes the
model and its supported `thinking` level; explicit choices win.
Without Jev or a confident choice, the coordinator consults its OMP peer and
submits an agreed assignment from the same eligible pool.

Disable Jev globally with `--jev off` / `OMP_TANDEM_JEV=off`, or use
`plan.model_selection="coordinator"` for a team that sends no summaries to Jev.
Auto classification exports the declared goal/title summaries and public model
facts, not source files, contract context or histories. [Protocol and examples](docs/guide.md#team-mode).

<a id="jev"></a>
## Optional Jev assistance and shadow routing

Jev is a separate, optional structured-decision service—not the model that performs
the coding task. **Recommendation, shadow-routing and focus are new in 3.12.0
and absent from 3.11.0 and earlier.** Inspect the loaded
runtime's `tandem_scope` capabilities before using them.

| Capability | Purpose | Availability |
|---|---|---|
| `tandem_audit` | Flag gaps between acceptance criteria and reported evidence | 3.11.0 and later |
| `tandem_recommend` | Suggest one caller-supplied skill or review direction before task creation | 3.12.0 and later |
| `execution.routing` | Compare a task-start model suggestion with the unchanged execution model | 3.12.0 and later, **shadow-only** |
| `execution.focus` | Rank optional context, defer permitted native tool schemas and retrieve exact focused excerpts | 3.12.0 and later |

Audits and recommendations support exact keyless previews. A runtime OpenRouter
key automatically enables recommendations unless disabled; `--jev-recommend`
remains an explicit enable switch. Report audits still require `--jev-audit`.
Recommendation sends additionally require the approved preview's matching hash.
Advice and confidence are not verified correctness or permission.

For **shadow model routing**:

1. The operator provides two or three exact models in a policy file through
   `--jev-routing-policy PATH` or `OMP_TANDEM_JEV_ROUTING_POLICY`.
2. Both the policy and the task's `execution.routing` must explicitly approve
   export of a short summary. No summary is inferred from prompts, files or history.
3. Code checks the catalog, capabilities, declared context/output estimates and
   optional estimated cost ceiling. An isolated metadata-only probe keeps catalog
   stalls separate from the execution process.
4. Jev may suggest an eligible model, `none`, or `unclear`. The task still uses its
   original model; `tandem_result.execution.routing` records the proposal, reason,
   routing time and separate Jev usage.

Explicit model choices, continuations, snapshot reviews and managed work bypass
the router. It never changes thinking, tools, roles, grants or acceptance. An
ordinary routing failure preserves the original selection; uncertain sends are
not retried. Missing `OPENROUTER_API_KEY` produces an explicit bypass.

**Context/tool/output focus** requires `--jev-focus-policy PATH`, approved data
classes and explicit `execution.focus` export consent for the current task.
Required context and permissions stay fixed; omitted material remains recoverable.
Focused readers return exact, nonexhaustive excerpts—not generated summaries.
This does not compact native history or select arbitrary outside-host tools.

Local RPC/HTTP and pinned-OMP checks verify the exercised boundaries. Small live
synthetic Jev runs succeeded; **general accuracy, speedups and cost savings are
not established**. Deferred schemas can shrink the first request while increasing
the complete interaction. See the [audit guide](docs/guide.md#optional-jev-evidence-audit),
[candidate recommendations](docs/guide.md#optional-jev-candidate-recommendation-unreleased),
[shadow routing](docs/guide.md#task-start-shadow-model-routing-unreleased)
and [focus configuration and measurements](docs/guide.md#optional-jev-context-tools-and-output-focus-unreleased).

## Plan changes and repository handover

See [plan transitions](docs/guide.md#plan-transitions) for stop evidence, saved checkpoints, capture-failure acknowledgments and fresh authorization; [repository handover](docs/guide.md#repository-handover) for boundary diagnostics and explicit closure/provenance commands.

Only the operator drives transitions and execution reconciliation. Supervisor teardown proves process stop, not absence of external effects. Never replay uncertain effects. Cross-scope links transfer no access, agreements, grants or acceptance; review the exact result in its own scope before explicit application.

## How it works

```mermaid
flowchart LR
    A[Coding agent] <-->|MCP stdio| T[OMP Tandem]
    T <-->|official omp_rpc| O[Oh My Pi]
    O <--> M[Your configured model]
    T <--> D[(Project data)]
```

| Mode | Use it for | Project access |
|---|---|---|
| `think` | Consultation and reasoning over supplied context | No project/shell tools; collaboration tools remain available |
| `analyze` | Investigation and review | Read/search/web search; no edits or shell |
| `work` | Explicitly authorized implementation | Edit/write/shell and related tools; **not a sandbox** |

New tasks create independent conversations. Follow-ups retain native OMP history but replace the current objective. Questions and intermediate artifacts keep uncertainty visible instead of turning missing information into assumed success.

## Evidence, not a promise

In our [real review case](docs/case-study.md), the first attempt was blocked by missing context (**80.558 s wall time**). An expanded review found a real deadline/cancellation bug, but its **300 s total budget** ended in a timeout after **331.723 s wall time**. A focused recheck completed in **186.127 s wall time** and identified a distinct **shared-SQLite publication-lock risk**, not yet runtime-verified in that episode. Completion is not proof of bug-free code; the case preserves failures and remaining uncertainty.

The publication-lock risk was then reproduced and fixed before release; the case separates that passing runtime follow-up from the original static report.

[Compatibility checks](docs/compatibility.md) use an actual pinned OMP binary and RPC SDK with a deterministic **localhost provider** in CI—no paid account is needed. Evidence applies to the exact tested combination, not a broad version range or every provider. The [benchmark document](docs/benchmark.md) is a comparative protocol only: **no comparative results or superiority claim**.

## Boundaries that matter

- Project data is bound to **trusted client workspace information**, never a task's model-supplied `cwd`. Foreign IDs do not open another project's history.
- The package does **not** sandbox processes with your OS permissions. Host shell sandbox settings do not automatically constrain an external OMP process.
- Reports are claims, not independent acceptance. `completed` does not prove `success`.
- Optional hooks diagnose prerequisites and provide a bounded Claude watchdog; they never install tools, read provider credentials, approve permissions, or replace polling when unavailable.
- Polling works without Channels. Claude push/webhooks are optional and remain subject to client and organization policy.
- Local storage is not offline inference: configured providers receive task context.

Read the [security policy](SECURITY.md) before reporting a vulnerability. Never include credentials, private conversations, or runtime databases in issues or pull requests.

## Documentation

| Topic | Reference |
|---|---|
| Installation, providers, and clients | [Complete guide](docs/guide.md) |
| Start Claude and the webhook with one short command | [Set up `claude-tandem`](docs/guide.md#one-command-launch) |
| Tasks, modes, results, questions, and artifacts | [Task workflow](docs/guide.md#tasks-and-execution-modes) |
| Product rules and decisions | [Product knowledge](docs/guide.md#product-knowledge-and-decisions) |
| Workspace isolation and explicit sharing | [Project isolation](docs/guide.md#project-isolation) |
| All MCP tools and limits | [API reference](docs/guide.md#mcp-tools) |
| Jev audits, candidate advice and shadow model routing | [Jev assistance](#jev) |
| Local data upgrades and migration | [Upgrades and legacy history](docs/guide.md#upgrades-and-legacy-history) |
| Claude Channels, webhook protocol, and managed setups | [Channels reference](docs/channels.md) |
| Development and contributions | [Contributing](CONTRIBUTING.md) |

Full guides are also available in [Russian](docs/guide.ru.md) and [Simplified Chinese](docs/guide.zh-CN.md).

## Development

```sh
uv sync --frozen --group dev
uv run pytest -q
uv run --frozen ruff check .
uv run --frozen ruff format --check .
uv build --wheel
```

`pytest` is a declared development dependency; `uv` installs the project package and its `omp_rpc` dependency into the same environment. Tests use temporary stores and local fault peers, not provider credentials. CI runs pytest, Ruff, wheel building, and distribution checks on Linux and macOS.

This repository begins with a reviewed snapshot of earlier private development. The **3.x** version series preserves that lineage without importing its Git history. “Legacy history” refers to local OMP conversation data, not hidden Git commits.

## License

[MIT](LICENSE), copyright (c) 2026 Flyozzzz. Commercial use, modification, and redistribution are allowed with the copyright and permission notice retained. The software is provided **AS IS**, without warranty. Dependencies keep their own licenses.

TDQS

B3.4/5.0

Scored across 28 tools

Disambiguation3/5

The tools cover distinct workflow modes, but several boundaries are easy to confuse: start/continue/team/review_run/desktop all initiate work, while result/wait/read_result/overview/read_artifact all observe or retrieve output. tandem_decision vs tandem_reply and tandem_review vs tandem_review_run add further overlap. The detailed descriptions help, but agents must carefully choose among similar coordination surfaces.

Naming Consistency3/5

All names use a consistent tandem_ prefix and snake_case, which makes the set readable. However, conventions are mixed: some names are verb-first (read_artifact, publish_artifact, export_context), others are noun-first (context_read, review_run, project_context), and several are bare resource names (team, desktop, scope, receipt, findings). The pattern is recognizable but not consistently verb_noun.

Tool Count2/5

With 28 tools, the surface is heavy for an MCP server and exceeds the manageable range even for a complex orchestration product. Many distinct workflows justify breadth, but the count increases selection burden and makes overlapping observation, review, and context tools harder to navigate.

Completeness4/5

The server covers a broad lifecycle: task start/continue/cancel, waiting/replies/results, review capture and findings, project context, artifacts, team/desktop workflows, notifications, diagnostics, and receipt gating. Gaps are minor, such as artifact discovery/listing and the fact that some grant/reconciliation operations are intentionally CLI-only. Overall it is a fairly complete coordination surface for the stated domain.

Maintenance

ActivityActive
ResponsivenessNo recent community issues