Terminals
Voxa needs a live Claude Code session to talk to. There are two ways it gets one: it can launch and manage the session itself, or it can attach to a terminal you already have open. This page covers both, how Voxa finds terminals, what permissions each backend needs, and the safety rules that govern everything it does inside your terminal.
Two ways to run Claude
Managed sessions (default)
By default, Voxa launches Claude Code itself, inside its own tmux session on a private voxa socket. That socket runs with no user config file, so a broken ~/.tmux.conf on your machine can't interfere with it. On macOS, Voxa then opens a visible terminal window attached to that session, so you can watch Claude work and type into it yourself at any time. Nothing about the session is hidden from you: it is a real, visible Claude Code session, just one that Voxa started.
If Voxa can't open that visible window (for example, because it doesn't have Automation permission yet), it tells you the tmux session name and how to attach to it by hand.
There's also a headless "drive" mode. In this mode Voxa runs Claude through the Claude Agent SDK instead of a terminal, with no interactive shell backing it. You still get a read-only watch window: a terminal tailing a log file of Claude's streamed output, so you can follow along even though you can't type into that window directly. Drive mode is opt-in, not the default.
Attaching to a terminal you already have open
If you'd rather keep using a terminal you already have open, say "use my open terminal." Voxa will discover the Claude Code sessions currently running on your machine and let you attach to one instead of starting a new managed session.
How Voxa finds terminals
Discovery is process-first: Voxa looks for every running claude process that's attached to a terminal (a tty), then matches each one against what it can see through tmux, iTerm2, Terminal.app, and, as a fallback, macOS's Accessibility API. Results are deduplicated by tty, with tmux taking priority, then iTerm2, then Terminal.app, then the Accessibility fallback.
For each terminal it finds, Voxa shows you:
- the working folder (cwd)
- which app it's running in
- whether it's currently working or idle
- a hint from the last line on screen
- how long ago it was last active (age)
Per-app support
Not every terminal app is controlled the same way. The table below shows what Voxa can do with each, and what permission it needs to do it.
| App / backend | How Voxa reads the screen | How Voxa types | Permission needed |
|---|---|---|---|
| tmux | Captures the pane directly | Sends keystrokes directly | None beyond tmux itself (private socket) |
| iTerm2 | AppleScript | AppleScript | Automation |
| Terminal.app | AppleScript | AppleScript, plus System Events for single keypresses (briefly steals focus while it does) | Automation, for both Terminal.app and System Events |
| Ghostty, Warp, VS Code, or anything else | macOS Accessibility API | Input posted straight to the app's process, without stealing focus | Accessibility |
For GPU-rendered terminals that don't expose readable text through Accessibility, Voxa can't read the screen directly. Instead it tracks progress through Claude's own transcript files, so it still knows whether Claude is working, idle, or waiting on you, even without a text view of the pane.
First-run permissions
The first time Voxa needs a permission it doesn't have, it tells you plainly what's missing and what to do:
- Accessibility: needed the first time Voxa has to control a terminal other than tmux, iTerm2, or Terminal.app. Voxa opens System Settings to the Accessibility pane for you. Grant access to the terminal app you ran
voxafrom, then attach again. - Automation: needed for iTerm2 and Terminal.app. macOS prompts for this the first time Voxa uses AppleScript against those apps.
- Screen Recording: only needed for screenshots. If it's missing, Voxa tells you to enable it in System Settings under Privacy & Security, then try again.
Safety promises
Voxa's attach controllers never close your terminal. Switching sessions, attaching somewhere else, or disconnecting all just detach; the terminal, tab, or window you had open stays exactly where it was.
The one exception is when you explicitly ask Voxa to close a terminal. Even then, what "close" means depends on the backend:
- tmux: kills the session.
- iTerm2: closes the tab.
- Terminal.app: ends the Claude process, then closes the tab.
- Accessibility-controlled apps: ends only the Claude process. The window itself is left open.
Approvals and the danger gate
When Claude Code shows one of its own on-screen permission prompts, Voxa turns it into a tappable card on your phone. Voxa only builds these cards from prompts it can actually see live on screen, so a stale or misread screen can't produce a phantom approval card.
Dictated dangerous commands get an extra check before they ever run. If you dictate something like rm -rf, a force push, a drop table, a deploy to production, or a disk-erasing operation, Voxa doesn't send it straight to Claude. It shows you a card explaining what's risky about it and waits for an explicit "Run it" before dispatching the command.
Claude's own autonomous tool calls get the same treatment from the other direction. If Claude itself tries to run something in that dangerous category without being asked, a hook denies the tool call before it executes. Claude sees the denial, stops, and asks you directly instead of running it.
If a voice decision doesn't clearly match one of the options on an approval card, Voxa defaults to decline rather than guessing at a "yes."
One honest caveat worth calling out: managed sessions run Claude with permissions bypassed (Claude Code's --dangerously-skip-permissions / bypassPermissions mode), so Claude itself won't stop you with its own trust prompts in that mode. The danger gate described above, plus the approvals you grant on your phone, are what stand in for that layer of safety.
Git by voice
Asking Voxa about your repo's status or diff is read-only: it just reports back what it finds, and changes nothing.
Committing or pushing is different. Both always show you a confirmation card first, naming the project and branch, and only run after you approve. Once approved, the actual git commit or git push runs inside your visible Claude session, not in some hidden process, so you can watch it happen.
Pushing never uses --force. If a branch has no upstream yet, Voxa won't set one up on its own: publishing a new branch upstream is something you still need to do by hand once, with git push --set-upstream.
For more on how Voxa handles voice and approvals generally, see voice operator. If something isn't behaving as described here, check troubleshooting.