Skip to content

Workspaces tabs and the daemon

Bálint Horváth edited this page Oct 26, 2026 · 2 revisions

Workspaces, tabs and the daemon

How malac keeps your work in a per-user daemon, organised as workspaces of tabs, so agents outlive the terminal and every client shares them.

Interactive malac runs in a background daemon, one per user. The terminal UI, the line mode, the web UI and the VS Code extension are all clients of it. That is what makes these things work:

  • Agents keep running after you close the terminal. Quit the terminal UI (or close the window) and the agents carry on in the daemon; run malac again to come back to them.
  • Work survives a reboot. Workspaces are saved to disk and restored when the daemon starts again. Agents come back idle and resume from their transcripts when you prompt them.
  • Several clients at once. Two terminals, a browser and VS Code can work on the same workspace at the same time and see the same agents live.
  • Approvals close everywhere. A permission request appears in every connected client; the first answer wins, and the dialog disappears in the others.

Workspaces and tabs

Thing What it is
Workspace A set of tabs: what you work on together, for example one feature across a backend and a frontend repository. You can keep several and switch between them.
Tab A project: one folder, with that folder's configuration, instructions and tools, and the agents working in it.
Agent A conversation in a tab. A tab can hold several top-level agents side by side, each with its own subagents.

Each tab loads its project's .malac/config.toml, AGENTS.md, skills and agent types, and connects its MCP servers, the first time an agent in it is used. The permission mode is set per tab.

Opening work from the command line

Command What it opens
malac The last workspace, from any folder, with all its tabs, where you left it
malac <prompt> The last workspace, with a new tab for this folder running the prompt
malac --name api <prompt> The same, with the new tab named api
malac -n A fresh workspace; the previous one stays saved
malac -n --name release A fresh workspace named release
malac -w release The workspace release, by name or id
malac -c The last session started in this folder, in its tab
malac -r <id> A saved session, in the tab that holds it or a tab for its folder

The first time, malac creates a workspace called default. -n and -w cannot be combined. These options work the same in the full-screen UI and with --plain.

Managing workspaces

malac workspaces                          # list them; * marks the last used one
malac workspaces rename default backend   # rename, by name or id
malac workspaces delete old               # delete; its sessions stay on disk
malac workspaces delete old --force       # even while its agents work (stops them)
* default  01a17450  3 tabs · 1 running  2026-10-25 20:14
  release  01a17462  1 tabs  2026-10-24 17:02

The terminal UI's Session menu and the web UI's workspace switcher do the same: new, switch, rename and delete. Workspaces are saved in ~/.malac/workspaces/, and ~/.malac/state.json remembers the last one.

The daemon

Clients start the daemon when it is not running, so most of the time you never think about it. It listens on 127.0.0.1:7700 (web.port, or any free port), serves the web UI, and writes ~/.malac/daemon.json so clients can find it.

Command What it does
malac daemon or malac daemon start Start it in the background, unless it runs; output goes to ~/.malac/daemon.log
malac daemon run Run it in the foreground, logging to the terminal
malac daemon status Version, address, clients, workspaces, running agents and jobs, and when it exits
malac daemon status --json The same as JSON
malac daemon stop Stop it. Refused while agents or jobs run; --force stops them.
malac daemon restart Stop and start, for example after an update. Same --force rule.
$ malac daemon status
malac daemon 1.0.0 (pid 68119) since 2026-10-25 18:33
  url        http://127.0.0.1:7700/?token=…
  remote     off (this machine and SSH tunnels only) · 0 paired devices
  awake      holding · 1 agent running (keep_awake = busy)
  clients    2
  workspaces 2 · 3 tabs loaded
  running    1 agents · 0 jobs · 0 waiting for approval
  exits      after 120 minutes without clients or work
  log        /Users/you/.malac/daemon.log

start, run and restart take --port, --host, --remote (let paired devices on other machines in; see Remote access) and --token.

When it exits

The daemon exits after daemon.idle_minutes (default 120) with no clients, no running agents or jobs and no pending approvals. Set it to 0 to keep it running:

# ~/.malac/config.toml
[daemon]
idle_minutes = 0
browse_root = "~/code"   # the web UI's pickers show only what is below this (default: home)
keep_awake = "busy"      # see below

The daemon reads [daemon], [web], [remote], [update] and [control] from your user configuration only; each tab loads the full configuration of its own folder. The daemon keeps the environment it was started with, so after changing an API key variable, run malac daemon restart, or store the key with malac provider add --api-key-stdin.

Keeping the machine awake

While agents or jobs run, the daemon keeps the machine from sleeping, and lets it sleep again a minute after the last one ends. Start a long refactor, walk away, and it is still working when you come back.

daemon.keep_awake
"busy" (default) Stay awake while agents or jobs run, and for a minute after the last one ends
"always" Stay awake as long as the daemon runs
"off" Never hold the machine awake

On macOS the daemon runs caffeinate -i -s -w <daemon pid>, which prevents idle sleep (and system sleep on power) and ends by itself if the daemon dies. On Linux it uses systemd-inhibit when it is installed; logind may refuse it for a session that is not active, and the status says so. Elsewhere it does nothing.

The terminal UI shows an awake segment in the status line while the machine is held awake, and View has Keep awake while working, Keep awake always and Let the machine sleep. The web UI has the same under Settings → Remote access, and malac daemon status shows the state and why. Both UIs change the mode until the daemon restarts; daemon.keep_awake sets it for every start.

Some things still win: closing a MacBook's lid puts it to sleep unless it runs in clamshell mode (on power, with an external display and a keyboard or mouse), and so do low battery, Sleep from the Apple menu and pmset schedules. The display still turns off; keep-awake holds the system, not the screen.

After an update

Updating malac never touches a running daemon: it keeps the version it started with until it restarts. When the terminal is newer than the daemon, the terminal UI shows daemon 1.0.0 running; restart it when idle in the status line (click it, or Help → Restart the daemon), the line mode prints a notice when it connects, and malac daemon status suggests malac daemon restart.

What runs where

Command Runs in
malac (full-screen UI) The daemon, starting it if needed
malac --plain, or ui.tui = false The daemon, starting it if needed; in its own process if the daemon cannot be reached
malac web, the web UI, the VS Code extension The daemon
malac -C <name> (full-screen, --plain, -p, prompts) The daemon of a saved connection on another machine; never started from here
malac -p, malac --json, piped input, no terminal Its own process: it never starts the daemon, and the run ends with the command

So scripts and CI are unaffected by the daemon: see Plain mode and scripting.

If the daemon cannot start, the full-screen UI says so and suggests malac --plain or malac -p. If the connection drops, the terminal UI shows it and Ctrl+R reconnects, starting the daemon again if needed.

Files

Path What it is
~/.malac/daemon.json Address, token, pid and version of the running daemon (mode 0600)
~/.malac/daemon.token The web UI token, kept across restarts so open pages reconnect; delete it to get a new one
~/.malac/daemon.lock Keeps two daemons from serving one home
~/.malac/daemon.log The background daemon's output
~/.malac/workspaces/<id>.json Saved workspaces
~/.malac/state.json The last workspace used
~/.malac/jobs/ Background jobs and their logs

Clients talk to the daemon over a documented WebSocket and HTTP API; see Protocol.

Clone this wiki locally