Agent handoff and the DNAgent workspace
DNAgent does not run an agent or a shell. You run the agent (e.g. Claude in a terminal
beside the app), and the app shares context with it through a workspace folder
(default ~/DNAgent, changeable with Workspace…). While the app runs, an agent can
also read what is open and selected live through MCP (below), without a handoff.
Live connection (MCP)
The running app serves agents on a user-only unix socket (~/.dnagent/agent.sock, or
$DNAGENT_AGENT_SOCKET). dnagent mcp relays an agent's stdio to it:
claude mcp add dnagent -- dnagent mcp # Claude Code
For MCPorter (Pi), add a dnagent server that runs dnagent mcp, like other stdio servers.
If the app is not running, dnagent mcp exits with a message; start the app and reconnect.
Tools (the contract is schemas/agent-tools.json):
| Tool | Does |
|---|---|
status | app version, workspace, number of open constructs |
list_documents | open constructs in tab order: id, name, length, topology, active, unsaved changes, edit_counter |
get_view | the active construct, view tab, selected range and selected feature (a dnagent features row) |
get_features | all features of an open construct, unsaved edits included, as dnagent features rows |
export_snapshot | writes the construct as it is open now to <workspace>/.dnagent/snapshots/ and returns the path, for CLI work |
open_file | opens a file as a new tab (or switches to its tab) and returns its document_id |
select_range, select_feature | select a region or feature and make its construct the active tab |
notify | shows a message in the app's Agent panel |
present | the end of autonomous work: opens a result file, shows a summary in the Agent panel and lists highlights (junctions, primer sites, new features); the first is selected and the user clicks the others |
The view tools reply only once the app shows the change ("applied": true, plus the
resulting view); if the window does not respond within 3 s they reply
"applied": false with a note. Invalid targets (a range outside the construct, a
wrapping range on a linear construct, an unknown feature, an unreadable file) are
rejected before anything changes, with codes such as invalid_range or
no_such_feature. Agents cannot edit or save through MCP yet.
Two ways to work with an agent:
- Autonomous: the agent works from start to finish with the CLI on files, writes
the result as GenBank and calls
present. Without the app it still works; the result is then offered through the watched workspace. - Supervised: the agent works step by step on what is open, reads your selection
with
get_viewand shows you regions withselect_range/select_feature.
Coordinates are zero-based and half-open; ranges with end < start wrap through the
origin. edit_counter increases with every change (edit, undo, redo) and never repeats.
GUI → agent: Hand off to agent (⇧⌘C)
For every open tab, DNAgent writes into <workspace>/handoff/:
<name>.gb: a DNAgent GenBank snapshot of what is open, including unsaved edits. The original file is not touched.context.json: which constructs are open and what you are pointing at.
It also shows a short prompt and copies it to the clipboard, for example:
DNAgent handoff: 2 open constructs (snapshots include unsaved edits) — context: ~/DNAgent/handoff/context.json
Selections mark the regions of interest. Use the dnagent CLI and write results as GenBank into ~/DNAgent (they will open in DNAgent automatically).
Each handoff replaces the previous one's files in handoff/.
context.json (format dnagent-handoff, version 1)
{
"format": "dnagent-handoff", "version": 1, "created": "2026-09-29T18:04:05Z",
"workspace": "/Users/me/DNAgent",
"coordinates": "zero-based, half-open; selections with end < start wrap through the origin",
"instructions": ["…"],
"constructs": [{
"document_id": 1, "name": "pEXAMPLE", "active": true,
"snapshot": "/Users/me/DNAgent/handoff/pEXAMPLE.gb", // read this with the dnagent CLI
"source": "/Users/me/constructs/pEXAMPLE.dna", "unsaved_changes": true,
"length": 9175, "topology": "circular",
"selection": {"start": 1250, "end": 6188, "length": 4938, "wraps_origin": false}, // or null
"selected_feature": { …same shape as `dnagent features` rows… }, // or null
"added_feature_ids": ["feature-0021"],
"features": [ …exactly the `dnagent features --output json` result for the snapshot… ]
}]
}
Keys appear in alphabetical order in the file. Feature rows and locations use the CLI's JSON contract.
Guidance for agents
- Work from the snapshots, not the
sourcepaths: sources may lack unsaved edits. - Use the
dnagentCLI (features,translate,orfs,gibson,annotate,convert, …). Put plan files and results in the workspace, not inhandoff/. - Write sequence results as GenBank (
--output genbank,annotate --out,convert --out), so DNAgent can open them with all metadata. - Selections and selected features are what the user means by "this", "these parts" or "the region".
Agent → GUI: the watched workspace
DNAgent checks the workspace every two seconds (sequence files up to one folder deep,
ignoring hidden folders and handoff/), along with every file open in a tab.
- New file (e.g.
product.gb): a notice offers Open (it opens in a new tab) or Dismiss. - Changed file that is not open: the same notice, as "Changed".
- Changed file open in a clean tab: the tab reloads, keeping the selection if the feature still exists.
- Changed file open in a tab with unsaved edits: a notice offers Reload (discard my edits) or Keep mine. Nothing is thrown away without asking.
The app's own saves don't trigger notices.
Tabs
Several constructs can be open at once. Each tab has its own selection, undo history and unsaved state (● on the tab). ⌘1–⌘9 switch tabs. The × closes a tab, asking first if it has unsaved edits. Opening a file that is already open switches to its tab.
Security
The app still exposes no shell or process execution to its web view. It writes only to the chosen workspace (handoff and agent snapshots) and to paths you save to, and it only reads the workspace to notice changes. The agent socket lives in a folder only your user can open (0700); it serves the tools above and nothing else.
Tests
The desktop e2e scenarios tabs-isolation, agent-handoff-product and
workspace-reload play the agent with real dnagent CLI commands in a test workspace.
They check the snapshots and context.json against the GUI and the CLI, and check the
notices and reloads. A Rust test checks every desktop command is served by the e2e server.
agent-mcp-live, agent-points-back and agent-presents-product play a live agent
through dnagent mcp and the e2e server's per-session agent socket, checking the agent's
view and what it shows against the GUI and the CLI.