Corral

Corral

A pen for your herdr spaces

A small local web app that runs beside herdr and gives every space a real terminal in your browser. Click a project and Claude Code (or a plain shell) opens in its folder, arranged in the layout you pick.

Corral in a browser: a sidebar of herdr spaces grouped into Work, Writing, and Uncategorized, with three terminal windows (api-server, dashboard, and notes) tiled on the right. The focused window, notes, has a purple title bar.

The problem it solves

Lots of projects, lots of agents, one screen

herdr keeps your projects as spaces and tracks what each agent is doing. Corral is for the moment you want to actually sit down and work across several of them: see them side by side, start or resume Claude Code with one click, and not lose anything when a tab closes.

"I have three agents running in three repos."

Watch them side by side

Open each space as a window and tile them with a layout like Halves, Main + 2, or 3 x 3. Status dots in the sidebar show which agent is working, idle, or blocked, so you know where to look next.

"Where was I in that project yesterday?"

Resume in one click

Set a space to open with "Claude Code, last session" and a click runs claude --continue in the right folder. When Claude exits, the shell stays open in the same place.

"I closed the tab by accident."

Terminals that survive

Every shell lives in its own tmux session. Closing the tab, reloading, or restarting Corral leaves the work running, and reopening the page puts each window back where it was.

"My Mac restarted, and all my sessions are gone."

Restore them

Corral keeps a backup of the open windows and the Claude Code conversation in each. After a restart, a Restore button reopens every window in its folder, resuming its conversation.

"I stepped away, and Claude is waiting on me."

Answer from your phone

Through Tailscale, your phone lists every window on the Mac, with the ones waiting for you on top. Tap one to read the conversation, reply, dictate, or send a photo, allow or deny a permission prompt, or start Claude Code in another project. A notification tells you when a session needs you.

"I have forty projects and can never find the one I want."

Sort them into groups

Make categories like Work or Writing, then right-click or drag spaces into them. Select several at once, or search and move every match. Each move can be undone.

"I closed that herdr space, and now it's gone."

Bring back inactive projects

Corral remembers every project folder it has seen. When a space disappears from herdr, the project moves to "Inactive projects" with a Reopen button that recreates the space.

"What's in this repo again?"

Peek at the files

Expand any space for a file tree, limited to that project's folder. Click a file to open it in a Mac app: Corral asks which one until you set a default for that type of file.

What you get

A browser workspace for herdr

Corral does not replace herdr. herdr keeps managing your spaces and agents; Corral reads herdr's list of spaces and opens its own terminals for them.

Every space in a sidebar

The sidebar lists each herdr space with its agent status, a search box, your categories, and the projects that are no longer open in herdr.

Working Idle Blocked No agent
  • Click a space to start Claude Code, Claude Code's last session, or a plain shell in its folder. A space keeps one window; clicking it again brings that window forward.
  • Right-click a space, or use its ⋯ button, to file it under a category, or make a new one on the spot.
  • Cmd-click or Shift-click to select several spaces and move them together.
  • Expand a space to browse its files. Click one to open it in a Mac app, chosen from the apps macOS offers for it; tick "Always" to make that the default for the file type. Right-click to choose again.
The Corral sidebar: an inactive project with a Reopen button, open windows with an expanded file tree, categories named Work and Writing, and a right-click menu for moving the scratch space into a category.

Layouts for your windows

In the spirit of Sash, a layout is a set of zones, and each window sits in one. Auto picks a tiling from how many windows are open and the shape of the screen.

  • Halves, Thirds, Quarters, Main + 2, Main over 2, 2 over 1, Main + 3, 3 x 3, and more.
  • A plain grid with the number of columns and rows you choose.
  • Drag a window's title bar onto another zone to move it there or swap.
  • Minimize a window to the bottom bar. It keeps running, and one click brings it back. Drag the bar's top edge to make it bigger or smaller.
Corral's layout menu with fifteen choices: Auto, Grid, Maximize, Halves, Stacked, Thirds, Quarters, Main + 2, 2 + Main, Main over 2, 2 over 1, 1 over 2, Main + 3, 3 x 2, and 3 x 3.

Real terminals, not a preview

Each window is a full terminal (xterm.js) connected to a shell on your Mac. Run Claude Code, a dev server, git, or anything else you would run in Terminal.

  • Closing a window ends its shell. Minimizing, reloading, or closing the tab does not.
  • Attach to any Corral shell from another terminal with tmux -L corral attach -t wt-<id>.
  • Links printed in a terminal are clickable.
  • Drag across text to copy it. Option-drag makes a browser selection instead.
  • After a Mac restart, Restore reopens the windows you had, each resuming its Claude Code conversation.
Three Corral terminals in the Main + 2 layout: api-server large on the left, dashboard and notes stacked on the right, with notes focused under a purple title bar.

