Security and policies
Enso runs agent tools on a machine you control. A workspace organizes their context;
the provider CLI’s permissions determine what those tools can do. Instructions in
AGENTS.md guide the model, but do not enforce filesystem or network restrictions.
Workspaces are unrestricted by default. Setup records unattended provider flags, including Codex’s flag that disables its sandbox. Before connecting sensitive files or a shared chat, choose the provider permissions you want and test them.
What restricted means
Set workspaces.NAME.restricted to true to require a provider policy file before
Enso starts that workspace’s chat provider, job provider, or heartbeat assessment.
Enso checks:
- The expected policy path exists as a file.
- The effective provider arguments do not contain a bypass flag Enso recognizes.
Currently these are Codex’s
--dangerously-bypass-approvals-and-sandboxand--yolo. - For Codex and Grok, the Enso home is trusted in that provider’s own user
configuration. Grok also accepts
--trustin the workspace’s arguments instead.
A failed check prevents that provider invocation and reports what is missing. An empty or invalid policy can still pass Enso’s file check: Enso does not parse the rules or prove that the provider enforces them. Other flags and provider configuration can change the effective permissions.
| Provider | Policy path inside the workspace |
|---|---|
| Claude Code | .claude/settings.json |
| Codex | .codex/config.toml |
| Grok | .grok/config.toml |
| OpenCode | opencode.json |
Antigravity has no supported workspace policy. Enso refuses agy in a restricted
workspace; choose another provider before enabling the restriction.
Scripts and background work
The restriction checks provider invocations. Job prerun/postrun scripts, heartbeat gates, and workflow commands, checks, and lifecycle scripts run as ordinary processes with the service account’s access. They do not inherit the provider’s sandbox. A prerun or gate can run even when the provider’s policy is missing; a command-only stage does not need a provider policy at all. See Jobs, Heartbeat, and workflow availability.
A job or beat can use a different provider from chat. If chat uses Claude and a job uses Codex, the workspace needs both policy files and each provider’s launch settings.
Example: read-only Codex
This example lets Codex inspect files without writing through its sandboxed tools. It does not limit reads to the workspace or remove secrets from the environment. Review connected tools separately; filesystem permissions do not define what a remote service will let a tool do.
Start with an initialized Enso home and Codex installed, signed in, and configured
under providers.codex. The example uses the configured model sol; substitute a
model from enso config show if your configuration differs. Run setup commands from
your own terminal, outside an Enso agent run. Paths below use the default ~/.enso;
substitute your ENSO_HOME when it differs.
1. Create the workspace and policy
enso workspace create research
mkdir -p ~/.enso/workspaces/research/.codex
nvim ~/.enso/workspaces/research/.codex/config.toml
Put these settings in that file. When adapting an existing workspace, merge them with its configuration instead of replacing unrelated settings.
sandbox_mode = "read-only"
approval_policy = "never"
never disables approval prompts; it does not disable the sandbox. An action outside
the sandbox must remain denied. OpenAI documents this combination for
non-interactive read-only use.
2. Trust the Enso home
Codex loads project configuration only under a trusted root. Enso’s root is the home,
not workspaces/research. Find its absolute, resolved path:
cd ~/.enso
pwd -P
In ~/.codex/config.toml (or $CODEX_HOME/config.toml), add or update the entry for
that exact path. Use the actual path in place of this example, without a trailing slash:
[projects."/Users/you/.enso"]
trust_level = "trusted"
This trusts the root used by all workspaces in that home. It does not grant them write access. CLI flags can still override project settings; see Codex configuration precedence.
3. Select the provider and enable the check
enso config set workspaces.research.agent '{"provider":"codex","model":"sol","effort":"high"}'
enso config set workspaces.research.providers.codex.args '[]'
enso config set workspaces.research.restricted true
enso workspace audit research
The empty argument list replaces the global list, removing setup’s bypass flag.
Enable restricted last, after the policy and trust entry are ready. These Enso
settings apply to subsequent work without a service restart; finish active work
before changing its permissions.
4. Try a harmless denied action
Create a small text file at knowledge/policy-probe.txt yourself. Confirm that
drafts/policy-probe.txt does not already exist, then run from the workspace:
cd ~/.enso/workspaces/research
codex exec 'Read knowledge/policy-probe.txt, then try to create drafts/policy-probe.txt containing only probe. Report the actual tool results.'
The read should succeed and the write should be denied. Inspect the tool result and
confirm the output file is absent; a model saying it complied or a successful process
exit is not proof. This uses your provider account. Repeat through a chat bound to
research to check the Enso path too; bindings explains
how to select that workspace.
For a workspace that needs to write drafts, change sandbox_mode to workspace-write
and keep approval_policy = "never". Test both an intended write and a prohibited one
outside its writable roots. This remains a provider sandbox, whose writable roots and
protected paths follow Codex’s rules.
The sandbox limits which files a command may touch, not which commands may run. Codex
also reads command rules from .codex/rules/*.rules beside the workspace’s config.toml,
under the same trusted root. To refuse one command, add
~/.enso/workspaces/research/.codex/rules/enso.rules:
prefix_rule(pattern=["enso", "config"], decision="forbidden")
Example: selected commands in Claude Code
Suppose a workspace should inspect files and run pwd and git status, while other
commands that need approval should be denied without waiting for a person.
Start with Claude Code installed, signed in, and configured under providers.claude.
enso workspace create review
mkdir -p ~/.enso/workspaces/review/.claude
nvim ~/.enso/workspaces/review/.claude/settings.json
Save this policy, merging with existing settings when applicable:
{
"permissions": {
"allow": ["Bash(pwd)", "Bash(git status)"],
"deny": ["Bash(enso config *)", "Bash(touch *)", "Edit", "Write"]
}
}
Then select an existing configured model and replace the unattended bypass arguments:
enso config set workspaces.review.agent '{"provider":"claude","model":"opus","effort":"high"}'
enso config set workspaces.review.providers.claude.args '["--permission-mode","dontAsk"]'
enso config set workspaces.review.restricted true
enso workspace audit review
In dontAsk mode, calls that would prompt are denied. File reads and other actions
that need no approval still run, as can tools allowed by other settings. This example
controls named tools and commands; it is not an operating-system sandbox. See
Claude Code permissions for matching and
configuration precedence.
From the workspace, test one allowed command and one explicit denial:
cd ~/.enso/workspaces/review
claude --permission-mode dontAsk -p 'Run pwd, then try touch drafts/policy-probe.txt. Report the actual tool results.'
Start with no probe file. pwd should run and touch should be denied; inspect the
tool result and verify no file was created. Repeat through the bound Enso chat.
Setup’s --dangerously-skip-permissions is unsuitable for this allowed-command
example: Enso’s earlier checks found deny rules still applied under that flag, but
allow rules did not narrow its access. Use the complete dontAsk override above.
Grok and OpenCode starting policies
These minimal policies deny the plain enso config command. Add the actions your
workspace must prohibit; these examples do not otherwise lock down its access.
As above, configure the provider first, write its file, set its complete workspace
argument list, then enable restricted and verify behavior.
Grok
In the workspace’s .grok/config.toml:
[permission]
deny = ["Bash(enso config *)"]
Set workspaces.NAME.providers.grok.args to ["--always-approve", "--trust"].
--trust records trust for the home. Alternatively, add this entry to
~/.grok/trusted_folders.toml (or $GROK_HOME/trusted_folders.toml) and omit --trust:
[folders."/Users/you/.enso"]
trusted = true
Use the home’s resolved absolute path; Grok also accepts its trailing-slash spelling.
From inside the workspace, grok inspect --json should report projectTrusted: true
and permissions.loaded greater than zero. Also test an intended allow and denial.
OpenCode
In the workspace’s opencode.json:
{
"permission": {
"bash": {
"*": "allow",
"enso config *": "deny"
}
}
}
Set workspaces.NAME.providers.opencode.args to ["--auto"]. Put broad patterns
before specific ones because the last matching rule wins. --auto approves requests
that the policy does not deny. See OpenCode permissions
for other tools and file access. From the workspace, use
opencode run --auto "Run enso config show" to test the denial; it should not print
the configuration.
Earlier Enso verification on September 10, 2026 used Codex 0.153.4, Grok 1.0.13, and OpenCode 1.18.27; the Claude version was not recorded. Those observations are not a guarantee for every version. Recheck after CLI upgrades or changes to provider flags, user configuration, plugins, or tools.
Auditing and troubleshooting
enso workspace audit NAME checks the home and that workspace against Enso’s expected
layout, and adds one policy check for the workspace’s chat provider only. It does
not parse policy rules, test a denied action, or validate every provider used by jobs and
beats. --fix does not write a policy for you.
The command exits 1 while any error remains and 0 otherwise; warnings never fail it.
Add --json to check it from a script. enso doctor reports the
same audit beside configuration, provider, transport, and service checks. enso serve
logs a startup warning for a failing workspace that is bound or named by a job, and then
keeps running: that warning is a notice, not a refusal.
For example, a Claude chat workspace can pass its audit while a Codex job in the same
workspace fails because .codex/config.toml is missing. Review each job’s agent and
each beat’s saved agent, then verify the provider they actually use.
| Symptom | What to check |
|---|---|
| Missing policy error | Put a file at the exact provider path inside the workspace. A directory at that path does not count. |
| Codex bypass error | Replace the workspace’s entire Codex argument list; check for both bypass spellings. |
| Trusted-root error | Use the resolved home path in the provider’s own trust configuration, not the workspace path. |
| Audit passes but actions are allowed | Inspect policy syntax, loaded configuration, other flags, and the actual tool used. A file-presence check cannot establish enforcement. |
| Chat works but a job or beat fails | Check its saved provider and workspace; chat defaults do not replace its agent. |
| Agent cannot change its own settings | Make the intended change from your own terminal after active work finishes. |
Limits and shared access
Policy files are not protected by Enso. A provider with sufficient file access
can edit its policy or config.json directly. A command deny rule covers matching
commands, not every way to produce the same effect. The enso config guard also
depends on the caller’s ENSO_WORKSPACE environment variable, which a process can
change. These measures help prevent accidental changes; hostile-process isolation
requires separately enforced OS/provider controls and protected controller state.
Chat access grants access to the agent’s capabilities. Telegram requires a private chat, an allowed user, and a binding. Slack channel bindings accept human participants subject to mention/thread rules; Slack has no Enso per-user allowlist for a bound channel. A mention requirement does not identify an authorized person. For personal use, bind your DM; for shared use, choose channel membership and provider permissions accordingly. See chat access.
Credentials and connected accounts are shared resources. Values loaded from
secrets/*.env are inherited by agents across
workspaces. A workspace does not create a separate OS account. Browser profiles
contain signed-in sessions, and
Cloud teams share the instance.
Enso’s own commands are not scoped to one workspace. Where the development
Knowledge and Memory
features are installed — neither is in v0.1.2 — an agent can list and print another
workspace’s notes with enso knowledge list|show --scope workspace:<name>, and read
conversation summaries from every workspace with
enso memory search "deploy" --all-workspaces. The bundled memory-refinement job
also runs in the default workspace, on batches that can include exchanges captured in a
restricted one. Workspaces organize context; they are not an access-control boundary.
Read-only viewing still exposes private data. The web viewer has no built-in authentication and can show files, prompts, and logs. Keep it on loopback or behind authenticated access.
Instructions are guidance. Treat fetched pages, attachments, and tool output as untrusted data. Instructions and skills can tell an agent to ignore embedded commands, but do not guarantee resistance to prompt injection or grant new action approvals.
