---
name: environments
description: Save verified software setups for reuse across Dench chats, children and automations. Covers dench env, encrypted workspace credentials, dench-env.json, dependency preparation, revision pinning, explicit mutable state, and local execution.
---

# Saved environments

Use a saved environment when the user asks to reuse scripts, installed packages,
configuration, or custom services across future chats. Ordinary one-off shell
work does not require one. Prefer an existing native Dench command or connected
integration when it already supports the requested task.

Keep the storage boundaries clear:

| Data | Save it with |
| --- | --- |
| Facts, decisions and explicit preferences | `dench memory save` |
| Standing instructions and workspace/personal background | `dench context` |
| Installed packages, scripts and nonsecret configuration | `dench env save` |
| API keys and credential files | `dench secrets set` |
| Shared business records | `dench crm` |
| Documents and outputs | `dench files` / `dench stage` |

Memory is not proof of setup. Confirm an environment's preparation receipt and
required credential metadata before saying it is ready. `dench cron secret`
only manages inbound automation webhook signing; it cannot store an API key.

## Commands

```sh
dench env list --json
dench env show openai-report --json
dench env save openai-report --path ./openai-report --wait 10 --json
dench env run openai-report -- node report.mjs
dench env run openai-report --revision <sha256> -- node report.mjs
dench env delete openai-report --json

dench secrets set OPENAI_API_KEY --stdin < /private/path/openai-key.txt
dench secrets set REPORT_CREDENTIALS --file /private/path/credentials.json --kind file
dench secrets list --json
dench secrets delete OPENAI_API_KEY --json
```

Environment names are lowercase slugs. Secret names use uppercase letters,
digits and underscores. Secret values go through stdin or a file, never a
command argument. Both kinds accept nonempty UTF-8 text without NUL, up to
64 KiB; binary credential files are not supported. In Dench chat, use the existing masked credential question
when user input is needed; its result is a storage receipt, not the value.

`env save` observes preparation for up to 10 seconds by default. Use `--wait N`
(0–600 seconds) or `--no-wait`. A `pending`/`building` result is a durable
preparation receipt, not a ready environment. A failed update leaves the
previous ready revision usable. Saving the same source again explicitly retries
a failed preparation; it does not repeat a business operation.

## Manifest and source files

The selected directory must contain `dench-env.json` and `SKILL.md`. List only
the files or directories intended for reuse in `files`. The two required files
are included automatically. Source uploads contain regular files only, with
relative paths and safe permissions; symlinks, path traversal, credential files,
package caches and installed dependency folders are rejected.

Example `dench-env.json` for a project with an existing npm lockfile:

```json
{
  "version": 1,
  "name": "openai-report",
  "purpose": "Generate the requested report with the team's OpenAI account",
  "files": ["report.mjs", "package.json", "package-lock.json"],
  "prepare": ["npm ci --omit=dev"],
  "verify": ["node --check report.mjs"],
  "env": { "REPORT_FORMAT": "markdown" },
  "secretEnv": { "OPENAI_API_KEY": "OPENAI_API_KEY" },
  "secretFiles": [],
  "statePaths": ["state"],
  "portable": true
}
```

`SKILL.md` should briefly explain when to use the setup, its commands, input and
output paths, and required credentials. Do not copy global harness rules into it.
Configuration in `env` and source files must be nonsecret. For a credential file,
declare `{"path":"config/auth.json","secret":"REPORT_CREDENTIALS"}` in
`secretFiles`. Add `"mutable":true` only when the application refreshes that
credential and its updated bytes need encrypted persistence.

Credential-file paths are relative to the execution workspace, which is also
the command's `HOME`. `config/auth.json` is read as `./config/auth.json`;
`.config/service/auth.json` is read as `$HOME/.config/service/auth.json`.
`XDG_CONFIG_HOME` points to that `.config` directory. Use the path the actual
tool expects; there is no extra `.home` directory or shared developer home.

Preparation runs once while publishing the revision. Verification runs without
credentials: check imports, binaries, configuration shape and tests that do not
contact a private service. `verify` must contain at least one command. A saved
credential is checked at execution; secret values never enter prepared images
or dependency bundles. Do not put `dench`, its login files, or platform API keys
in the reusable package set.