Remote control

Answer Claude from your phone

With Tailscale, the private network between your own devices, Corral becomes a remote control for every terminal on your Mac. See which Claude Code sessions are waiting for you, allow or deny what they ask, answer them, start new ones, and read back what happened, from your phone, a tablet, or another computer. The phone can even get a notification when a session needs you.

Corral's phone page listing four windows: notes and dashboard under Waiting for you, api-server under Working, and a blog shell, each with its folder.
Whose turn it is. Sessions waiting for you come first, then the ones working, then shells, so you can see at a glance what is open.
The notes window on a phone, in Conversation: your prompts as purple bubbles on the right with their times, Claude's replies on the left, the status line under them, then a row of keys starting with Use suggestion, Type, Esc, and Shift-Tab, quick replies, a camera button, a message box, and a Send button. The header has a Terminal button and a menu button.
The conversation, with the keys. Your prompts and Claude's replies with its status line; Terminal switches to the full terminal. Use suggestion sends Claude's suggested prompt in one tap.
The Start in a project sheet: a choice of Claude Code, Last session, or Shell, a search box, and the list of herdr spaces with their status dots.
Start something. Claude Code, its last session, or a shell, in any space. It also waits in the Mac's bottom bar.
The phone list with data-lab at the top, marked Needs permission in red. Its card shows the command Claude wants to run, then buttons for Yes, Yes and don't ask again, and Deny.
Allow or deny. A session stopped at a permission prompt shows what it wants to run and a button for each answer.
The Changes view for the dashboard project: the changed files, api.js and a new empty.test.js, then the diff with removed lines in red and added lines in green.
Changes. What is not yet committed in the window's project, as a colored diff.

Chat or Terminal

A Claude Code window opens on its conversation: your prompts and Claude's replies as chat bubbles, with Claude Code's status lines under them. Terminal switches to the full terminal, and Chat switches back. The phone remembers your choice, and the keys and message box work in both.

Notifications

Tap Alerts to get a push when a permission prompt opens or Claude finishes its turn, even with Corral closed. By default nothing is sent while you are at the Mac. Mute any one window from its menu. On an iPhone, this needs Corral on the Home Screen.

From the card

A working session shows how long it has run and a Stop button. Each card shows the permission mode, and its ⋯ menu has Last reply, Next mode, Mute, Rename, and Close. Press and hold a card to read Claude's last reply.

Quick replies and swipes

Chips such as Continue, Run the tests, and Commit and push fill the message box in one tap. Swipe across a terminal to move to the next window.

Mac stays awake

While a window is working or waiting on a prompt, Corral keeps the Mac from idling to sleep, so the phone can still reach it. Closing the lid still sleeps.

On the Mac too

The desktop page shows the same Allow and Deny buttons in each window, and its Alerts button sends a desktop notification when a window needs you.

Send a photo

The camera button sends a picture to the Mac and pastes its path into Claude Code, which attaches it to your next message.

Keys a phone lacks

Use suggestion, Esc, Shift-Tab for Claude Code's modes, Tab, Ctrl, ^C, the arrows, Enter, and 1, 2, and 3 for Claude Code's menus.

Type or dictate

The message box works with the keyboard's microphone, and a message with several lines goes in as one.

Like an app

Add it to your Home Screen and it opens full screen. Restore brings back the windows from before a Mac restart.

Compared with Claude Code's Remote Control (/rc): Remote Control needs no setup beyond signing in, and reaches the sessions you turned it on for, through Anthropic's servers. Corral needs Tailscale on both devices, and then shows every window on the Mac without turning anything on (Claude Code and plain shells alike), lets you start new ones in any project, and reaches your Mac over your tailnet, encrypted end to end.

Set it up

  1. Install Tailscale on the Mac and on your phone from tailscale.com/download, and sign in to the same account on both.
  2. Turn on HTTPS for your tailnet. In the Tailscale admin console, open the DNS page, make sure MagicDNS is on, and under HTTPS Certificates choose Enable HTTPS.

    Tailscale's certificates are recorded in a public log that includes the machine's name, so rename the Mac in Tailscale first if its name says anything private.

  3. Have Tailscale forward to Corral. With Corral running, run this once on the Mac. If HTTPS is not on yet, it prints a link to turn it on.
    $ npm run tailscale   # tailscale serve --bg --https=8443 http://127.0.0.1:8777
  4. Open it on the phone. Corral's On your phone button copies the address, which looks like https://<this Mac>.<your tailnet>.ts.net:8443/m. Send it to your phone and open it.
  5. Keep it on your Home Screen. In Safari, use the Share button and choose Add to Home Screen.
  6. Turn on notifications (optional). Open Corral from its Home Screen icon, tap Alerts, then Turn on notifications. Send a test checks the whole path.

