From c83bb80354c3dda2c22180c7135b38659c0220df Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Wed, 12 Aug 2026 13:25:28 -0600 Subject: [PATCH] docs: Updated docs to mention static file inclusion in sbx-mixins --- Agents.md | 13 ++++++++++++- Custom-Tools.md | 13 ++++++++++--- Sandboxes.md | 39 +++++++++++++++++++++++++++++++++++++++ Sharing-Configurations.md | 14 +++++++++++--- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/Agents.md b/Agents.md index 6023d9d..7af91d9 100644 --- a/Agents.md +++ b/Agents.md @@ -895,9 +895,20 @@ Layout: /agents// ├── config.yaml ├── tools.sh -└── sbx-mixin.yaml # ← gets auto-applied alongside the embedded base kit +├── sbx-mixin.yaml # <- gets auto-applied alongside the embedded base kit +└── files/ # <- optional sibling: dotfiles/scripts/refs auto-mounted into the sandbox + └── home/ + └── .config/my-tool/settings.json + workspace/ + └── .editorconfig ``` +The sibling `files/` directory is optional. If present, its contents are staged into the mixin's kit and injected into +the sandbox via [sbx's static-files convention](https://docs.docker.com/ai/sandboxes/customize/kits/#inject-files): +`files/home/*` lands under `/home/agent/`, `files/workspace/*` lands under the mounted workspace. See +[Sandboxes: Bundling static files alongside a mixin](Sandboxes#bundling-static-files-alongside-a-mixin) for the +caveats (symlinks rejected, tree contents hashed into the kit identity, exec bits preserved). + ## Example A custom agent that uses `httpie` to call an internal API: diff --git a/Custom-Tools.md b/Custom-Tools.md index c4e30ce..21885af 100644 --- a/Custom-Tools.md +++ b/Custom-Tools.md @@ -38,7 +38,10 @@ is meaningful as a portable unit you'd share via [Sharing Configurations](Sharin ``` /functions// ├── tools.sh -└── sbx-mixin.yaml +├── sbx-mixin.yaml +└── files/ # optional: static resources auto-mounted into the sandbox + └── home/ + └── .config/my-tool/rules.toml ``` **Global custom-tools mixin:** Covers all your custom tools at once. Use this when several tools share the same @@ -48,7 +51,11 @@ binary/domain needs and you don't want to duplicate: /functions/sbx-mixin.yaml ``` -Both are auto-discovered by Coyote on every `coyote --sandbox`. No flags or registration required. +Both are auto-discovered by Coyote on every `coyote --sandbox`. No flags or registration required. If you drop a +sibling `files/` directory next to either mixin, its contents get staged into the mixin's kit and injected into the +sandbox via sbx's [static-files convention](https://docs.docker.com/ai/sandboxes/customize/kits/#inject-files). See +[Sandboxes: Bundling static files alongside a mixin](Sandboxes#bundling-static-files-alongside-a-mixin) for the +caveats. ### Example: a custom tool that uses `httpie` @@ -396,4 +403,4 @@ export function run(name: string): string { ``` This is useful for pinning a specific Python version, using an alternative TypeScript runtime like -[Bun](https://bun.sh/) or [Deno](https://deno.com/), or working with virtual environments. \ No newline at end of file +[Bun](https://bun.sh/) or [Deno](https://deno.com/), or working with virtual environments. diff --git a/Sandboxes.md b/Sandboxes.md index 18a4f38..f3fc9c3 100644 --- a/Sandboxes.md +++ b/Sandboxes.md @@ -354,6 +354,45 @@ Inside the sandbox, `INTERNAL_API_TOKEN` holds the literal string `proxy-managed `Authorization: Bearer ` header added at the proxy. Use `header:` + `format: "%s"` instead of `scheme: bearer` for non-standard headers (exactly one `%s` required, and `format`/`scheme` are mutually exclusive). +### Bundling static files alongside a mixin + +For content that doesn't need runtime substitution (dotfiles, tool configs, helper scripts, cheatsheets, reference +material, etc.), drop it into a `files/` directory alongside the `sbx-mixin.yaml`. Coyote stages the whole tree into the +cache-backed kit it hands to `sbx`, and sbx applies its normal +[static-files convention](https://docs.docker.com/ai/sandboxes/customize/kits/#inject-files): `files/home/*` lands +under `/home/agent/`, `files/workspace/*` lands under the mounted workspace, and so on. + +```text +/agents/researcher/ +├── sbx-mixin.yaml +└── files/ + ├── home/ + │ └── .config/my-tool/settings.json # → /home/agent/.config/my-tool/settings.json + └── workspace/ + └── .editorconfig # → /.editorconfig +``` + +The convention applies to **every** discovery path in the table above: the workspace mixin, per-tool mixins, RAG +sidecars, and the top-level user mixin can each ship a sibling `files/`. There's no per-source special-casing. + +Use `files/` for static content; use the mixin's [`setup.files`](#what-a-mixin-can-declare) entries for content that +needs `${WORKDIR}` substitution or has to be generated at startup. + +**Caveats:** + +- **The `files/` directory must be a sibling of the `sbx-mixin.yaml`, not somewhere else in the config tree.** Coyote + doesn't recurse into arbitrary paths. A tree at `/files/...` with no adjacent mixin is ignored, and a + file (rather than a directory) named `files` next to the mixin is also ignored. +- **Symlinks inside the tree are rejected with an error** at sandbox-launch time. This is deliberate: a symlink + pointing at `/etc/passwd` in a shared bundle would silently exfiltrate host content into the sandbox. Copy the file + in for real, or reference it via a `setup.files` `content:` entry. +- **The tree's contents are hashed into the kit identity.** Editing any file under `files/` invalidates the cached kit + dir on the next `coyote --sandbox`, so iteration is safe. No stale content is served from cache. +- **Executable bits are preserved on Unix.** Scripts placed at e.g. `files/home/.local/bin/my-helper` land runnable + inside the sandbox. +- **UTF-8 paths only.** A file whose path Coyote can't render as UTF-8 (rare, but possible on some filesystems) is + rejected at wrap time so the kit hash stays deterministic across platforms. + ### Built-in mixins Coyote ships Coyote already ships mixins for the most common needs. They get auto-applied whenever they're relevant — you don't need to do anything to enable them: diff --git a/Sharing-Configurations.md b/Sharing-Configurations.md index b834063..b234c24 100644 --- a/Sharing-Configurations.md +++ b/Sharing-Configurations.md @@ -367,10 +367,12 @@ unknown sources. ### Before installing a bundle from a source you don't fully trust -1. **Grep the repo for `sbx-mixin.yaml` files** and read each one: +1. **Grep the repo for `sbx-mixin.yaml` files** and read each one, then list any sibling `files/` trees they'll drop + into your sandbox: ```sh git clone --depth 1 https://github.com// /tmp/audit find /tmp/audit -name 'sbx-mixin.yaml' -exec cat {} + + find /tmp/audit -type d -name files -path '*/agents/*' -o -type d -name files -path '*/functions/*' ``` 2. **Look specifically at**: - `permissions.network.allow` (v1: `network.allowedDomains`): What domains are being added to the sandbox's allowlist? @@ -378,6 +380,11 @@ unknown sources. (apt repo, official installer, signed release) or arbitrary URLs? - `environment.variables`: Do any look like credential exfiltration vectors (`*_API_URL` pointing at unknown hosts, `LD_PRELOAD`, etc.)? + - **Sibling `files/` trees next to any `sbx-mixin.yaml`**: These are auto-mounted into the sandbox via sbx's + [static-files convention](https://docs.docker.com/ai/sandboxes/customize/kits/#inject-files). Look for anything + landing at `files/home/.config/*` (agent config overrides), `files/home/.local/bin/*` (executables on `$PATH`), + or `files/workspace/*` (files dropped into your project dir). See + [Sandboxes: Bundling static files alongside a mixin](Sandboxes#bundling-static-files-alongside-a-mixin). 3. **First-run with `--no-mixins` to verify the bundle's non-sandbox features work** without granting any sandbox elevation: ```sh @@ -395,5 +402,6 @@ off, abort with Ctrl-C (only safe before `sbx create` starts running install com ### When sharing your own bundle If you publish a config repo, **document any `sbx-mixin.yaml` files in your `README.md`**. Explain what they add to -the sandbox and why. Users who land on your repo will trust you more if you make the privilege grants explicit -instead of letting them discover via grep. \ No newline at end of file +the sandbox and why, and if any of them ship a sibling `files/` tree, spell out what lands where (e.g. "installs a +`~/.gitconfig` and a helper at `~/.local/bin/foo`"). Users who land on your repo will trust you more if you make the +privilege grants explicit instead of letting them discover via grep.