> ## Documentation Index
> Fetch the complete documentation index at: https://docs.charlielabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Environment setup

> Prepare Charlie devboxes for repo-specific dependencies and system packages.

Charlie works best when your repo can set up its own development environment from a fresh clone.

Put setup where your repo already runs after dependency installation. For JavaScript and TypeScript repos, that usually means `postinstall`. Gate Charlie-only work with `IS_CHARLIE=1`, store secrets in dashboard repository environment variables, and use `AGENTS.md` to tell Charlie how to use the environment.

<Note>
  Use this setup path for build, test, and tooling dependencies that can be installed noninteractively. Running services, such as Docker Compose stacks, background processes, or databases, should be documented in `AGENTS.md` and handled as a separate workflow.
</Note>

## What Charlie sets up automatically

Charlie creates repo-specific devbox blueprints so new runs start from a prepared environment instead of a blank machine.

For most repos, Charlie will:

* Clone the repository into the devbox.
* Provide common tools and package categories: Git, Bash, Python, Node package managers, build tools such as `make`, `cmake`, and `pkg-config`, CLIs such as `jq`, `ripgrep`, `curl`, and `gh`, `mise`, and native headers used by frequent Node/image/database-client packages.
* Detect JavaScript package managers and run dependency installation with the repo's normal lifecycle scripts.
* Inject configured repository environment variables from the Charlie dashboard.
* Set `IS_CHARLIE=1` during Charlie runs.

Charlie does not try to guess every apt package your repo might need. If your tests, builds, or tools need extra system packages after dependencies install, declare them in your repo setup.

## Recommended pattern

For JavaScript and TypeScript repos, use this shape for setup that can run after package-manager dependency installation has completed:

<Steps>
  <Step title="Call a setup script from postinstall">
    Keep `package.json` small and route the real work to a script. Do not use this path for apt packages that are required by dependency install scripts or native addon builds; `postinstall` runs too late for those.

    ```json theme={null}
    {
      "scripts": {
        "postinstall": "bash scripts/setup-charlie-env.sh"
      }
    }
    ```
  </Step>

  <Step title="Guard Charlie-only work with IS_CHARLIE">
    The script should exit quickly outside Charlie unless you intentionally support local use.

    ```bash theme={null}
    #!/usr/bin/env bash
    set -euo pipefail

    if [[ "${IS_CHARLIE:-}" != "1" ]]; then
      exit 0
    fi

    sudo DEBIAN_FRONTEND=noninteractive apt-get update
    sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      libpq-dev \
      pkg-config
    ```
  </Step>

  <Step title="Make setup idempotent and noninteractive">
    Design setup so it is safe to run more than once.

    * Use `--no-install-recommends` for apt packages.
    * Pass `DEBIAN_FRONTEND=noninteractive` on each `sudo apt-get` command.
    * Prefer commands that no-op when packages already exist.
    * Do not prompt for input.
    * Do not print secrets.
  </Step>
</Steps>

## Install system dependencies

Use real apt commands for packages that must exist before tests or build tools run, as long as those packages are not required during dependency installation itself.

Example: native database client headers and build metadata:

```bash theme={null}
sudo DEBIAN_FRONTEND=noninteractive apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
  libpq-dev \
  pkg-config
```

Example: image processing dependencies used by common native modules:

```bash theme={null}
sudo DEBIAN_FRONTEND=noninteractive apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
  libvips-dev \
  libcairo2-dev \
  libpango1.0-dev
```

Example: command-line tools needed by tests:

```bash theme={null}
sudo DEBIAN_FRONTEND=noninteractive apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
  poppler-utils \
  graphviz
```

Keep the list focused. If Charlie already has a tool installed, you do not need to reinstall it. If a package is needed while `bun install`, `pnpm install`, `yarn install`, or `npm install` is still running, do not rely on `postinstall`; ask Charlie for a pre-dependency-install blueprint update instead.

<Tip>
  If you want one setup script to work in Charlie and on developer laptops, consider using `mise` for user-level tools and runtimes. Charlie devboxes include `mise`, so a guarded setup script can run `mise install` for repo tools while keeping apt-only work behind the `IS_CHARLIE=1` guard or a separate opt-in local path.
</Tip>

## Non-JS repos

`postinstall` is the main recipe for work that can happen after JavaScript dependency installation. Charlie runs package-manager installs first, so dependency install scripts and native addon builds may fail before the root `postinstall` script can install missing system packages.

