A standalone Docker Sandboxes kit (kind: mixin) that adds
live web access to any sandbox agent via the Firecrawl Python SDK (firecrawl-py).
This kit gives whatever agent you run the ability to search the web, scrape a page to clean markdown, and crawl a site, instead of relying on its training-cutoff knowledge.
Four observable things, so each is independently verifiable (see §3):
- Installs
firecrawl-py==4.30.1as the agent user (1000). - Declares a
firecrawlcredential - the key is swapped into theAuthorizationheader by the sbx proxy on requests toapi.firecrawl.dev, never baked into the image or written to the sandbox. - Allows network egress to
api.firecrawl.dev(plus PyPI for install) viapermissions.network.allow. - Injects an
agentInstructionsnote so the agent knows the capability exists and how to call it.
Get a key from firecrawl.dev (it looks like fc-...). Store it once with
sbx's secret manager - the key is never baked into the kit, and the sbx proxy injects it into the sandbox at
runtime (sbx run has no -e flag):
echo "$FIRECRAWL_API_KEY" | sbx secret set -g firecrawl # -g = all sandboxesRunning sbx secret set -g firecrawl with no piped value prompts you for the key interactively instead.
Confirm it's stored:
sbx secret lsOn the first sbx run with this kit, sbx asks you to approve sending the firecrawl credential to
api.firecrawl.dev and records a binding in ~/.config/sbx/credentials.yaml. Because the value already lives
in the secret store, you can accept the defaults — no env var or file source is needed. (In v2 the kit only
declares what it needs and where to inject it; you control where the key comes from.)
Under centralized governance, one org rule is also required. The kit declares egress to
api.firecrawl.devitself, but ifsbx policy lsshowsGovernance: Managed by <org>, that managed policy is default-deny and overrides the kit's allow — scrapes fail with a proxy-side 403 (Blocked by network policy: domain api.firecrawl.dev:443 — no matching allow rule). The governance owner must add a network allow rule forapi.firecrawl.devto the org policy (mirror the shape of any existing per-service rule, e.g. a single-hostallow). PyPI is typically already allowed for installs;api.firecrawl.devis the one host to add. Localsbx policy allowrules do not work here — they're ignored for org-managed domains. On an ungoverned host using a localbalanced/openpolicy, no extra step is needed.
Layer the mixin onto an agent. From the published image:
sbx run --kit docker.io/ajeetraina777/sbx-kits-firecrawl:latest claudeOr straight from this repo over git:
sbx run --kit "git+https://github.com/ajeetraina/sbx-kits-firecrawl.git" claudeOr from a local clone (the kit lives at the repo root):
git clone https://github.com/ajeetraina/sbx-kits-firecrawl.git
sbx run --kit ./sbx-kits-firecrawl/ claudeThe trailing argument (claude above) is the coding agent that runs inside the sandbox, a separate axis
from the kit. Any supported agent works — sbx run --help lists them:
claude, claude-bedrock, codex, copilot, cursor, docker-agent, droid, gemini, kiro, opencode, shell
So you can swap claude for, say, codex:
sbx run --kit docker.io/ajeetraina777/sbx-kits-firecrawl:latest codexArguments meant for the agent itself go after a -- separator, e.g. sbx run --kit ...:latest codex -- --help.
Once you're in the sandbox session, use ! shell escapes to prove the mixin is really inside. Verify on
independent layers, from a cheap import check up to a full end-to-end scrape.
i. The package is installed (the pinned version, in the user-site path):
!python3 -c "import firecrawl, importlib.metadata as m; print('firecrawl-py', m.version('firecrawl-py'), '->', firecrawl.__file__)"Expect firecrawl-py 4.30.1 (the exact pin from this kit's spec.yaml) installed under
/home/agent/.local/lib/.../site-packages/ — the user-site location that matches the kit installing as user
1000 rather than as root.
ii. The credential is wired as a proxy-managed sentinel — the real key never enters the sandbox.
FIRECRAWL_API_KEY is set to the literal proxy-managed inside the container (the kit sets this sentinel via
environment.variables, since the firecrawl-py SDK won't send a request without it), and the proxy swaps in
the real key on outbound requests to api.firecrawl.dev. Seeing the sentinel (not a real fc-… key) is the
fingerprint that the credential is proxy-managed:
!env | grep -E 'FIRECRAWL_API_KEY'Expect FIRECRAWL_API_KEY=proxy-managed. If you instead see a real fc-… value, the credential is coming
from somewhere other than this kit's proxy injection.
iii. End-to-end functional proof — scrape a page through the cloud API. This single command transitively
exercises the package, the env var, and network egress to api.firecrawl.dev, so if you only run one check,
run this one:
!python3 - <<'PY'
from firecrawl import Firecrawl
fc = Firecrawl() # reads FIRECRAWL_API_KEY
doc = fc.scrape("https://docs.docker.com/ai/sandboxes/", formats=["markdown"])
md = getattr(doc, "markdown", None) or (doc.get("markdown") if isinstance(doc, dict) else "")
print(md[:300])
PYExpect the first few hundred characters of the page's clean markdown.
The agentInstructions note tells the agent it can do this; the one-liners:
from firecrawl import Firecrawl
fc = Firecrawl()
fc.scrape("https://example.com", formats=["markdown"]) # one page -> clean markdown
fc.search("docker sandboxes mixin kit", limit=5) # search the web, get page content
fc.crawl("https://docs.example.com", limit=20) # crawl a whole site/sectionSee the Firecrawl Python SDK docs for the full API (formats, structured JSON extraction with a schema, crawl options, etc.).
If sbx run --kit docker.io/... fails with a mount-policy error like:
ERROR: failed to create sandbox: ... mount policy denied: /Users/<you>: no applicable policies for op(...)
the sbx runtime is refusing to mount your home directory. sbx run mounts the current working directory into
the sandbox, and mounting your entire home dir is blocked for safety. Run from any directory other than your
home directory.
If a scrape fails with a network error, confirm api.firecrawl.dev is in the kit's permissions.network.allow
(it is, by default) and that your org's governance policy hasn't overridden it.
If a scrape fails with WebsiteNotSupportedError: ... Blocked by network policy: domain api.firecrawl.dev:443 — no matching allow rule — blocked by default deny policy (HTTP 403 from the sbx proxy, not from Firecrawl),
your sandbox is under centralized governance and the managed policy is default-deny without a rule for
api.firecrawl.dev. The kit's own permissions.network.allow — and any local sbx policy allow — cannot
widen egress under managed governance; only the org can. Confirm with:
sbx policy ls <sandbox-name> # look for "Managed by <org>" and whether api.firecrawl.dev is allowedIf you see network policy for "api.firecrawl.dev" is managed by your organization; local allow rules are not applied, ask whoever owns the governance profile to add an api.firecrawl.dev allow rule (alongside the
existing PyPI allow). Alternatively, run the kit on a host using a local balanced or open policy instead of
managed governance. Everything else in the kit (SDK install, proxy-injected credential) works regardless — only
the outbound scrape is gated by this rule.
If a scrape raises PaymentRequiredError: ... Insufficient credits (HTTP 402), that's the good failure:
the request authenticated successfully (a bad/missing key returns 401, not 402) — your Firecrawl account is
just out of credits. The kit is working; top up at https://firecrawl.dev/pricing or lower the request
limit.