A small web page for driving coding-agent conversations (Claude Code, Codex and opencode) on this machine from any other device on your Tailscale network.
Your agents, your code, and the conversation history all stay on the host machine — other laptops or phones just open a web page. Every device sees the same live conversation, including streaming replies and permission prompts, so you can start something on one laptop and approve or continue it from another.
Conversations are each agent's own native sessions — Claude Code's in
~/.claude/projects, Codex's in ~/.codex, opencode's in its own store — so
anything started in a terminal or desktop app shows up here too, and anything
started here can be resumed there (claude --resume, the Codex app or
codex resume, or the session list in opencode).
npm install
npm startRequires Node 18+, and Claude Code logged in on the host — agentdeck uses that login. Codex and opencode are optional: each one installed on the host shows up as another agent, using its own login.
By default agentdeck listens on this machine's Tailscale IP, port 7878, so
only devices on your tailnet can reach it. On startup it prints the address
to open from other devices; prefer the MagicDNS name it prints
(http://<machine-name>:7878) over a bare IP, and always include the
http:// prefix. It also answers on http://localhost:7878 on the host
itself.
The first time you open it, the page shows a code and waits for approval.
Run npm run approve in this folder on the host and type that code to let
the browser in.
After that, a new device can be approved from one you already use (see
Security).
Port, project roots, an optional password, and other settings are environment variables — see docs/REFERENCE.md.
Anyone who can use this page can run commands on the host through the
agents, so each browser has to be approved once. A new browser shows a
short code and waits. Every device that already uses agentdeck gets a prompt
asking for that code; typing it there lets the new browser in. The code is
only ever shown on the new browser, so nobody can get approved by a tap on a
prompt you didn't expect. For the very first device, run npm run approve on
the host and type the code there. Approvals are
kept on the host, so restarts don't sign anyone out. Devices, at the
bottom of the sidebar, lists them and removes any you no longer use. If a
PASSWORD is set, typing it also approves a browser.
agentdeck also refuses requests that a page from another site makes through your browser, so a website you visit can't drive it. Keep it on a private network like Tailscale all the same. See docs/REFERENCE.md for the details.
The sidebar lists every agent's conversations for a project together, each marked with its agent. When more than one agent is installed, a picker chooses the agent for a new conversation; an existing conversation always continues with the agent it started with. The mode, model and effort menus adapt to show what the selected agent offers — see docs/REFERENCE.md for what each agent's modes mean. The Usage button in the header shows the plan limits of whichever agent's login is active.
Type / at the start of a message to list the skills and slash commands
the chat's agent has in this project: your own, the project's, plugins'
and the agent's built-in ones. Keep typing to filter, pick one with the
arrow keys and Enter (or Tab, or a click), add any arguments and send.
Typing /name yourself works the same as picking it. See
docs/REFERENCE.md for how each agent runs them.
Hover a conversation in the sidebar and click the tag button to add or remove tags (up to 10, 30 characters each). Each change is saved as soon as you make it. Tags you've used become quick tags you can toggle with one click. The Tags section at the top of the sidebar has a chip for every tag; click one to list that tag's conversations from all workspaces. Tags live on the host and sync across every device, but are never written into the agents' own transcripts.
Attach up to 10 images to a message — click 📎, paste, or drag files onto the composer — and images the agent shares back (screenshots, tool output, generated images) appear inline too, loaded from the host so every device sees them. Click any image to view it full size. Videos (MP4, MOV, WebM) and audio (MP3, M4A, WAV, Ogg, FLAC) the agent links, names or returns from a tool play inline. See docs/REFERENCE.md for how images and file-name mentions are matched.
Drop any other file onto the composer (or pick it with +) and it's copied to the host, and its path there is put into your message, so the agent can read it. This works from any device, since a browser never tells the page where a dropped file lives. See docs/REFERENCE.md.
One conversation runs one turn at a time. Messages sent while the agent is working — from any device — wait in a queue shown above the composer and run in order as each turn finishes. A queued message can be sent now (stopping the current turn so it runs next), edited (taken back into the message box), or removed before it starts. Stop ends the current turn and clears the queue, putting the queued messages back into the message box of the device that pressed it. Permission prompts (file edits, shell commands, plan approval, questions) appear on every connected device, and whichever answers first wins. Avoid keeping the same conversation open here and in a terminal, desktop app, or opencode TUI at the same time — each keeps its own copy in memory and won't see the other's messages.
Hover any message you sent and click the fork button beside it to branch the conversation: the host copies it, through the end of that exchange, into a new conversation of the same agent, which then opens. Forking from the last message copies the whole conversation. A branch is one of the agent's own sessions, so it resumes in a terminal too, and it starts with the model, effort, mode and tags of the chat it came from. The fork button is hidden while a turn is running, because the transcript is still being written.
Every new conversation, with any agent, starts knowing which projects are
on this machine: each folder under the project roots with its path, the
opening paragraph of its README, when it was last active and the titles of
its latest chats from all three agents. Ask about another repo by name and the
agent knows where to look, and agentdeck offers to add that repo to the
chat's folders (see Folders). Chat titles are often the start
of a chat's first message, so whatever you typed there goes to the provider
of every new chat. Set WORKSPACE_INDEX=off to turn it off — see
docs/REFERENCE.md.
A chat works in its project folder, and can work in other folders too. The 📁 button in the composer lists them: pick projects to add, or type any folder's path, and remove them with ×. When a message names another project under the project roots, by name or path, a prompt asks whether to add it to the chat. Each project is asked about once per chat. Allow it and the agent can read and edit there without asking for access first, in this and later turns. The chat's mode still decides which actions need approval. A chat's folders are kept with its model and mode, so every device continues it the same way. See docs/REFERENCE.md for what each agent does with them.
A soft two-note chime plays when a conversation finishes a turn, and a more insistent double beep when a permission prompt appears. Both play for every conversation on the host, not just the one you have open, so a chat left running in another workspace still calls out. The bell button in the header mutes them, per device. Browsers only allow sound after you've interacted with the page, so the first click or key press after opening arms it.
The header ends with one-click buttons that run on the host. Restart is built in: it restarts agentdeck itself, which is how to pick up a change an agent just made to agentdeck's own code without going to a terminal. Every open page shows "Restarting…" and reloads when the server is back; a message you were typing comes back with it. If any conversation is mid-turn, the button asks first, because a restart stops those turns.
Settings, at the bottom of the sidebar, adds your own buttons (macros): a label, an optional emoji, and a shell command that runs on the host in the open workspace's folder. Each one shows what it printed in a card above the composer, and can restart agentdeck once it succeeds, for an "update and restart" button. The list is kept on the host, so every device shows the same buttons; on a phone, Restart stays in the header and ⚡ opens the rest. See docs/REFERENCE.md for how the restart works under a LaunchAgent or when started by hand.
If Tool Hub is running on the host and knows the open workspace, the header also shows a project bar for its dev server: a dot that is green while it runs, Open to visit it, Restart to restart it through the hub (asking first, then showing the hub's answer in a card like a quick action's), and Hub to open the project in Tool Hub. Links use whatever host name the page was opened with, so they work from a phone on the tailnet too. On a phone the bar is just the dot; tap it for the three actions. Without a hub nothing is shown. See docs/REFERENCE.md.
docs/REFERENCE.md covers:
- All environment variables
- What each agent's permission modes mean
- How image and file-mention matching works
- Code layout, for hacking on agentdeck itself
- Running agentdeck at login (LaunchAgent), and troubleshooting
This project is MIT licensed — see LICENSE.
