Improve parallel-workspaces developer CLI,
and add an opt-in layer that lets four AI
coding agents (Claude Code, opencode, VS Code Copilot, OpenAI Codex CLI)
drive a specific workspace through a single launcher command.
Parallel-workspace semantics
----------------------------
each run-devenv-agentic call brings up one wsN;
--ws N (integer; default 0) targets a specific workspace and auto-starts
ws0 first when N>=1 so the worker invariant holds. --sync is forbidden on
ws0 and re-seeds the workspace from the live repo for ws1+. Stop semantics
mirror the start invariant -- ws0 is the last to stop, shared infra stops
with it, --all walks every instance highest-first. The worker policy
section explains why workers run only on ws0 (Postgres FOR UPDATE
SKIP LOCKED is safe across many workers but the cron dedup primitive is
best-effort, and :telemetry / :audit-log-archive are not idempotent).
Per-instance Valkey Pub/Sub isolation, msgbus topology, and the
"async task notifications miss ws1+ tabs" caveat are stated explicitly.
The mem:prod-infra/core memory captures the same external-services and
task-queue / Pub-Sub topology in agent-readable form, and
mem:backend/core and mem:critical-info now cross-link it so backend work
surfaces the horizontal-scaling constraints from the start.
AI coding agent integration
---------------------------
New top-level .devenv/ directory holds committed templates
(templates/{claude-code,opencode,vscode}.json and templates/codex.toml,
each with \${PENPOT_MCP_PORT} and \${SERENA_MCP_PORT} placeholders) plus
committed shared entries (matching shared/* files for Playwright, the
only workspace-independent server we ship today).
./manage.sh start-coding-agent <claude|opencode|vscode|codex> [--ws N]
launches the chosen client against one workspace. It cd's into the
target's directory (the live repo for ws0; workspace-path "wsN" for ws1+)
and refuses to launch unless (a) the binary is on PATH, (b) the
workspace directory exists for ws1+, and (c) the instance is up
(devenv-main-running) -- the MCP servers only exist while the devenv is
running. The agentic-devenv guide is restructured around this Quick
start path, with a per-client table and a Manual configuration fallback
for clients we don't cover.
Co-Authored-By: Codex <codex@openai.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
14 KiB
title, desc
| title | desc |
|---|---|
| 3.11. Agentic Development Environment | Dive into agentic Penpot development. |
Agentic Development Environment
The agentic DevEnv is an extension of the standard DevEnv (the general DevEnv instructions apply), which is optimised for AI agent-based development, adding additional tools and processes that support agentic automation.
The general workflow is as follows:
- Start the agentic DevEnv.
- Start a debugging-enabled browser and open Penpot, using a Penpot user with the remote MCP integration enabled.
- Use an AI client (MCP client) which is connected to a suite of MCP servers to solve development tasks.
Capabilities
The agentic DevEnv leverages several MCP servers in order to provide AI agents with a comprehensive toolbox for Penpot development:
- Penpot MCP Server provides tools for directly interacting with a live Penpot instance,
enabling the agent to
- execute JavaScript code in the frontend (using the plugin API),
- execute ClojureScript code in the frontend (REPL),
- import .penpot files for reproducing issues,
- export design elements as images, and more.
- Serena MCP Server provides code intelligence tools with support for Clojure and TypeScript. Its memory system is used to organise project knowledge in a context-efficient manner.
- Playwright MCP Server provides tools for browser remote control.
Equipped with the tools provided by these MCP servers, the agent can fully close the development loop, i.e. it can ...
- retrieve information on an issue from GitHub,
- import relevant design files for reproduction,
- execute JavaScript and ClojureScript code directly in Penpot in order to
- simulate user interactions (e.g. to reproduce an issue),
- test hypotheses on the root cause of an issue, and
- experiment with implementations before touching the actual codebase,
- detect, analyse and recover from crashes in the frontend,
- make code changes (using IDE-like symbolic operations)
- test the changes in the live Penpot instance, and
- create commits and PRs resolving the issue.
Configuring and Starting the Agentic DevEnv
First-Time Setup: Building the Image. If you are starting the agentic DevEnv for the first time, you need to build the updated docker image, adding support for agentic tools:
./manage.sh build-devenv --local
Enable the Penpot MCP Connection in the Frontend.
The agentic DevEnv relies on a connection between the Penpot frontend and the Penpot MCP server
being established automatically.
Edit the file frontend/resources/public/js/config.js,
creating it if it does not exist, and make sure the penpotFlags variable contains the
enable-mcp flag.
var penpotFlags = "enable-mcp";
Running the DevEnv in Agentic Mode. Each invocation starts one instance.
--ws N (N≥1) auto-starts ws0 first if it's not already up — ws0 is the
worker-bearer and must be running whenever any ws1+ is:
./manage.sh run-devenv-agentic # main (ws0)
./manage.sh run-devenv-agentic --ws 1 # ws0 if needed, then ws1
Starting an instance that is already running is an error. Per-instance ports
are offset by 10000 × N (ws1's MCP at http://localhost:14401/mcp, Serena
MCP at http://localhost:24181, Serena dashboard at http://localhost:24182,
etc.). manage.sh prints the full per-instance URL set (Penpot UI, MCP
stream, Serena MCP, Serena dashboard, attach command) every time it brings an
instance up, so you don't need to compute the offsets by hand. See the
Parallel workspaces section in the Dev environment guide for
the workspace and lifecycle details (including the --sync flag and shutdown
shape).
Note: the MCP and Serena tmux windows are only added when the session is first created. If you've already run
./manage.sh run-devenv(non-agentic) in an instance,run-devenv-agenticerrors out because the instance is already running. Kill the session first to recreate with the agentic windows:docker exec penpot-devenv-ws0-main sudo -u penpot tmux kill-session -t penpot ./manage.sh stop-devenv ./manage.sh run-devenv-agentic
Opening Penpot with Remote Debugging & MCP Enabled
Enable Remote Debugging in Your Browser.
Penpot needs to be opened in a browser that has remote debugging enabled.
In Chromium-based browsers (such as Google Chrome, Opera, Vivaldi, etc.),
this can be achieved by launching the browser with the --remote-debugging-port argument.
For most newer browsers, you will also need to specify a user data directory,
as using debugging with your regular browser profile is disallowed for security reasons.
google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-debug-profile"
This enables the Playwright MCP server to connect to the browser and control it.
Verify that debugging was enabled correctly by navigating to http://127.0.0.1:9222/json/version.
If you change the port, adjust the MCP server configuration accordingly (see below).
Note: For security reasons, you should not enable remote debugging with a profile
that you use for regular browsing activities.
Open Penpot with the MCP Integration Enabled. The Penpot instance in the DevEnv can be accessed at https://localhost:3449. Once logged in, navigate to your account settings, click on "Integrations" in the sidebar, and enable the "MCP Server" toggle. Note: You do not need to use the generated key (or the provided URL), as the MCP server in the agentic DevEnv is running in single-user mode and does not require authentication.
Configuring Your AI Client
A given AI client session drives exactly one workspace. The Penpot and
Serena MCP servers it talks to live inside that workspace's main container
on workspace-specific ports — a client configured against ws0 cannot drive
ws1, and vice versa. Running N parallel workspaces therefore means
configuring (or launching) N AI clients, each pointed at a different
workspace's ports.
There are two ways to wire this up:
- For Claude Code, opencode, VS Code Copilot, and the Codex CLI, use
./manage.sh start-coding-agent, which loads a per-workspace MCP config generated by the devenv tooling. See Quick start below. - For any other client (JetBrains AI Assistant, Claude Desktop, Antigravity, …) — or if you'd rather configure the supported clients yourself — see Manual configuration.
Quick start: start-coding-agent
Every time you bring a workspace up with run-devenv-agentic, manage.sh
regenerates four MCP config files with that workspace's ports baked in:
| Client | File | Loaded how |
|---|---|---|
| Claude Code | <workspace>/.devenv/mcp/claude-code.json |
--mcp-config <file> flag |
| opencode | <workspace>/.devenv/mcp/opencode.json |
OPENCODE_CONFIG=<file> env var |
| VS Code Copilot | <workspace>/.vscode/mcp.json |
Auto-discovered when opening the workspace |
| Codex CLI | <workspace>/.codex/config.toml |
Auto-discovered from the project root (trusted projects only) |
The files are committed templates + an envsubst pass; see
.devenv/README.md for the full layout.
To launch a coding agent:
# Default target is ws0 (the live repo).
./manage.sh start-coding-agent claude [...args forwarded to claude]
./manage.sh start-coding-agent opencode [...args forwarded to opencode]
./manage.sh start-coding-agent vscode [...args forwarded to 'code']
./manage.sh start-coding-agent codex [...args forwarded to codex]
# Target a specific parallel workspace with --ws N (integer only).
./manage.sh start-coding-agent claude --ws 1 # drives ws1
./manage.sh start-coding-agent opencode --ws 2 # drives ws2
The launcher cd's into the target workspace before exec'ing the client, so
config files are resolved from the right directory regardless of where you
invoke manage.sh from. It refuses to launch if the target instance's
main container is not running — the Penpot and Serena MCP servers only
exist while the devenv is up. Bring the instance up first with
./manage.sh run-devenv-agentic --ws N, then retry.
--ws accepts a non-negative integer only (--ws 0, --ws 1, …). Spellings
like --ws main or --ws ws1 are rejected so the flag shape stays uniform
across attach-devenv, run-devenv-agentic, stop-devenv, and
start-coding-agent.
What each launcher does:
- Claude Code is started with
--mcp-config .devenv/mcp/claude-code.json, which is additive — your existing global Claude Code MCP entries stay available alongside the three entries we ship (Penpot MCP, Serena MCP, Playwright). To shadow one of our entries with a private one, install it under Claude Code's local scope (claude mcp add --scope local …); local wins over--mcp-config. - opencode is started with
OPENCODE_CONFIG=.devenv/mcp/opencode.json. opencode's precedence chain is global →OPENCODE_CONFIG→ project, so the file we generate overrides entries with the same name in your global config. To override our entries in turn, drop a personalopencode.jsonat the repo root — it's gitignored on purpose. - VS Code Copilot —
code "$PWD"opens VS Code on the current workspace. Copilot loads both your user-profile MCP config and the workspace's.vscode/mcp.json, so our entries land alongside whatever you have globally. Same-name entries can be shadowed via your user profile. - Codex CLI —
codexis exec'd from$PWD. Codex auto-discovers.codex/config.tomlat the project root, but only for "trusted" projects; the first launch in a workspace will prompt you to trust it. Entries in~/.codex/config.tomloverride the project file on name conflict.
Manual configuration
The start-coding-agent launcher covers Claude Code and opencode. For any
other client, or if you prefer to wire things up yourself, configure the
MCP servers in your client's native config format using the URLs below.
The Penpot and Serena URLs for the workspace you want to target are printed
by manage.sh every time it brings an instance up; copy them straight from
that output. The mechanical rule is port = base + 10000 × N for wsN, with
bases 4401 (Penpot MCP) and 14181 (Serena MCP). Playwright is not
workspace-scoped — it connects to your local browser, so the same entry works
for every client.
Project-level MCP config files (Claude Code, opencode — manual path)
If you'd rather not go through the launcher, both Claude Code and opencode support project-level MCP config files that merge with the developer's global config:
- Claude Code reads
.mcp.jsonat the project root. Local scope (claude mcp add --scope local …) overrides project scope. - opencode reads
opencode.jsonat the project root (or any ancestor Git directory). Configs are merged in the order global →OPENCODE_CONFIG→ project.
The schemas differ between the two, so a workspace supporting both ships both files. For multi-workspace work, edit the port numbers in each workspace's copy once to match its offset.
Example configuration
Below is a JSON-based configuration snippet in Claude Code's mcpServers
schema, targeting ws0 (main), using mcp-remote to wrap HTTP-based
servers. To target a different workspace, substitute the Penpot MCP and
Serena MCP URLs with the ones for that workspace.
For clients using a different configuration format, extract the relevant information (server URLs or launch commands) and configure the servers appropriately, referring to your client's documentation.
{
"mcpServers": {
"penpot-ws0": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:4401/mcp", "--allow-http" ]
},
"serena-ws0-devenv": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:14181/mcp", "--allow-http"]
},
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest", "--cdp-endpoint=http://127.0.0.1:9222"]
}
}
}
Penpot MCP Server
- The URL above connects directly to the server in the DevEnv, which runs in single-user mode. You do not need to use the proxied URL or the user token that is provided by the Penpot UI.
Serena MCP Server
- The matching Serena dashboard lives on the next port (
14182for ws0,24182for ws1, …) and is also printed bymanage.shon startup.
Working on Development Tasks
After having made the configuration changes, restart your AI client. The configured MCP servers should now be running and accessible to your client.
The agent's entrypoint for development is an activation of the penpot project with Serena.
Start by instructing your agent as follows,
Activate project penpot.
and it should retrieve fundamental project information, expecting further instructions on what to do.
Always start your first prompt with these activation instructions, as this bootstraps the agent's context.
Checking MCP Server Operability
To check if all integrations are working correctly, you can perform a series of tests.
-
Open Penpot in the debugging-enabled browser and open a design file.
-
Ask the agent to activate the project (Serena project activation):
Activate project penpot.
-
Penpot MCP
-
Checking the connection to the Penpot frontend:
Get an overview of the current page in Penpot by using the
execute_codetool. -
Checking the ClojureScript REPL:
Use the
cljs_repltool to check whether the Penpot frontend has crashed.
-
-
Serena MCP
-
Checking Serena's symbolic tools:
Use the
find_symboltool to find functionlocate-shape(cljs) and classPenpotMcpServer(ts)
-
- Playwright MCP
-
Checking the connection to the browser:
Use Playwright MCP server to find the Penpot browser tab.
-