Initial Release
A minimal, reproducible InterSystems IRIS for Health Community Edition sandbox built for AI coding
agents to work against. One Docker Compose service with durable storage, wired up two ways: for VS
Code, so ObjectScript editing, compiling, and debugging work out of the box; and for agents — Claude Code,
Copilot, Cursor — via the IRIS MCP server suite, which gives them
direct tooling for development, administration, interoperability, operations, and data against this
instance. A throwaway IRIS an agent can safely drive, break, and rebuild.
The HSCUSTOM namespace is the default target for everything here.
| Piece | Purpose |
|---|---|
| https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/docker-compose.yml | Runs intersystems/irishealth-community:latest-cd as iris-community-edition, publishing 1972 (SuperServer) and 52773 (Management Portal), with ISC_DATA_DIRECTORY=/durable/iris |
| https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/iris-data/ | The durable-storage bind mount (./iris-data → /durable). Tracked in git as an empty folder — see Durable storage |
| https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/iris-community-edition.code-workspace | The intersystems.servers definition for the container — the connection profile Server Manager and the ObjectScript extension resolve against |
| https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.vscode/settings.json | The objectscript.conn that references that profile, including the active toggle — see VS Code / ObjectScript setup |
| https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/LICENSE | MIT |
intersystems-community.objectscript-pack). This bundles the ObjectScript language server, the Server Manager, and the InterSystems Language Server.# from the project root
docker compose up -d
First start pulls the image and initializes the instance into ./iris-data, which takes a few minutes.
Watch it finish:
docker compose logs -f iris
The instance is ready when the log reports the IRIS startup as complete.
_SYSTEM / SYSHSCUSTOMdocker compose exec iris iris session iris -U HSCUSTOMOn a Community Edition container the default password is expired on first login. The Portal will prompt
you to change it. The password is not stored in this repo — Server Manager prompts for it on first
connect and saves it in your OS keychain. If you change it, update it there and in any MCP server
configuration below.
docker compose stop # stop, keep the data
docker compose start # start again
docker compose restart # restart
docker compose down # remove the container (data in ./iris-data survives)
docker compose ps # status
To start completely fresh, docker compose down and then delete the contents of ./iris-data (keeping
.gitkeep) before bringing it back up.
ISC_DATA_DIRECTORY=/durable/iris tells IRIS to keep its databases, journals, and configuration on the
bind-mounted ./iris-data directory instead of inside the container’s writable layer, so the instance
survives docker compose down and image upgrades.
Those files are machine-local instance state and must never be committed. https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.gitignore keeps
the folder in the repository while ignoring everything in it:
https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/iris-data/*
!https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/iris-data/.gitkeep
So a fresh clone gets an empty https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/iris-data/ ready to be populated on first docker compose up.
Open https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/iris-community-edition.code-workspace (File → Open
Workspace from File…) rather than the plain folder. This matters for more than convenience — see
Where the active toggle lives below.
The connection is expressed the way the InterSystems Settings
Reference
prescribes — a named server profile, referenced by name from the connection — split across two files:
| File | Scope | Setting | Holds |
|---|---|---|---|
| https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/iris-community-edition.code-workspace | Workspace | intersystems.servers |
The irishealth-community profile: webServer scheme/host/port, superServer port, username |
| https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.vscode/settings.json | Workspace Folder | objectscript.conn |
server (the profile name), ns, active |
// https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/iris-community-edition.code-workspace "intersystems.servers": { "irishealth-community": { "webServer": { "scheme": "http", "host": "localhost", "port": 52773 }, "superServer": { "port": 1972 }, "username": "_SYSTEM" } }
// https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.vscode/settings.json "objectscript.conn": { "server": "irishealth-community", "ns": "HSCUSTOM", "active": false // ← flip this to connect }
active ships as false on purpose, so opening the workspace never attempts a connection to a
container that may not be running. Flip it here, or use the ObjectScript status-bar item — which writes to
this same file.
No password is stored in the repo. Server Manager prompts on first connect and saves it in your OS
keychain; an inline password property is deprecated by the extension.
objectscript.conn also accepts host, port, and https, but the extension’s connection resolver
never reads them. It has exactly two branches:
let s = (conn["docker-compose"] && extensionKind !== ExtensionKind.Workspace) || !conn.server || !config("intersystems.servers", folder).has(conn.server) ? "" : conn.server;
if (s !== "") { // resolve scheme/host/port/pathPrefix/auth/superServer from intersystems.servers[s] } else if (conn["docker-compose"]) { // probe the running container for its mapped port } // ← no third branch: inline host/port is dead config
Hence the docs’ note on objectscript.conn.server: “Specify only ns and active when using this
setting.” Note the first clause too — a docker-compose block outranks server, so the two are
mutually exclusive rather than complementary. This project publishes fixed ports (1972, 52773) on
localhost, so the profile names them directly and no docker-compose block is used.
Non-obvious, and it silently breaks the active toggle. AtelierAPI.setConnection starts by testing the
workspace folder name against intersystems.servers:
let s = configName.toLowerCase(); // configName = the workspace FOLDER name if (config("intersystems.servers", configName).has(s)) { this.externalServer = true; // ← folder name matches a server name } else { s = (...) ? "" : conn.server; }
this._config = { serverName: s, active: this.externalServer ? !inactiveServerIds.has(s) // ← conn.active is IGNORED : conn.active, // ← conn.active is honored ... };
A match puts the folder in externalServer mode — intended for server-side isfs folders named after
a server — where active is read from inactiveServerIds, an in-memory set populated only at runtime by
connection failures. Your "active": false is parsed and then discarded, so the file watcher’s gate
(api.active && syncLocalChanges != "off") stays open and sync keeps running. The write path is guarded
the same way (externalServer || await Se(...), where Se persists conn.active), so the extension
never records the toggle either.
This folder is iris-community-edition, so the profile is named irishealth-community to stay clear
of it. If you rename the directory, check it still differs from the profile name.
active toggle livesThe toggle is in https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.vscode/settings.json deliberately. The extension picks its write target by inspecting
which scope already defines objectscript.conn:
const target = config.inspect("conn").workspaceFolderValue
? ConfigurationTarget.WorkspaceFolder // → https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.vscode/settings.json
: ConfigurationTarget.Workspace; // → the .code-workspace file
config.update("conn", { ...existing, active: newValue }, target);
Because https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.vscode/settings.json defines the whole objectscript.conn object, that first branch always
wins: every connect/disconnect lands there and never churns the shared workspace file. Keeping the object
complete at folder scope also means nothing depends on VS Code merging one setting across two files.
This depends on opening the workspace file. A folder opened directly makes https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.vscode/settings.json
Workspace scope, leaving workspaceFolderValue undefined and sending the toggle back to the
.code-workspace — and worse, the .code-workspace file’s own settings are not loaded at all, so the
intersystems.servers profile would go missing entirely. Opening a .code-workspace — even one with a
single folder entry, as here — is what makes https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/.vscode/settings.json Folder scope.
The iris-execute-mcp-v2 suite gives AI coding
assistants (Claude Code, Copilot, Cursor) direct tooling against this container — five MCP servers
covering dev, admin, interop, ops, and data.
It is not vendored into this repo — it gets cloned and built wherever you keep checkouts.
If you use Claude Code, you do not have to run any of the registration
commands yourself — hand it the job. Open this project in Claude Code and paste:
Set up the IRIS MCP server suite for this project.
- Clone https://github.com/jbrandtmse/iris-execute-mcp-v2 if I don't already have a checkout, then build it:
pnpm install && pnpm turbo run build(needs Node 18+ and pnpm 9+; install pnpm withnpm install -g pnpmif it's missing).- Register all five servers -- iris-dev, iris-admin, iris-interop, iris-ops, iris-data -- with
claude mcp addat user scope, so they're available in every project. Each one runsnode <checkout>/packages/iris-<name>-mcp/dist/index.js.- Point them at the container this repo's https://github.com/jbrandtmse/iris-community-edition-ai-sandbox/blob/main/docker-compose.yml starts, using these environment variables: IRIS_HOST=localhost, IRIS_PORT=52773, IRIS_USERNAME=_SYSTEM, IRIS_PASSWORD=SYS, IRIS_NAMESPACE=HSCUSTOM, IRIS_HTTPS=false If I've already changed the _SYSTEM password, ask me for the current one instead of using SYS.
- Make sure the container is up (
docker compose up -d) and confirm the result withclaude mcp list.
Tell me what you changed and what I need to restart.
Claude Code will need to be restarted afterwards for the new servers to load.
Both this section and the one above are specific to Claude Code —
claude mcp addis the Claude
Code CLI. For any other MCP client (Copilot, Cursor, Cline, Claude Desktop, …), configure the same five
commands and environment variables in that client’s own MCP config, or use the suite’s
iris-mcp-clientsCLI / the IRIS MCP Launcher extension, which wire up 13 supported clients for you.
Clone and build the suite (Node.js 18+ and pnpm 9+ required):
git clone https://github.com/jbrandtmse/iris-execute-mcp-v2.git
cd iris-execute-mcp-v2
pnpm install
pnpm turbo run build
Then register the servers with user scope so they are available in every project, pointed at this
container with HSCUSTOM as the default namespace. One per server (iris-dev, iris-admin,
iris-interop, iris-ops, iris-data):
REPO=/path/to/iris-execute-mcp-v2
for s in dev admin interop ops data; do
claude mcp add "iris-$s" -s user \
-e IRIS_HOST=localhost -e IRIS_PORT=52773 \
-e IRIS_USERNAME=_SYSTEM -e IRIS_PASSWORD=SYS \
-e IRIS_NAMESPACE=HSCUSTOM -e IRIS_HTTPS=false \
-- node "$REPO/packages/iris-$s-mcp/dist/index.js"
done
Verify with claude mcp list. The container must be up for the servers to connect.
MIT.