The command line, as a product
Every button, key and menu item runs an action by name, and the same names are reachable from a shell. What the window shows is readable as JSON, and what changes in it is a stream a script can follow.
No socket, no port, no service
A command is a file written into the settings folder, and the window sees the change. Nothing listens on a network address and nothing runs in the background of its own. That is also why the interface checks drive the whole program through this command line: what it does for a script is what the buttons do for a hand.
The command line is installed with the program at ~/.config/vobuda/bin/vobuda. Link it into /usr/local/bin or call it by its path. VOBUDA_CONFIG points it at another settings folder, and every command then affects only the window on that folder, which is how a check drives its own instance without touching a working window. vobuda mcp offers the same commands to an agent as MCP tools.
Reading the window
Four commands that only look. Nothing here changes the window.
| Command | What it gives | Example |
|---|---|---|
vobuda state | The window as JSON: tabs, the block tree, what runs in each block, its folder, its listening ports, the prompt marks, the copy of the project it sits in, the open panel, the theme, the agents' numbers. Per block: id, view, running, agent, tree, cwd, ports, prompts, copy. Per tab: id, title, signal | vobuda state | jq '.tabs[0].blocks[] | {id, running, ports, cwd}' |
vobuda events [--since N] [--no-follow] | What changes, one JSON line each, as it happens. Every line has seq (a number that only grows), at (epoch milliseconds), window and kind, then the fields of that kind. --since N prints what came after line N first, then follows; --no-follow stops after that backlog | vobuda events | jq -c 'select(.kind=="signal" and .signal=="waiting")' |
vobuda log [lines] | The core's and the interface's log, the last lines of it (40 by default). Errors from the web view land here too | vobuda log 100 |
vobuda where | The path of the settings folder | vobuda where |
The event log is events.jsonl beside the settings, trimmed from the front once it passes two megabytes. The follower watches the path, so the trim loses it nothing.
The event stream
What a script can wait for, without polling and without guessing a number of seconds.
| Kind | Fields | When |
|---|---|---|
tab.open, tab.close | tab, title | A tab appears or goes |
block.open, block.close | block, tab, view, by | A block appears or goes. by says what closed it: a cross, an action (a key or the command line), the still-running question, a finished vobuda run, a moved page, its tab, a restore, or unknown |
signal | tab, title, signal | A tab is marked done or waiting |
block.start, block.finish | block, tab, program, after | A program starts or ends in a block |
block.cwd | block, cwd | The block's folder moved |
ports | block, ports | The block's listening ports changed |
command.exit | block, code | A command ended, read from the shell's prompt marks |
run.exit | block, run, code | A vobuda run ended |
guard.refused | tool, kind, what, cwd | The fence stopped the agent: a delete, a write outside the project, or a key |
copy.open, copy.removed, copy.kept | path, branch, root, ahead, dirty | A copy of the project made, removed, or kept because it holds work |
review.accept, review.put-back, review.tell, review.commit, review.merge, review.pr | path, hunk, root, hash, branch, url | The decisions of a review |
snapshot.taken, snapshot.restored | cwd, prompt, at, files | A snapshot of the project, and one put back |
project.publish, project.github, project.packed | folder, path | The project handed on |
Driving the window
One dictionary of actions is behind the keys, the buttons, the menus, Cmd+K and this command line. An unknown action is refused, not ignored, and the refusal is in the log.
| Command | What it does | Example |
|---|---|---|
vobuda do <action> | Any action by name. An argument follows a colon. The full list is the right-hand side of the shortcuts file plus the command list (Cmd+K in the window) | vobuda do "tab.new:/path/to/project" |
vobuda send <text> | Types into the active block. A trailing \n is the return key; only \n and \t are unescaped, the rest is the shell's business | vobuda send 'npm test\n' |
vobuda run <command> | Runs the command in a block of its own beside the active one, waits, and exits with its code. The header shows running, then the exit code; a block that succeeded closes after a moment unless kept, a failed one stays. For a command that should run where a person can watch | vobuda run cargo test && echo green |
vobuda button <id> | Presses a dock button by its id, as if with the mouse | vobuda button files |
vobuda ui | Everything on the screen a hand could use, as JSON: an id that stays the same in every language, a name, a kind (button, field, toggle, tab, row, item, link), its state, why it is greyed if it is, the block it stands in, its content if it is a field. A control behind a closed menu is not listed, because a hand could not press it either | vobuda ui | jq '.[] | select(.kind == "row") | .name' |
vobuda press <id|name> [--block N] | Calls the control's own click, the same event a hand makes. Two things answering to one name refuse the press and list both by id, with a non-zero code; --block settles it. The answer says what appeared, what went and what turned on or off. Nothing here moves the pointer | vobuda press block.close --block 2 |
vobuda type <name> <text>, vobuda key <name> <key> | Text into a named field, or one key: Enter, Escape, Tab, the arrows, Backspace, a letter, with modifiers in front (shift+Enter, cmd+Left, ctrl+c). Both go through the events the interface listens for, so a search filters and a rename saves | vobuda type search quiet |
vobuda click <name> <col,row> | A click on one cell of a terminal, counted from zero at the top left: the press and the release a hand makes there | vobuda click "Terminal input" 8,3 |
vobuda shot [--block] [--element <name>] | A picture of the whole window, and the path to it. --block takes the block that has the keyboard, --element one control by name. Every picture is a file of its own, named by the time it was taken | vobuda shot |
vobuda wait <key> <value>, vobuda wait --control <name> | Waits until the window says so, instead of sleeping. The key is a path into vobuda state. A wait that runs out says what the key stayed instead and returns non-zero. Thirty seconds unless --timeout says otherwise | vobuda wait agentBusy false |
vobuda signal done|waiting|clear | Marks the active tab: a badge, a sound, a notice. It is what the agents' hooks call; any program in a block can do the same with printf '\e]9;done\a' | vobuda signal waiting |
vobuda workspace list|open <name>|new|delete <name> | A workspace is a separate project window with its own tabs | vobuda workspace open shop |
Settings, and the rest of the toolbox
Every setting is a file in the settings folder, and the window follows the file. A pinpoint edit writes the value with its own type and leaves the rest of the file valid.
| Command | What it does | Example |
|---|---|---|
vobuda set <file> <key> <value> | A nested key in a settings file, typed | vobuda set settings.json signals.quiet.enabled true |
vobuda theme, vobuda skin, vobuda dock | The theme by name, the monitor skin, the side of the dock | vobuda theme dark |
vobuda edit <file> | The file in your $EDITOR | vobuda edit settings.json |
vobuda backup [file.zip], vobuda restore <file.zip> | The whole settings folder as one file, and back | vobuda backup |
vobuda pack [folder] | The project as one archive for a developer, beside the project, with a readme on top: what it is, how it runs, what changed last, that the keys were left out. node_modules, .git, builds and every .env are not in it. Prints the archive's path | vobuda pack |
For the agents' hooks
These are what the window writes into Claude Code's and Codex's settings. A person or a script can call them too.
| Command | What it is for |
|---|---|
vobuda ask | Where should this page open? Here, a new tab, its own window, or the browser |
vobuda note <kind> | Notes beside the agent's numbers: compacting, compacted, helper on, helper off, folder, edited, failed |
vobuda brief | The window's brief for the agent at the start of a session |
vobuda snapshot | The project folder as it is, before the turn; a key in the request stopped |
vobuda guard | Before a tool runs: the fence, never delete, keys, the last tool recorded |
What each of these writes, where, and how to take it out again is on the page about what vobuda does with your machine.
Two examples
The first is a script that opens a project the way a person likes it and then listens. The second is what an agent does from its own block.
#!/bin/shvobuda do "tab.new:$HOME/work/shop"vobuda do block.splitvobuda do agent.claudevobuda do block.prevvobuda send 'npm run dev\n'# and, in another script, say so when an agent is waitingvobuda events | jq -c 'select(.kind=="signal" and .signal=="waiting")' | while read -r line; do say "the agent is waiting"; done # read the windowvobuda state | jq '.tabs[0].blocks[] | {id, running, ports}'# run a command where the person can watch, and get its exit codevobuda run cargo test# wait for the window instead of sleepingvobuda wait agentBusy false# change a setting by writing the filevobuda set settings.json monitor.every 5 What this is not
Not a protocol with a version: the files are the interface, and they are the same files a person edits. Not a way to talk to a chosen window among several: addressing a window is the workspace's business. Not a way to start or supervise the program: a command is a note left for a running window.
Try it from your own shell
The command line comes with the program, and a settings folder of its own is one variable away.
curl -fsSL https://vobuda.com/install.sh | sh