# Workspace trust

Helix has several features that can execute arbitrary code:

- Language servers (LSP)
- Debug adapters (DAP)
- Local workspace configuration (`.helix/config.toml`, `.helix/languages.toml`)
- Git integration (filters and other commands in a repository's `.git/config`)

To protect against malicious projects (a checked-out PR, a freshly cloned
repository, etc.) Helix gates these behind explicit per-workspace trust.
By default language servers start automatically (their binaries come from
`$PATH`, not from the workspace) and debug adapters may be launched, but
loading `.helix/config.toml` or `.helix/languages.toml` and trusting a
repository's `.git/config` requires opting in. Note that debug adapters
are never started automatically — you launch them yourself — but the same
trust level still gates whether they may run. The model is intentionally
similar to [direnv](https://direnv.net/): you run `:workspace-trust` once
per workspace and Helix remembers across sessions.

## Granting trust

When Helix opens a file inside a workspace it has never seen before, a
modal trust prompt asks:

- **Trust** — allow the workspace permanently.
- **Never** — exclude the workspace; never prompt again.

`<Esc>` (or any other dismissal) caches "untrusted for this session" so
the prompt doesn't re-fire for every file you open in the workspace. The
next time you start Helix in that workspace, it'll prompt again.

A small `[⚠]` indicator appears in the bottom-right of the editor (next
to the macro-recording `[@]`) whenever the workspace is in restricted mode
*and* running `:workspace-trust` would change observable behavior — i.e.
when there's a local config to load or an LSP that would start.

You can also run `:workspace-trust` / `:workspace-untrust` /
`:workspace-exclude` directly from the typed command prompt.

## Revoking trust

Run `:workspace-untrust` to revoke a workspace's trust grant. The next time
you open a file in that workspace, you're back to the untrusted hint.

## Detecting changes after trust was granted

When you trust a workspace, Helix records a hash of every file under
`.helix/`. If those files change afterwards (a malicious checkout, an
inadvertent rebase, etc.) Helix detects the mismatch on the next open and
reports the workspace as *stale*:

```
Workspace `.helix/` config changed since `:workspace-trust`. Local config
not loaded. Run `:workspace-trust` to re-allow.
```

In the stale state, language servers continue to run (they use the
globally-configured binaries on `$PATH`, which are unchanged), but
`.helix/config.toml` and `.helix/languages.toml` are not loaded. Run
`:workspace-trust` again to re-pin the new hash.

## Storage

Trust grants live in `data_dir()/workspace_trust/`, one small file per
workspace. The filename is the SHA-256 of the workspace's absolute path;
the contents look like:

```
path = /home/user/proj1
hash = sha256:abc123...
excluded = false
```

- Linux, macOS: `~/.local/share/helix/workspace_trust/`
- Windows: `%AppData%\Roaming\helix\workspace_trust\`

The one-file-per-workspace shape is safe under multiple concurrent Helix
instances — different workspaces never write the same file.

## Configuration

Settings live under `[editor.workspace-trust]`:

| Key       | Values                              | Default     | Effect                                                                       |
| ---       | ---                                 | ---         | ---                                                                          |
| `level`   | `"none"`, `"servers"`, `"insecure"` | `"servers"` | What is auto-trusted in every workspace. See below.                          |
| `prompt`  | `true`, `false`                     | `true`      | Whether to surface the modal popup. The `[⚠]` indicator is shown regardless. |
| `trusted` | list of glob patterns               | `[]`        | Workspaces matching a pattern are trusted without a grant. Discouraged; see below. |

### Recommended setups

**Default: trust servers, prompt before loading workspace config.**

```toml
[editor.workspace-trust]
level = "servers"
prompt = true
```

Language servers start automatically in every workspace — their binaries
come from `$PATH` and are not workspace-controlled — and debug adapters
you launch are allowed to run. The modal only appears when opening a file
in a workspace whose `.helix/config.toml` or `.helix/languages.toml` would
unlock something. Trust everything else with one keystroke per workspace,
deny with another.

**Maximum security: never prompt, trust each workspace by hand.**

```toml
[editor.workspace-trust]
level = "none"
prompt = false
```

Nothing trusts implicitly: language servers, debug adapters, local
config, and git `Trust::Full` are all off until you run
`:workspace-trust`. The popup never appears; the `[⚠]` indicator in the
bottom-right is your only signal that the current workspace is
restricted. Suited to users who would rather grant trust as a
deliberate action than dismiss a dialog.

> [!WARNING]
> `level = "insecure"` is highly discouraged. It implicitly trusts every
> workspace you open, which defeats the protection entirely: a
> checked-out PR with a malicious `.helix/config.toml` would get its
> configuration loaded and any language server it defines launched, with
> no prompt and no indicator. Only set this if you accept full
> responsibility for what's in every project directory you `cd` into.

### Trusting workspaces by path (discouraged)

If you keep all your repositories under a predictable layout, you can
trust them in bulk with glob patterns instead of granting each workspace
individually:

```toml
[editor.workspace-trust]
trusted = [
  "~/src/github.com/me/*",
  "~/work/repos/*",
]
```

A workspace whose path matches a pattern is trusted for everything, just
as if you had run `:workspace-trust` in it. `~` and environment variables
are expanded.

> [!WARNING]
> This is weaker than an explicit grant and is discouraged. It skips the
> `.helix/` change detection entirely (a malicious checkout under a
> matched directory is never flagged as stale), and it trusts *any*
> repository that later lands under a matching path — including one you
> clone into `~/src/github.com/me/` from an untrusted source. Prefer
> granting trust per workspace; reach for this only if the prompts are
> genuinely disruptive to your workflow. An explicit `:workspace-exclude`
> still overrides a matching pattern.

## Git trust

Workspace trust also gates how Helix opens git repositories. Untrusted
workspaces are opened in [gix](https://github.com/Byron/gitoxide)'s
`Trust::Reduced` mode; trusted workspaces use `Trust::Full`.

Under `Trust::Reduced`, gix still runs the full filter pipeline (so
built-in conversions like `core.autocrlf` keep working) but ignores
configuration coming from the untrusted, repository-local `.git/config`.
That means `filter.*.clean` / `filter.*.smudge` drivers and similar
keys that would otherwise execute external programs are dropped until you
trust the workspace.

Helix forces this trust level explicitly rather than letting gix infer it
from `.git` directory ownership — a malicious `.git/config` in a directory
you happen to own is still treated as untrusted until you run
`:workspace-trust`.