Only you get in. Corral still listens on 127.0.0.1 only; each request through Tailscale must carry your Tailscale login, which Tailscale adds and a device cannot fake (details under Security). To turn it off, run tailscale serve --https=8443 off.

How it works

One small Node process

server.js serves the page, runs each shell in a pseudo-terminal attached to a tmux session, and streams it to the browser over a WebSocket. Nothing leaves your machine, except to your own devices when you turn on Tailscale access.

Your browser

xterm.js draws each terminal and sends your keystrokes.

Corral server

Node on 127.0.0.1:8777, with ws for the WebSocket.

node-pty

A pseudo-terminal per window, attached to its tmux session.

tmux (-L corral)

A private tmux server that keeps every shell alive.

The sidebar comes from herdr api snapshot, and each space's project folder from herdr's ~/.config/herdr/session.json. Corral polls herdr every 30 seconds, so it notices a space that closes even while no page is open. herdr's session files are not a public API, so a future herdr release could change them. Another device reaches Corral through tailscale serve, which forwards to the same loopback address; each device gets its own tmux client, so tmux sizes a window for whichever device typed last.

Install

Run it in a minute

$ git clone https://github.com/ismayc/corral.git
$ cd corral
$ npm install   # also makes node-pty's helper executable
$ npm start     # then open http://127.0.0.1:8777
  • macOS. That is where Corral is built and tested. Linux may work but is untested.
  • Node.js, tested with Node 24.
  • herdr on your PATH or at ~/.local/bin/herdr, tested with herdr 0.9.3.
  • tmux, recommended (brew install tmux). Without it, Corral still works, but shells end when the server stops.
  • Claude Code, if you want a click to start it.
VariableDefaultWhat it does
CORRAL_PORT8777Port to listen on (always on 127.0.0.1)
CORRAL_TMUX_SOCKETcorralName of Corral's private tmux server
HERDR_BIN~/.local/bin/herdr, else herdr on your PATHPath to the herdr command
CORRAL_SORT_BINscripts/herdr-sort-spacesScript that re-sorts herdr spaces after a Reopen
CORRAL_TAILSCALEonSet to 0 to refuse every request through Tailscale
CORRAL_TAILSCALE_PORT8443The HTTPS port tailscale serve uses for Corral
CORRAL_TAILSCALE_USERSThe login that owns this Mac in TailscaleComma-separated Tailscale logins allowed in

To use Corral from your phone or another computer, follow the remote control setup.

Security

Strict about who can reach it

A browser terminal can run any command by design, so Corral only answers your own machine and your own Tailscale login, and never takes a command from the page.

Loopback only

It listens on 127.0.0.1 and has no login of its own. Do not expose it on another interface or behind any proxy other than tailscale serve.

Your tailnet, your login

Through Tailscale, a request must name this Mac's tailnet address and carry an allowed Tailscale login, which tailscale serve sets and a sender cannot fake. A public Funnel request carries none, so it gets nothing.

Other sites cannot drive it

Every request needs a loopback Host header, which blocks DNS rebinding, and every change and terminal connection needs a loopback Origin.

A fixed menu of programs

The page can choose Claude Code, Claude Code with --continue, or a shell. It never sends a command.

Only apps macOS offers

Opening a file hands it to macOS open with an app that macOS lists for that file, checked again each time, or shows it in Finder. The page cannot name any other program.

Names, never contents

The file tree lists names only and refuses any path whose real location, after resolving symlinks, is outside the project.

No borrowed identity

Started from inside Claude Code or a herdr pane, Corral strips that session's variables (CLAUDE_CODE_*, HERDR_*, TMUX*) from every shell it starts.

Answers only to an open prompt

Allow and Deny send one key, and only after Corral has read Claude Code's session file and the screen again and found the same prompt still open with that answer. An answer names its prompt, so it never lands on a newer one. A card can otherwise send only Esc or Shift-Tab.

Stays on your Mac

A few small files in ~/.local/share/corral, your browser's local storage, and a private tmux server. The page loads no outside resources. If you turn on notifications, each one goes through your phone's push service, encrypted so that the service cannot read it.

Limits

What it does not do

herdr's own terminals

herdr's API offers snapshots and events but no live byte stream, so Corral opens its own terminals rather than showing the ones inside herdr.

Scrollback after a restart

After a Corral restart, a window shows the current screen. Older scrollback stays in tmux (tmux -L corral attach).

Undocumented re-sort

Reopen re-sorts herdr's spaces alphabetically through an undocumented herdr method, workspace.move_block.

Prompts read off the screen

Allow and Deny read Claude Code's permission prompt from the terminal (tested with Claude Code 2.1.292). If a release changes its look, answer in the terminal.

Awake, not lid-proof

Keeping the Mac awake blocks idle sleep only. A closed lid still sleeps, and then the phone cannot reach it.