Codex thinks. Claude builds. Codex attacks. Claude repairs. Duet proves.
Duet is a local-first native desktop orchestrator for the Claude Code and OpenAI Codex CLIs. It uses the coding-agent subscriptions already authenticated on your computer—never the Anthropic API or OpenAI API—and isolates every implementation in a temporary Git worktree until you explicitly apply it.
flowchart TD
U[User task] --> I[Inspect Git repository]
I --> A[Codex · Architect]
A --> B[Claude · Implementer]
B --> V[Duet · Tests and benchmarks]
V --> R[Codex · Adversarial reviewer]
R --> D{Verified and approved?}
D -- yes --> Done[Verified result]
D -- no --> C[Claude · Repair]
C --> V
The machine has the final say. A positive model review never overrides a failing required check.
- Add and inspect local Git repositories, including branch, SHA, dirty state, language, build system, and suggested tests.
- Detect the locally installed
claude,codex, andgitexecutables and inspect authentication status where the CLI supports it. - Create one app-managed branch and worktree for every run. Normal agent edits are directed to that isolated worktree.
- Stream typed lifecycle events and stdout/stderr from cancellable, timeout-bounded Tokio subprocesses.
- Run Codex as architect/reviewer and Claude as implementer/repairer through supported headless CLI modes.
- Choose Duet, Codex-only, or Claude-only routing and configure each active agent's model and reasoning effort.
- Discover installed Codex models and their supported reasoning levels through the official local Codex App Server protocol.
- Ask a repository-aware Codex assistant questions through streamed App Server turns in a read-only sandbox.
- Run project commands in a streaming, cancellable Console and inspect loopback development servers in a sandboxed Preview panel.
- Run a required test/build command and any configured benchmark independently of model opinion. Checks are serialized by default; users can opt into parallel execution when their commands do not share mutable artifacts.
- Repeat review/repair up to a user-selected bound and stop on repeated no-op repairs.
- Persist projects, runs, stages, raw output, normalized output, verification, reviews, changed files, and events in SQLite.
- Reopen historical runs after restart; active runs become
interruptedrather than incorrectly appearing complete. - Inspect a live timeline, activity, changed files, unified diff, tests, structured review, and raw logs.
- Choose a preferred editor in Settings and open only registered projects or Duet-managed run worktrees through a backend-validated handoff.
- Explicitly apply a binary Git patch only after checking that the target SHA is unchanged and its working tree is clean.
- Run a complete no-usage development flow with Mock agents enabled.
Duet has no Duet cloud service and contains no OpenAI or Anthropic API client. Run history, logs, and managed worktrees remain in the operating system's application-data directory. The official local agent CLIs receive the task, relevant source context, and diffs and may make their normal service connections under their own terms and authentication.
Only add repositories you trust. Duet constrains Codex with its CLI sandbox and runs Claude in safe mode from the managed worktree, but it is not an operating-system security boundary against malicious repository instructions, hooks, tools, or configuration.
Duet does not automatically merge, commit, push, force-update, or mutate a remote. Removing a project only removes it from Duet. Discarding a run checks that its path is inside Duet's managed worktree directory before asking Git to remove it.
- macOS 12 or newer (Apple Silicon build documented here)
- Node.js 20 or newer and npm
- Rust stable toolchain
- Git
- Claude Code CLI
- OpenAI Codex CLI
Verify the tools:
git --version
claude --version
codex --versionInstall Claude Code using Anthropic's official instructions, run claude, and complete its official subscription login flow. Confirm with:
claude auth statusDuet does not accept or store an Anthropic API key.
Install Codex using OpenAI's official instructions, then use its ChatGPT subscription login:
codex login
codex login statusDuet does not accept or store an OpenAI API key.
git clone https://github.com/atkunja/duet.git
cd duet
npm install
npm run tauri devFrontend-only production compilation:
npm run buildNative tests and checks:
cargo test --manifest-path src-tauri/Cargo.toml
cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets --all-features -- -D warningsFrontend tests:
npm testCreate the native application and DMG with:
npm run tauri buildOn Apple Silicon, locally ad-hoc-signed artifacts are written to:
src-tauri/target/release/bundle/macos/Duet.app
src-tauri/target/release/bundle/dmg/Duet_0.1.0_aarch64.dmg
Local builds are automatically sealed with an ad-hoc hardened-runtime signature, so codesign --verify --deep --strict succeeds. Public distribution still requires an Apple Developer ID certificate and notarization.
Create a tiny repository:
mkdir /tmp/duet-example
cd /tmp/duet-example
git init
npm init -y
printf 'export const add = (a, b) => a + b;\n' > index.js
git add .
git commit -m "initial example"Open Duet, choose Add a repository, select /tmp/duet-example, enable Mock agents, enter Document the project, and run it. Duet creates an isolated worktree, adds DUET_MOCK_RESULT.md, verifies the configured command, obtains a mock structured review, and displays the patch without touching /tmp/duet-example.
A realistic live-agent task might be:
Add bounded concurrent job execution with graceful shutdown, cancellation tests, and backwards-compatible configuration.
Leave Mock agents disabled. Codex will inspect and plan, Claude will implement, Duet will execute the repository's tests, and Codex will review the resulting diff before any repair round.
Duet auto-detects common Cargo, Node, Python, Go, CMake, Maven, and Gradle projects. Commands can be overridden in the task composer. The internal models are ready for a repository-level duet.toml; an example is provided in duet.toml.example.
React / TypeScript
typed commands + structured Tauri events
│
Rust / Tauri / Tokio
├─ agent adapters (Claude and Codex JSONL normalization)
├─ fail-closed Codex App Server runtime, model discovery, and streamed threads
├─ dependency-enforcing task graph with dynamic repair rounds
├─ cancellable process-tree and Console streaming
├─ deterministic verification
├─ Git repository/worktree safety
└─ SQLite state and restart recovery
│
app-managed Git worktree
The backend validates project identity and serializes repository mutations before running a user-entered Console command; frontend JavaScript never receives unrestricted process handles. Role prompts are separate and agent adapters share a common Agent trait, so routing can evolve without rewriting the workflow core.
On macOS, Tauri resolves Duet's application data under the normal per-user Application Support location. It contains:
duet.sqlite3
worktrees/<run-id>/implementation/
No state is scattered into a selected repository except files an agent intentionally changes inside the isolated worktree. A future release will read an optional duet.toml from the repository.
- CLI missing: Open Settings & Doctor and confirm the executable path. Launching Duet from Finder can have a narrower
PATHthan your shell; support for manual executable selection is planned. - Authentication unknown: Run
claude auth statusorcodex login statusin Terminal. Some CLI versions do not expose a machine-readable status. - Worktree creation fails: Ensure the repository has at least one commit and no conflicting
duet/run-*branch. - Run start is blocked: Commit or stash changes in the original repository first. Duet deliberately starts from a clean, recorded commit.
- Apply is blocked: The original repository must still be on the run's base commit and have a clean working tree. This is intentional.
- Run interrupted: The prior process cannot be reattached after an application exit. Duet preserves its worktree and marks the run interrupted.
- V1 targets macOS and emits a unified diff; side-by-side diff mode is not yet included.
- Public macOS distribution still requires a Developer ID certificate, hardened runtime signing, and Apple notarization; local builds are ad-hoc signed.
- Repositories and their local configuration must be trusted; the Claude CLI safe mode is not an OS-level write sandbox.
- CLI authentication detection depends on each installed CLI's status command and may report “not detectable.”
- Agent escalation (Codex implementing after repeated Claude failures) is represented by role-independent adapters but is not exposed as an automatic policy yet.
- The integrated Codex assistant is intentionally read-only and ephemeral; file changes still go through a verified Duet run.
duet.tomlis documented and modeled conceptually but GUI command overrides are the active configuration path in V1.- Benchmark output is retained generically; metric-specific latency/throughput parsers are future work.
- Interrupted OS processes are terminated by application shutdown and cannot be resumed; only their state and worktree are recovered.
Keep the local-first and worktree-safety invariants intact. New agent integrations must use official local CLIs, persist raw and normalized output, remain cancellation-aware, and have tests that do not consume agent subscriptions. Run all frontend and Rust tests before opening a pull request.
MIT. See LICENSE.