Repository navigation
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
malacagain 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.
| 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.
| 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.
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.
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.
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 belowThe 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.
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.
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.
| 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.
| 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.
Getting started
Tutorials
- Tutorials
- Tutorial 1: Your first task
- Tutorial 2: Delegating to subagents
- Tutorial 3: Automating a browser
- Tutorial 4: Long-term memory with Milvus
- Tutorial 5: Running malac unattended
- Tutorial 6: Customizing malac
- Tutorial 7: Running malac on a server
Using malac
- Workspaces, tabs and the daemon
- The terminal UI
- Plain mode and scripting
- Sessions
- Jobs
- Permissions and autopilot
- Subagents
- Memory
- Project context
- Plugins and marketplaces
- Computer and browser control
- Web UI
- VS Code
- Remote access
- Mobile (preview)
- MCP servers
- Configure malac by asking
- Updating
Reference
- CLI
- Slash commands
- Configuration
- Tools
- Control service tools
- JSON events
- Protocol
- Environment variables
Guides
- Using an LLM gateway
- Running models locally
- Vector memory with Milvus
- Controlling a remote machine
- Writing agent types, skills and commands
- Security model
- Things to know
Project