Let Claude Code and Codex hand work to your other coding agents, in your real project, and keep the conversation going.
You talk to Claude Code or Codex as usual. When you want a second opinion, a parallel pair of hands, or simply another model, say so: "ask Grok to review this", "have Droid fix the failing tests". Turnweft starts that agent in the same project folder. The agent reads and changes the real files, and the result comes back to your conversation. Ask a follow-up tomorrow and you reach the same agent session, which still remembers the earlier work.
Supported agents: Dim, Droid, Grok, OpenCode and agy.
Status:
0.1.0-alpha, macOS only. It works end to end with all five agents in both Claude Code and Codex, but expect rough edges. Changes are listed in CHANGELOG.md.
If you use more than one coding agent, you probably know the routine:
- You copy code and context from one tool into another, then copy the answer back.
- The second agent works on a copy or in a separate folder, so its changes have to be moved over by hand.
- Coming back later means starting a new chat and explaining everything again.
- Each agent has its own plugin, and each plugin behaves a little differently.
Turnweft replaces that with one way of working. You stay in the assistant you already use, the other agent works where your code actually lives, and every session can be picked up again.
These conversations are illustrative; real wording depends on the agents and models you use.
You (in Claude Code): Ask Grok to review the login changes I just made. Don't change anything.
Claude: Grok looked at
src/auth/session.tsandsrc/auth/login.tsand flags two issues. The session token is compared with==instead of a constant-time check. A failed login doesn't reset the attempt counter. Want me to have Grok fix them, or should I?
Grok read the real files in your project. Because you asked for a review, it changed nothing.
You: Have Droid fix the failing tests in
test/math.test.js, then tell me what it changed.Claude: Droid fixed both bugs. Changed in this turn:
src/math.js. Your own uncommitted edit toNOTES.mdwas already there and was left alone. I ran the tests myself: 2 passed, 0 failed.
Turnweft compares git snapshots taken before and after the turn, so it can list files that changed during the turn separately from changes you already had. It can't tell who made a change: if you edit the same folder while an agent works, your edits show up too. The plugin also tells Claude to run the tests itself rather than take the agent's word for it.
You (the next morning): Ask the same Droid session why it changed the rounding.
Claude: Droid says the old code used
Math.floor, which rounds negative numbers the wrong way for this function, so it switched toMath.trunc…
Each Turnweft session is tied to the agent's own session. When an idle agent is stopped to save resources, the next question resumes that exact session. It never starts a fresh one that has forgotten everything.
The first time an agent needs more than reading in a project, such as editing files and running commands, a macOS dialog asks you. It names the agent, the project and exactly what the agent will be allowed to do. You click Allow once for that agent, project and kind of task, and the waiting task starts by itself. If your Claude Code conversation runs in bypass permissions mode, or your Codex thread has full access, Turnweft takes that as your answer and doesn't ask.
- Install once. Run
npm install -g turnweft, then add the plugin to Claude Code and/or Codex (see Quick start). - Ask in plain language. For example: "Ask OpenCode how this module is structured" or "Have agy implement the CSV export". There are no new commands to learn.
- Confirm once if asked. A dialog may appear the first time an agent edits files in a project. It waits for you, and silence never counts as "no".
- Check the result. You see the agent's answer, the files that changed during the turn, and the permission mode it actually ran with. The plugin tells Claude or Codex to verify the work, for example by running the tests, before calling it done. An agent saying "done" is a claim, not proof.
- Follow up anytime. Ask the same agent again, minutes or days later, and it remembers the earlier work.
- Stay in control. You can cancel a running task, list or revoke past permissions, and see exactly what each agent was allowed to do.
- People who already use Claude Code or Codex and also have accounts with other coding agents.
- People who want a second model to review or double-check work without copy-pasting.
- People who want to spread work across agents, quotas or models while one conversation stays in charge.
Requirements:
- macOS
- Node.js 22.13 or later
- The command-line tool of each agent you want to use (
dim,droid,grok,opencode,agy), already signed in
npm install -g turnweft
turnweft doctor # shows which agents were found; starts no model taskClaude Code:
claude plugin marketplace add handong66/turnweft
claude plugin install turnweft@turnweftCodex:
codex plugin marketplace add handong66/turnweft
codex plugin add turnweft@turnweftStart a new conversation afterwards so it loads the plugin; for Codex, restart the app first. Then try:
Ask Droid to explain what this project does, in five bullet points.
- "Ask Grok to review my last commit for security problems. Read only."
- "Have Droid fix the failing test in
test/api.test.tsand run the tests." - "Ask OpenCode to compare our two caching approaches and recommend one."
- "Have agy add a
--jsonflag to the export command." - "Continue with the same Dim session: why did you choose that library?"
- "Cancel the Droid task."
You can name a model if you want one ("use Droid with glm-5.3-flash"), and a thinking level too ("use Dim with thinking level max"). Otherwise each agent uses its own defaults. Thinking levels use each agent's own values, and the exact set depends on the model:
| Agent | Thinking levels | Applied as |
|---|---|---|
| Dim | auto, none, high, max |
ACP option thought_level |
| Droid | none, low, medium, high, xhigh, max |
ACP option reasoning_effort |
| Grok | low, medium, high, xhigh |
ACP option reasoning_effort |
| OpenCode | low, high, max, default (some models: medium) |
ACP option effort |
| agy | low, medium, high, xhigh, max |
--effort at launch |
You can also change the thinking level mid-conversation ("let Dim think harder from now on"). It applies to every task that starts after the change (a task already running keeps its level), in the same agent session, so the agent keeps its context. Dim, Droid, Grok and OpenCode change it inside the running session, like their own CLIs do. agy only accepts the level at launch, so Turnweft restarts agy on the same conversation with the new level. The level is re-applied whenever a session is resumed. If the agent doesn't offer the level with its current model, that task fails with invalid_effort before anything is sent, the error lists the levels it does offer, and the session stays usable. Results report the level requested and the level the agent reports.
- Read-only when you ask for analysis. Reviews and questions run in each agent's read-only or ask-first mode wherever the agent has one. Grok is the exception: Turnweft can't verify Grok's actual permission mode, so Grok tasks need one confirmation even for analysis. If your Grok config auto-approves everything, Grok can't be held read-only at all, and the confirmation says so.
- Broader modes are confirmed once. Some agents can only edit in a mode that goes beyond what you granted. For example, the agent approves commands automatically, or it skips its own permission checks. Then a macOS dialog asks you once per agent × project × kind of task. If the agent's version changes, or the mode starts allowing more, you are asked again.
- Bypass conversations aren't asked. In Claude Code, only
bypassPermissionscounts; auto mode and every other mode still show the dialog. In Codex, only full access (danger-full-access) counts. Turnweft learns the mode from Claude Code or Codex itself, never from what the model says. This kind of approval covers one task and is not remembered. - Every result tells the truth about permissions. It states the mode the agent actually ran with, what that mode allows beyond your grant, and what authorized it.
- Nothing runs twice by accident. If the connection to the agent drops after a task was handed over, the task is marked
in_doubtfor you to check. It is never resent automatically. Closing Claude Code or Codex doesn't stop a running task: it keeps going in the background, and you can check on it later. - Local only. Turnweft keeps its state in
~/.turnweftand makes no network requests of its own. The agents themselves talk to their providers as usual.
What Turnweft can't do:
- It can't hold an agent tighter than that agent's own permission modes allow.
- It can't stop another program running under your account from editing Turnweft's local files.
Tested on macOS with these versions:
| Agent | How Turnweft talks to it | Mode used for code changes | Edits files | Follow-ups | Resume after idle | Cancel |
|---|---|---|---|---|---|---|
| Dim 0.5.16 | ACP | workspace-write; command requests answered by Turnweft |
✅ | ✅ | ✅ | ✅ |
| Droid 0.233.0 | ACP | autonomy_level=normal; each edit and command request answered by Turnweft |
✅ | ✅ | ✅ | ✅ |
| Grok 1.0.46 | ACP (agent --no-leader stdio) |
follows your ~/.grok/config.toml |
✅ | ✅ | ✅ | ✅ |
| OpenCode 1.18.34 | ACP | build mode, following OpenCode's own permission config |
✅ | ✅ | ✅ | ✅ |
| agy 1.2.16 | native long-lived stream-json | skip permissions + accept edits | ✅ | ✅ | ✅ | ✅ |
Claude Code / Codex ──MCP──▶ turnweft mcp ──▶ shared state (~/.turnweft/state.sqlite)
│
▼
one background worker per active session
│
┌──────────── ACP ───────────────┴──── native stream-json ──┐
▼ ▼ ▼ ▼ ▼
Dim Droid Grok OpenCode agy
- One runtime, two thin plugins. The npm package is the only runtime. Each plugin contains an MCP registration, a skill that teaches the assistant how to use Turnweft, and a small launcher. The Claude Code plugin also has a hook that reports the conversation's permission mode. If the runtime is missing, the plugin offers a single setup tool that explains how to install it.
- Sessions and jobs. A session binds to one native agent session. Each request is a background job. The caller supplies a
requestId, so a retry returns the original job. Jobs in a session run in order, and writes to the same project run one at a time, even across sessions. - Native permissions, read back where possible. Whenever an agent session is opened or resumed, Turnweft sets the agent's own permission mode and, for agents that report it, reads it back. If the agent reports something else, the task doesn't run. Grok's mode comes from its config file and can't be read back; for OpenCode, only the mode is checked, not its full permission rules.
- Idle and resume. Idle agents are stopped after 10 minutes. The next request resumes them through their native session ID. If resuming fails, you get an error instead of a silent fresh start.
- Two hosts, one store. Claude Code and Codex share the same state. To continue a session from the other host, attach it explicitly.
The full design and every decision are in TURNWEFT_DESIGN_AND_DEVELOPMENT_PLAN.md. Test records: docs/m0/M0_RESULTS.md (protocol probes) and docs/e2e/E2E_RESULTS.md (end to end). These documents are in Chinese.
When an agent's mode goes beyond your grant, the job is recorded as waiting_confirmation and nothing runs yet:
- Turnweft first asks the host to show its own confirmation prompt. In testing, Claude Code 2.1.286 and the Codex 0.160.0 desktop app both declined it automatically without showing it.
- Turnweft then shows a macOS dialog. It names the agent, the project, the mode and what that mode allows beyond your grant. The dialog waits for your choice; no answer never counts as a denial.
- Allow starts the waiting job without resubmitting. Deny cancels it (
confirmation_denied). A proposal expires after 24 hours (confirmation_expired). turnweft sendon the command line shows the same dialog. You can also runturnweft policy grant <proposalId>in a terminal and typeyesorno. It refuses non-terminal input and has no auto-approve flag, but it can't tell who is typing. Run it yourself; don't let an agent with a terminal tool run it for you.
Bypass conversations. Turnweft trusts only a signal the host produces for that very call:
- Claude Code: right before each
turnweft_askorturnweft_delegatecall, the plugin's PreToolUse hook receives the conversation's current permission mode. The hook records the mode for that exact call (tool and task arguments). The record is valid for 15 seconds and used once. OnlybypassPermissionscounts. - Codex: the call's turn metadata must say
sandbox_mode: danger-full-access.
The approval covers one job, at the permissions it had when you submitted it. The turnweft command line never takes a bypass signal. A conversation that was open before you installed or updated the plugin keeps the old version until you start a new one.
Confirmations are stored per agent × project × kind of task. List them with turnweft policy list, and revoke one with turnweft policy revoke <id>.
Optional settings live in ~/.turnweft/config.json:
{
"language": "en",
"executables": { "droid": "/custom/path/droid" },
"idleReleaseMs": 600000,
"inactivityTimeoutMs": 600000
}languagepicks the language of text shown to people, such as dialogs, CLI output and confirmation messages:"en"or"zh".- Order of precedence: the
TURNWEFT_LANGenvironment variable, then this setting, thenLC_ALL,LC_MESSAGESandLANG, then the macOS primary language, and finally English. - Hosts started from the Dock don't see shell variables, so this setting is the reliable way to choose.
- Tool descriptions and workflow hints written for the model are always in English.
- Order of precedence: the
executablesgives explicit paths to agent CLIs. Without it, Turnweft looks onPATH, then in~/.local/bin,/opt/homebrew/binand/usr/local/bin. It also checks~/.opencode/binfor OpenCode and the copy ofdimbundled in DimAgent.app.idleReleaseMsis how long an idle agent is kept running before it is stopped. The default is 10 minutes.inactivityTimeoutMsis how long a turn may go without any activity from the agent before it is cancelled. The default is 10 minutes.
The plugins cover normal use. The CLI is useful for scripting and inspection:
turnweft session create --agent droid --cwd . # returns a tws_… session ID
turnweft session update tws_… --effort high # thinking level for the following tasks
echo "Fix the bug in src/math.js and run the tests" | turnweft send --session tws_… --intent implement
turnweft job wait twj_… --include-result
turnweft cancel twj_…
turnweft policy list
turnweft session close tws_…- An agent shows as unavailable. Run
turnweft doctor. It checks that each CLI is installed and reports its version, but it doesn't check whether you are signed in. A signed-out agent fails when a task runs; the error code depends on the agent and the stage at which it fails. If the CLI lives somewhere unusual, set its path underexecutables. - A dialog appeared in a bypass conversation. Bypass approval needs runtime 0.1.0-alpha.2 or later (
npm install -g turnweft@latest). Otherwise, either that conversation started before the plugin was installed or updated, or the assistant used theturnweftcommand line instead of the plugin tools. Start a new conversation. - The assistant says Turnweft isn't installed. The plugin found no runtime. Run
npm install -g turnweft, then start a new conversation. - Logs are in
~/.turnweft/logs/:mcp.log: confirmation channelsdialog.log: dialogsworker-*.log: one file per session
- macOS only, including the confirmation dialog.
- Stopping an agent relies on process groups. Child processes that leave their group (for example with
setsid) are not tracked. - Grok's actual permission mode can't be read back; Turnweft infers it from
~/.grok/config.toml. OpenCode's effective permission rules can't be read back either. Results say so. - OpenCode's ACP doesn't report provider errors such as an exhausted quota, so Turnweft only detects them through the inactivity timeout.
- Setting a Dim model explicitly changes that workspace's default model for good. Results mention it.
- agy doesn't report its thinking level back, so for agy the result shows the level that was passed at launch.
- Claude Code and Codex are hosts, not targets: Turnweft doesn't delegate work to them.
Cancel or close any running sessions first (turnweft session list, then turnweft session close <id> --policy cancel_running); uninstalling doesn't stop tasks that are already running.
claude plugin uninstall turnweft@turnweft
codex plugin remove turnweft@turnweft
npm uninstall -g turnweftTurnweft's sessions, confirmations and logs stay in ~/.turnweft until you delete that folder.
git clone https://github.com/handong66/turnweft.git
cd turnweft
npm install # also enables the repository's git hooks (unless core.hooksPath is already set; skipped in CI)
npm run build
npm link # the turnweft command now runs this checkout
npm test # core and host-layer tests with simulated agents; no model quota used
node scripts/live-smoke.mjs droid --model <model> [--effort <level>] # real agent end to end (uses quota)Every change that affects users updates the docs and adds an entry to CHANGELOG.md. The git hooks check this on every commit and merge, and scan the staged content for private data. Publishing requires a changelog section for the version and scans the final package automatically. Change versions only with npm version <v>; it keeps the plugin manifests in sync.