For Python, create a project-local `.venv` during preparation and install pinned
requirements into it. For example, `python3 -m venv --copies .venv` followed by
`.venv/bin/python -m pip install -r requirements.txt`. Save the requirements and
scripts as sources; the built `.venv` belongs to the prepared dependency bundle.
Use `--copies`: absolute interpreter symlinks cannot be safely moved in portable bundles.

The source JSON is limited to 16 MiB and 512 files. A prepared portable bundle
is limited to 128 MiB compressed and 512 MiB unpacked. Set `portable:false` for OS-level dependencies that cannot
be activated as a prepared directory; those need a new sandbox from the saved
snapshot. A running sandbox cannot switch its base operating-system image.

## What is reused

Each logical Harness A job already retains its own sandbox between commands
and continuations. A saved environment makes the setup reusable by other jobs.

| Situation | Preparation cost |
| --- | --- |
| Same job and revision | Reuse prepared files; no install or extraction |
| New job bound to the environment | Start from its prepared snapshot |
| Compatible existing sandbox first uses the environment | Download and extract its prepared bundle once |
| Explicit source update | Build and verify the new revision once |
| Native local CLI on another platform | Explicit local preparation once, then reuse that platform cache |

Only the selected environment is activated. Sandbox allocation, cold image
transfer and first bundle extraction still take time; do not promise zero
startup cost. Changing a credential does not rebuild packages. Dench's launcher
is maintained separately from the user's dependency cache.

The CLI activates the setup in a separate writable directory for each job.
Dependency artifacts are shared by revision; business output and configuration
writes are isolated. Plain `export`, an ad-hoc global installation, or a file
left in a previous chat is not cross-chat persistence.

## Automations, children and state

Bind a ready environment at admission so the first sandbox uses its snapshot:

```sh
dench chat new "Run the report and summarize its output." --environment openai-report --follow
dench cron create "Morning report" --every 1d --environment openai-report --prompt "Run node report.mjs and summarize the saved report."
dench cron update <jobId> --environment openai-report
dench cron update <jobId> --clear-environment
```

The environment is workspace-shared. New automation runs select its latest ready
revision. An active job retains its resolved revision, and children inherit that
revision. Current workspace authorization is checked at execution; deletion or
revocation does not become success merely because a previous run worked.

Mutable state must live under declared `statePaths`. Automation-bound jobs use
an automation-specific namespace; ordinary jobs use a job-specific namespace.
Reserved job and automation namespaces require their owner; native local state
is also isolated by caller. For deliberate cross-job state sharing, use an
explicit custom key:

```sh
dench env run openai-report --state-key reports:shared -- node report.mjs
```

State commits and mutable credential-file updates compare their saved versions.
A concurrent change returns a conflict with recovery evidence; it must not cause
the completed report, send, payment, or other operation to execute again.
Keep credentials out of state paths. Persist user-facing reports through Dench
files or CRM so users can find them independently of execution state.

## Local execution

The native CLI uses the same manifest and authorized credential bindings. A
Linux prepared image is not a macOS/Windows dependency cache. On the first local
use, explicitly allow preparation for that machine:

```sh
dench env run openai-report --prepare-local -- node report.mjs
```

Later runs omit `--prepare-local` and reuse the verified cache. Preparation
commands execute on the local machine with a restricted environment and a
separate setup directory. This is not an OS sandbox. Local Harness A also gives
each job its own home directory; it does not share the developer's home archive.

## Failures and recovery

- Missing credential: store the named value and reuse the same environment.
- Preparation failed: inspect its error code, correct the source/recipe, and save.
- Incompatible runtime or a nonportable late activation: start a new job bound
  to that environment; do not silently reinstall or replace the active sandbox.
- Missing local prepared cache: reuse the published bundle (or explicitly
  prepare the local platform again). If a published sandbox snapshot was
  deleted externally, its ready revision is not rebuilt automatically. Save an
  explicit new source revision, recording the rebuild reason in `SKILL.md`,
  wait for it to become ready, and start a new job. Existing jobs retain their
  original revision; resaving identical sources returns the same ready receipt.
- Revoked access: report the denial once. A previous memory or cached setup
  cannot override current workspace authorization.
- State or credential conflict: retain the receipt and reconcile the stored
  versions. Never rerun a completed external action to reconstruct evidence.
- Legacy setup: import selected sources and credentials explicitly, verify the
  resulting environment, then retire the old archive. Whole-home restoration
  and old filesystem daemons are not part of Harness A's execution path.
