Scripting and permissions
This page explains how to script sMind by Spacing Mind from the command line, choose permission modes for agents, and use the built-in MCP server. It is for developers automating agent work.
sMind by Spacing Mind, version 0.17.0. This page describes the 0.17.0 release.
Everything in the web UI also works from the smind command line. This page covers scripts, permission modes, and the MCP server.
Run an agent from a script
smind task send streams the run and waits for it to end. To start a run and come back later, detach:
RUN=$(smind task send <taskId> glm "<prompt>" --auto-accept --detach)
smind task logs "$RUN" -f
smind task runs <taskId>--detach prints just the run ID. task logs -f follows the run, and task attach streams it again. Detaching never stops a run. Raw agent events are hidden by default; add --verbose to send, attach or logs to see them. A prompt that needs a human still prints in full.
Choose where a task starts
By default a task branches from the workspace checkout's current HEAD, so a stale local branch gives a stale base. Pick the start point yourself. Use at most one of these:
smind task new <workspaceId> "title" --base origin/develop
smind task new <workspaceId> "title" --branch some-branch
smind task new <workspaceId> "title" --pr 123--base fetches the remote branch first, so your main checkout is never touched. --branch checks out an existing branch. --pr builds the task from a GitHub pull request.
Permission modes
Each provider has its own modes:
| Provider | Modes |
|---|---|
| Claude Code | acceptEdits (default), default, plan, auto, bypassPermissions |
| Codex | auto (default), full-access |
| GLM and Kimi | the modes the agent offers, plus --auto-accept to approve every prompt |
smind task send <taskId> claude-native "<prompt>" --mode plan
smind task send <taskId> glm "<prompt>" --auto-acceptAnything the mode still asks about waits for a person. The web UI shows it, or use the command line:
smind task permissions <runId>
smind task approve <runId>
smind task deny <runId>To run Claude Code without anyone approving each command, pick auto and pin the model, because an unpinned run uses the CLI's own default:
smind task send <taskId> claude-native "<prompt>" --model claude-sonnet-5-5 --mode auto --detachauto lets Claude Code's own classifier approve prompts. It is not a sandbox: an explicit instruction to do something destructive will probably be approved. Keep briefs narrow, and let each agent work in its own task worktree. bypassPermissions skips prompts with no classifier at all.
You can change a live run's mode instead of approving calls one by one:
smind task mode <runId> --auto-accept on
smind task mode <runId> acceptEdits
smind task mode <runId> --auto-accept offTurning on auto-approval needs a person at a terminal: the command asks you to type yes. This is a speed bump, not a lock. Every client of the daemon holds the same token, so the real boundary against an agent that can run shell commands as you is the provider's own permission mode or sandbox.
A standing permission policy (optional)
Off by default. If you turn it on, smind can answer the routine permission requests of your agents from a file you write, so you only read the requests that need a person. No model is involved: the daemon compares each request with your rules.
- Create the file:
smind policy initwrites~/.smind/steward/policy.yamlwith every example commented out and no active allow rule. It refuses to overwrite an existing file. - Add the rules you want. Edit the file by hand; nothing in smind, no agent and no relay session can write it.
- Turn the engine on with
steward.policy.enabled: trueinconfig.yaml. The daemon reads the file again whenever it changes, with no restart.
How a request is decided:
- A request nothing allows is asked, exactly as without the policy. If nobody answers within 5 minutes it is denied.
denybeatsask, andaskbeatsallow, whatever the order in the file.- A command is split into its simple commands. An
allowneeds a rule for every one of them; anything smind cannot parse with certainty (an unbalanced quote,eval,bash -c "$x", process substitution) is asked. - Paths are resolved through symlinks before they are compared with a rule's
paths.within. - A short list of commands is always denied, whatever your file says:
git stash, force pushes, merging or releasing, anything that touches your smind home or the daemon's port, killing processes, secret dumps, writes outside the task worktree,curl | sh, pointing a test'sHOMEat your real home, andgit add -A. The denial names the rule. - If the file is invalid, smind applies only that fixed list and asks about everything else.
Every decision is recorded in an audit log that you can read and that smind keeps for 90 days. Commands are shown with secrets masked and heredoc bodies left out.
smind policy show # validity and the rules in force
smind policy test "git push origin my-branch" # explain a decision, no side effects
smind policy audit # recent decisions (--json for scripts)On Windows
The engine works on Windows with the same rules. Paths may use drive letters (any case), UNC names, and \ or /; comparison is case-insensitive, and links and junctions are resolved before comparing. %USERPROFILE%, ~ and $HOME are all your home. The always-denied list also covers C:\Windows, Program Files, ProgramData and AppData, and the PowerShell and cmd equivalents of rm, copy and move, Get-Content of secrets, Get-ChildItem Env:, and iwr … | iex. A command string passed to powershell -Command, pwsh -c or cmd /c is read in its own syntax and the commands inside it are checked like any other, so the always-denied list and your deny and ask rules apply to them; the wrapper itself is never auto-approved. A string the engine cannot read with certainty (an encoded command, a script block, escape characters, a variable that builds the command) is asked. Anything the engine cannot place on Windows (C:foo, \\.\pipe, file:stream, trailing dots) is asked or denied, never allowed.
This does not narrow a provider mode that already approves everything (bypassPermissions, --auto-accept): those requests never reach smind. It is a convenience for your own routine commands, not a sandbox.
Connect other tools over MCP
smind mcp serve runs an MCP server on stdio, so an agent (Claude Code, Cursor and others) can drive smind tasks without shelling out:
{ "mcpServers": { "smind": { "command": "smind", "args": ["mcp", "serve"] } } }The daemon must already be running. task_send returns a run ID at once, and task_wait blocks until the run ends, a permission is pending, or its timeout passes.
The server deliberately has no approval tools. An agent can show you a pending permission, but only you approve it, in the web UI or with smind task approve. For the same reason an agent cannot turn on auto-approval itself.
smind mcp add, ls, rm, enable and disable manage the MCP servers that your agents use. See the CLI reference.
Set up worktree dependencies
Each task gets a fresh git worktree with no node_modules. A workspace setup script runs once, in the background, when a task is created:
smind workspace setup set <workspaceId> --setup-file setup.sh
smind workspace setup show <workspaceId>The script runs with sh -c and the daemon's PATH. While it runs the task counts as busy, so a smind task send right after task new needs --when-busy queue. The prompt is delivered when setup finishes.