Browse docsWorkspaces

Workspaces

A workspace is where an agent works. It is the provider’s working directory, the context it starts with, and the default home for files that belong to that workspace. It is not a sandbox: an explicit task or workspace rule may name another destination.

Enso is opinionated about this. The layout below is fixed, Enso creates it, enso workspace audit proves it is still intact, and --fix repairs it. The point is that every path the agent is told about in AGENTS.md actually exists, and that skills are wired up rather than assembled by hand.

Quick start

enso workspace create research
enso config set bindings.slack:C0123456789 research
enso workspace audit research

Use your actual Slack channel ID and invite the bot there. The binding applies to the next message without a restart. Telegram and private-message keys are described in Bindings.

Layout

~/.enso/workspaces/<name>/
├── AGENTS.md          # purpose, scope, terms, approval rules for this workspace
├── CLAUDE.md          # symlink -> AGENTS.md
├── skills/            # skills unique to this workspace
├── knowledge/         # durable reference material the agent should keep
├── drafts/            # generated or editable output
├── uploads/           # chat attachments, one directory per turn
├── .claude/skills     # symlink -> ../skills, read by Claude Code and Grok
├── .agents/skills     # symlink -> ../skills, read by Codex, Grok, Antigravity, and OpenCode
└── .claude/settings.json, .codex/config.toml, .grok/config.toml, opencode.json
                       # optional: each CLI's own policy file; required when restricted
Directory What belongs there
knowledge/ Things that stay true. Reference notes, extracted facts, research the agent should be able to find next week.
drafts/ Generated or editable work: posts, reports, and scratch analysis. Review before deleting.
uploads/ Chat attachments. Enso writes here; nothing else should.
skills/ Skills only this workspace needs.
Policy files Each CLI’s own project-level permission file, in its own format. Optional, unless the workspace is restricted.

Names are lowercase kebab-case (meteor, blog-research), at most 64 characters. The name is the directory name, and there is no other valid location.

The knowledge feature adds shared reference at ~/.enso/knowledge/ (or $ENSO_HOME/knowledge/ for a custom home) and automatically discovers each workspace’s knowledge/ for the reader. Use workspace knowledge for its own context and shared knowledge for material used across workspaces. Both support nested folders and links; see Knowledge for the format and migration guide.

Memory records a conversation’s workspace alongside its dated exchanges in enso.db. Agents can filter recall to that workspace; these records do not create files in its knowledge/ directory. Workspace filters organize context, not access permissions.

AGENTS.md is the file you write; CLAUDE.md is always a symlink to it so both CLI families read one document. Skills follow the same rule: skills/ is the directory you write, and the two dot-directories are symlinks to it that the provider CLIs discover. One source of truth, generated links everywhere else. Keep AGENTS.md short — what the workspace is for, what ambiguous terms mean, and any rule that must be visible on every single turn. Detail belongs in knowledge/, referenced by path. See Customizing.

enso init prepares this layout for default, filling missing instructions and links without changing existing files. It reports conflicting files, directories, and links instead of replacing them. This also makes an interrupted initial scaffold safe to rerun; see Non-interactive setup. The ordinary workspace audit retains its separately documented repair behavior.

Uploads

Chat attachments download into <workspace>/uploads/<id>/, one directory per turn, for both Slack and Telegram. The agent is given the local paths in its prompt.

A Slack attachment is named by Enso: an opaque token, then a short readable tail taken from the original name, so nothing a sender chooses decides a path. Slack file metadata is otherwise untrusted too, so a file is fetched only from Slack’s own file-download endpoint and one that names anywhere else is skipped without a request. A Telegram attachment keeps its own filename, sanitized.

These are retained on purpose — an agent may need to come back to a file the next day — and Enso never deletes them. enso workspace audit reports the total size so you can decide when to clear it out.

Skills

Skills resolve across three scopes.

Scope Location Who owns it
Workspace <workspace>/skills/<name>/SKILL.md You, for this workspace only
Enso ~/.enso/skills/<name>/SKILL.md You, bundled skills, and installed official optional skills
User Your CLI’s own user directory, see below You, entirely outside Enso

Enso ships its core skills into ~/.enso/skills/; see the bundled skill list. enso init and enso setup write a missing bundled skill and preserve existing copies. Managed upgrades refresh only bundled files that match their recorded baseline; edits and tracked deletions are preserved. enso and the enso- prefix are reserved for what Enso installs, skills and jobs alike, so the audit warns about a name in that namespace it did not put there. See Customizing for the owning rules.

