Spens logoSpens

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 spens CLI binary on your $PATH (see Getting started)
  • An ACP-compatible editor (Zed, Devin Desktop, …)

Install spens-acp

uv tool install spens-acp --index https://gitlab.com/api/v4/projects/refwd1%2Fspens-acp/packages/pypi/simple

This 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/simple

Verify

spens-acp --help

You 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:

FieldValue
Commandspens-acp (or python3 -m spens_acp if you installed with pip and have no wrapper script)
Environment variablesAny 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:

VariableExample
FIREWORKS_API_KEYfw-…

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:

  1. session/new params (env / agent, or inside _meta)
  2. --env / --agent flags or SPENS_ENV / SPENS_AGENT env vars
  3. <workspace>/.spens.config.json keys default_env / default_agent
  4. Error if nothing is found

Alternative: If you prefer to configure everything in Zed's settings.json directly, 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:

  1. Zed sends initialize to spens-acp. The wrapper validates the spens binary and advertises its capabilities.
  2. Zed sends session/new. spens-acp creates an ACP session id and records the workspace directory.
  3. You type a prompt in Zed. Zed sends session/prompt. spens-acp launches a fresh spens session in the sandbox, streams progress back as session/update notifications, and returns the final assistant text in a PromptResponse.
  4. 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 pi

This 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-acp is on your PATH, or use the full path / python3 -m spens_acp.
  • "No environment/agent configured" — set SPENS_ENV / SPENS_AGENT in the editor's agent env, pass --env / --agent in the command arguments, or add default_env / default_agent to .spens.config.json.
  • Zed shows no response — open Zed's log (zed: open log) and look for spens-acp stderr. Key milestones like session '…' created, launching spens session, and spens session '…' ended are always logged there. Set SPENS_DEBUG=1 in 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 by SPENS_DIR). Make sure spens actually writes there.

For a complete configuration reference, advanced options, and detailed troubleshooting, see spens-acp configuration.

On this page