For non-JS repos, use the closest equivalent your team already trusts:

* `make setup-charlie`
* `just setup-charlie`
* `scripts/setup-charlie-env.sh`
* `mise install` plus a documented setup task

Then document the command in `AGENTS.md` so Charlie knows to run it when preparing the repo or debugging environment failures.

## Tell Charlie how to use the environment

Use `AGENTS.md` for durable instructions about setup, verification, and known caveats.

```md theme={null}
## Charlie environment

- Repo setup that runs after dependency installation is handled by `postinstall`, which calls `scripts/setup-charlie-env.sh`.
- The setup script installs Charlie-only system packages when `IS_CHARLIE=1`.
- If tests fail because a system package is missing after dependencies are installed, update the setup script instead of installing packages ad hoc.
- If dependency installation itself fails because a native package is missing, ask Charlie for a pre-dependency-install blueprint update.
- Required secrets are configured as Charlie dashboard repository environment variables. Do not print them in logs.
- Validate environment changes with `bun test` and the affected package checks.
```

Keep this short and operational. `AGENTS.md` should tell Charlie what to do, not repeat every package in the setup script.

## Secrets and environment variables

Use dashboard repository environment variables for non-public keys, tokens, and runtime config needed during Charlie runs. Configure them under your repository settings in the <a href="https://dashboard.charlielabs.ai">Charlie dashboard</a>.

Good uses include:

* Package registry tokens such as `NPM_TOKEN`.
* API keys for test doubles or sandbox services.
* Runtime config used by build or verification commands.

Do not commit secrets to the repo, echo them from setup scripts, or include them in generated logs. If a setup command needs a secret, read it from the environment and fail with a generic message when it is missing.

## How blueprints work

Blueprints are repo-specific prepared devbox images. They are similar to Docker images: Charlie builds them from your repo setup so future devboxes can start faster with dependencies already present.

Charlie checks blueprints on repository pushes and rebuilds them when the existing blueprint is stale. Changes may not apply immediately, and existing devboxes may keep using the environment they already have.

If you need a setup change available right away, contact Charlie and ask for an on-demand blueprint update.

## Troubleshooting

### `apt-get` prompts or hangs

Pass `DEBIAN_FRONTEND=noninteractive` on the `sudo apt-get` command and use `-y`:

```bash theme={null}
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends <package>
```

### A native dependency fails during package install

`postinstall` cannot repair apt packages required by dependency install scripts or native addon builds, because the package-manager install may fail before `postinstall` runs. Ask Charlie for a pre-dependency-install blueprint update for those packages.

### Package install works once, then fails later

Make the script idempotent. Check for files, directories, or commands before creating or installing them, and prefer package manager commands that tolerate already-installed packages.

### A package is missing in Charlie but installed locally

If the package is needed after dependencies install, add it to the repo setup script and commit the change. If it is needed while dependencies install, ask Charlie for a pre-dependency-install blueprint update. Local machine state is not part of the blueprint unless the repo can recreate it.

### A change is not visible in a new Charlie run

Blueprint updates may lag. Ask Charlie for an on-demand blueprint update if the new package is blocking work.

### Setup needs a running service

Leave it out of this page's setup path for now. Document the need in `AGENTS.md` and ask Charlie how to handle that workflow separately.

## Complete example

`package.json`:

```json theme={null}
{
  "scripts": {
    "postinstall": "bash scripts/setup-charlie-env.sh"
  }
}
```

`scripts/setup-charlie-env.sh`:

```bash theme={null}
#!/usr/bin/env bash
set -euo pipefail

if [[ "${IS_CHARLIE:-}" != "1" ]]; then
  exit 0
fi

sudo DEBIAN_FRONTEND=noninteractive apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
  libpq-dev \
  pkg-config \
  poppler-utils

if command -v mise >/dev/null 2>&1 && [[ -f .mise.toml ]]; then
  mise trust .mise.toml -y
  mise install
fi
```

`AGENTS.md`:

```md theme={null}
## Charlie environment

- Environment setup that can run after dependency installation runs from `postinstall` via `scripts/setup-charlie-env.sh`.
- Charlie-only setup is guarded by `IS_CHARLIE=1`.
- Repository secrets come from Charlie dashboard environment variables. Never print them.
- If tests or builds fail after dependency installation because a package is missing, update `scripts/setup-charlie-env.sh` and re-run the affected verification command.
- If dependency installation itself fails because a native package is missing, ask Charlie for a pre-dependency-install blueprint update.
```