Skill names must be unique across the workspace and enso scopes. A workspace does not override an enso-wide skill by reusing its name; the audit reports that as an error, because the provider CLIs disagree about which copy would win (see the table below). A name that collides with one of your user-level skills is a warning.

How they reach the agent

Every provider CLI discovers project skills by walking from its working directory up to the nearest Git root, following symlinks on the way. The working directory is the workspace and the Git root is the Enso home (enso init and enso setup prepare it), so two symlinks in each place put both Enso scopes in reach:

~/.enso/.claude/skills                    -> ../skills
~/.enso/.agents/skills                    -> ../skills
~/.enso/workspaces/<name>/.claude/skills  -> ../skills
~/.enso/workspaces/<name>/.agents/skills  -> ../skills

These links are static. Add or edit a skill in <workspace>/skills/ or ~/.enso/skills/ and the next turn can load it; no Enso restart or link regeneration is needed. The provider CLI discovers the files when Enso launches it for a turn. enso workspace audit --fix creates a missing link and repairs one that points elsewhere.

The home-level AGENTS.md reaches the agent the same way: Codex, Grok, Antigravity, and OpenCode walk up to the Git root for AGENTS.md, and Claude Code walks up for CLAUDE.md. That is why the home must be a Git root, and the audit checks that it still is.

The runtime discovery reference records version-specific provider behavior. Enso requires unique names instead of relying on different providers to resolve collisions the same way.

Antigravity is the odd one out: its working directory is the folder registered for a project in ~/.gemini/config/projects/, not the shell’s cwd. Started without a project it discovers nothing — not the skills above, not any AGENTS.md. So on the first turn Enso launches agy with --new-project, which registers the workspace, and pins every later launch to that project id. Nothing is asked of you, and nothing in the workspace changes; see Configuration.

OpenCode needs no registration and no extra workspace link: it reads the existing .agents/skills links directly. Its native user-level skills are the skill/ and skills/ directories below each of its configuration roots, and both names below both roots are scanned by Enso, alongside the Claude-compatible user directories OpenCode also loads:

Root Where it is
Global configuration $XDG_CONFIG_HOME/opencode when that variable is set and non-empty, otherwise ~/.config/opencode
Additional configuration The directory OPENCODE_CONFIG_DIR names, when it is set and non-empty

OPENCODE_CONFIG_DIR adds a root rather than moving the global one, and it does not move OpenCode’s global AGENTS.md, which stays at the global root. Two roots that resolve to the same directory are scanned once.

User-level skills are found by each CLI on its own, and so are your user-level instructions (~/.claude/CLAUDE.md, ~/.codex/AGENTS.md, ~/.gemini/AGENTS.md, and AGENTS.md at OpenCode’s global root above, so ~/.config/opencode/AGENTS.md by default). They apply inside Enso too. Enso scans the user-level skill directories so the audit and the web viewer can show the full skill picture, but it does not read user-level instruction files or write either kind of file. If another tool manages them, Enso stays out of its way. In a listing a user-level directory counts as a skill when it has a SKILL.md; Enso does not validate its contents, and a name present in more than one of those directories is shown once.

None of the CLIs require the frontmatter name to match the directory name; all of them use the directory name as the skill’s identity. Enso requires the match anyway, so that what you see in a listing is the directory you edit.

Auditing

enso workspace audit                 # the home and every workspace
enso workspace audit meteor          # the home and one workspace
enso workspace audit --fix           # repair what can be repaired, then report the rest
enso workspace audit --json          # machine-readable, for scripts and the viewer

The audit checks, each finding carrying the check id shown:

Check Id Severity --fix behaviour
Required directories exist inside an existing workspace directory error Creates them
CLAUDE.md is a symlink to AGENTS.md link error Creates or repoints the link
.claude/skills and .agents/skills are symlinks to ../skills link error Creates or repoints the link
The home is a Git root, and no workspace is one git-root error Runs git init in the home
The home has AGENTS.md, skills/, and the same three links agents-md, directory, link error Creates skills/ and the links
AGENTS.md exists agents-md error Reports only
AGENTS.md is not still the untouched template agents-md warning Reports only
Every skill directory has a SKILL.md whose name matches the directory skill error Reports only
No skill name appears in both the workspace and enso scope skill-collision error Reports only
No skill name collides with a user-level skill skill-collision warning Reports only
No enso-* skill or job exists that Enso did not install reserved warning Reports only
The workspace is bound, or named by a job orphan warning Reports only
A restricted workspace passes its chat provider’s policy prerequisite check policy error Reports only
Unexpected entries at a workspace’s top level, or under workspaces/ unexpected warning Reports only
uploads/ size — — Reported as a number

