Browse docsSecurity and policies

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:

  1. The expected policy path exists as a file.
  2. The effective provider arguments do not contain a bypass flag Enso recognizes. Currently these are Codex’s --dangerously-bypass-approvals-and-sandbox and --yolo.
  3. For Codex and Grok, the Enso home is trusted in that provider’s own user configuration. Grok also accepts --trust in 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.