Using spens with an IDE
Connect spens to Zed, Devin Desktop, and other ACP-compatible editors via spens-acp
Warning: spens-acp is alpha software. It may experience bugs or challenges.
spens-acp is an Agent Client Protocol (ACP) shim for spens. It exposes any spens agent and environment pair over JSON-RPC 2.0 on stdio, so ACP-compatible editors can drive spens sessions while spens keeps providing the sandboxed container, network interception, and audit logs.
This page walks through installing spens-acp and wiring it to Zed as an external agent.
Prerequisites
- Python 3.12 or newer
- The
spensCLI binary on your$PATH(see Getting started) - An ACP-compatible editor (Zed, Devin Desktop, …)
Install spens-acp
With uv (recommended)
uv tool install spens-acp --index https://gitlab.com/api/v4/projects/refwd1%2Fspens-acp/packages/pypi/simpleThis installs spens-acp into its own environment and puts the spens-acp command on your PATH.
With pip
pip install spens-acp --extra-index-url https://gitlab.com/api/v4/projects/refwd1%2Fspens-acp/packages/pypi/simpleVerify
spens-acp --helpYou should see usage information and available flags.
Configure Zed
Zed supports external agents through the Agent Client Protocol. To add spens as an external agent, open Zed and go to Settings → AI → General → External Agents.
Click Add custom agent and fill in:
| Field | Value |
|---|---|
| Command | spens-acp (or python3 -m spens_acp if you installed with pip and have no wrapper script) |
| Environment variables | Any provider API keys you need (see below) |
Environment variables
Zed lets you pass environment variables to the agent process. You should include at least your LLM provider API key so the agent can call the model. For example, if you use Fireworks:
| Variable | Example |
|---|---|
FIREWORKS_API_KEY | fw-… |
Other common keys are ANTHROPIC_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY, etc. Spens intercepts these via the sandboxed proxy, so the real secret never enters the agent container directly.
You can also pass SPENS_ENV and SPENS_AGENT here, but it is usually cleaner to set them in .spens.config.json per project instead (see below).
Project-level configuration via .spens.config.json
The cleanest way to wire spens-acp to a project is to set the defaults in .spens.config.json inside the workspace. Then the Zed agent config does not need to hardcode an environment or agent — it just starts spens-acp and the project decides what to use.
Add these keys to your existing .spens.config.json:
{
"default_env": "node-22",
"default_agent": "pi"
}When a session starts, spens-acp resolves the workspace directory from the session/new request, reads .spens.config.json there, and picks up default_env / default_agent automatically. This means the same Zed agent entry works across different projects, each using its own configured pair.
The resolution order is:
session/newparams (env/agent, or inside_meta)--env/--agentflags orSPENS_ENV/SPENS_AGENTenv vars<workspace>/.spens.config.jsonkeysdefault_env/default_agent- Error if nothing is found
Alternative: If you prefer to configure everything in Zed's
settings.jsondirectly, add a custom agent there with"command": "spens-acp"and any"env"or"args"you need. The UI above writes the same values behind the scenes.
Run a session from the editor
Once configured, open any file in a spens-initialized workspace and start an agent panel in Zed. The flow is:
- Zed sends
initializeto spens-acp. The wrapper validates the spens binary and advertises its capabilities. - Zed sends
session/new. spens-acp creates an ACP session id and records the workspace directory. - You type a prompt in Zed. Zed sends
session/prompt. spens-acp launches a fresh spens session in the sandbox, streams progress back assession/updatenotifications, and returns the final assistant text in aPromptResponse. - Each prompt turn is recorded so the next turn replays earlier conversation history, making the ACP session feel like one continuous chat. See spens-acp configuration for how to control history length and budgets.
Because spens runs inside Docker, the first session in a new environment builds the images. This takes a few minutes. Later launches reuse cached images and start faster.
Smoke test without the editor
If something does not work in the editor, test the pipeline directly on the command line:
spens-acp --smoke-test "reply with hello" --env node-22 --agent piThis drives the agent through initialize, session/new, and session/prompt against your real spens binary, printing every session update to stderr. If the smoke test passes but Zed hangs, the problem is in the editor-to-wrapper connection (check Zed's log for stderr output). If the smoke test fails, the last line shows exactly where the wrapper stopped.
Troubleshooting basics
- No output at all — make sure
spens-acpis on your PATH, or use the full path /python3 -m spens_acp. - "No environment/agent configured" — set
SPENS_ENV/SPENS_AGENTin the editor's agent env, pass--env/--agentin the command arguments, or adddefault_env/default_agentto.spens.config.json. - Zed shows no response — open Zed's log (
zed: open log) and look for spens-acp stderr. Key milestones likesession '…' created,launching spens session, andspens session '…' endedare always logged there. SetSPENS_DEBUG=1in the agent environment for full argv, event, and state-transition detail. - Session directory never appears — the wrapper expects sessions under
<workspace>/.spens/sessions/(or the path set bySPENS_DIR). Make sure spens actually writes there.
For a complete configuration reference, advanced options, and detailed troubleshooting, see spens-acp configuration.
Spens