A passing policy check covers only the chat provider’s launch prerequisites. It neither tests a denial nor checks providers used only by jobs or beats. Follow the verification and troubleshooting guide to check the permissions you intend.

With the knowledge feature, the home directory check also requires knowledge/; --fix creates it when missing without changing its contents. Use enso knowledge audit separately to check the pages’ metadata and links.

--fix only ever creates and repairs. It never deletes a file, never edits AGENTS.md, and never touches anything under knowledge/, drafts/, or uploads/. A real file or directory sitting where a link belongs is reported and left for you to move aside. Fixes run first and the report shows what remains, so a second --fix finds nothing to do.

The command exits 1 while any error remains and 0 otherwise; warnings never fail an audit. An orphan workspace — one nothing is bound to and no job names — is a warning, not an error. So is an unexpected top-level entry: Enso tells you it is there and leaves it alone. Files the CLIs themselves drop inside .claude/, such as Claude Code’s .cc-writes/, are expected and not reported, and neither is .DS_Store.

--fix repairs directories inside an existing workspace; it does not recreate an entire missing workspace. Use enso workspace create NAME to scaffold one.

A workspace with its own .git is an error that --fix does not touch. The CLIs stop their walk at the nearest Git root, so a repository inside a workspace hides the home’s AGENTS.md and skills from the agent. Keep the repository elsewhere.

--json prints one object: ok, the home, and one entry per workspace.

{
  "ok": false,
  "home": {"path": "/Users/you/.enso", "status": "ok", "findings": [], "fixed": []},
  "workspaces": [
    {
      "name": "meteor",
      "path": "/Users/you/.enso/workspaces/meteor",
      "status": "error",
      "bindings": ["slack:C0123456789"],
      "jobs": ["meteor-forum-watch"],
      "uploads_bytes": 1048576,
      "findings": [
        {"check": "directory", "severity": "error", "message": "drafts/ is missing", "fixable": true}
      ],
      "fixed": []
    }
  ]
}

status is the worst severity present (error, warning, or ok), fixed lists what --fix did on this run, and fixable says whether --fix would repair a finding. The same report backs enso workspace list’s audit column, the warning enso serve logs at start, and the web viewer.

enso doctor runs the workspace audit alongside a config check, the provider paths, and the service status, for one strict answer to “is this machine healthy”. It exits 1 on an audit error even when serve can continue as described below; see CLI.

Creating and retiring

enso workspace create meteor

Scaffolds the full layout, seeds AGENTS.md from the template, and creates the skill links. Then bind a conversation to it in config.json; the next message in that conversation lands in the new workspace, with no restart. See Configuration.

enso workspace list shows every workspace with the bindings pointing at it, the jobs naming it, and its audit summary.

To retire one, remove or repoint its bindings and jobs, and repoint any projects that name it while preserving their tasks. Inspect active and paused beats with enso heartbeat list --workspace NAME, paging through results if needed; move ongoing beats to another workspace or explicitly close work that is ending. Pausing a beat keeps its workspace reference. Keep the directory while any of those dependents still needs it.

Let running turns, jobs, and beats finish before moving files, and remove the retired workspace’s configuration override when present. Run enso config check before and after archiving or deleting the directory; deletion needs the user’s authorization. These changes need no Enso restart. Configuration validation catches missing binding and project directories, but it does not inspect heartbeat state, so the beat review is a separate step. Enso does not delete a workspace for you.

When a workspace is malformed

A bound workspace that fails its audit is a warning at service start, not a fatal error. It is logged, the viewer shows it, and turns still run. A missing drafts/ should not take your chat bridge down. The same goes for a workspace a job names, and for the home itself: enso serve logs one line per failing root, naming the errors, and points at enso workspace audit.

The exception is a bound workspace directory that does not exist at all: config check treats that as a problem and enso serve refuses to start. If a bound directory disappears while the service is running, the next read of config.json fails the same check: the service logs that once and keeps the last valid configuration, a turn bound to the missing directory fails when its provider cannot start there, and other conversations and jobs continue. A missing directory named only by a job is a job validation problem: that job cannot run, while the service and other jobs can continue.