Changelog

What's new.

The notable, user-visible changes to the workbench, newest first. For the full per-version technical detail, see the GitHub Releases.

SQL Server as a curated service

Add Microsoft SQL Server to your workbench with monoceros add-service acme mssql. You get the free Developer edition, and the database is already there. Your code reads the connection from MSSQL_*. You can also import a .bacpac export into it.

The image only exists for x86_64. On an Apple Silicon Mac it needs Rosetta in your Docker runtime, and it does not run under Docker VMM.

Read SQL Server.

Journeys carry a status, and the backlog follows it

Every journey page now starts with a status: Draft in blue, In review in yellow, Agreed in green. You set it on the page or tell the skill, and the backlog skill works from it. A draft gets nothing yet, a journey in review gets its epic so it already shows up on a timeline, and an agreed journey gets its stories.

When a journey goes back to Draft or disappears, the backlog skill tells you its epic is left over. It never deletes the epic itself. The brief lost the status row it had, because nobody ever changed it.

Read Personas and journeys.

Subject areas, from the domain model into the code

The domain model now groups its entities into subject areas. Each area owns its entities: only it changes them, the others just read them. You confirm every area on its own, and only journeys that are in review or agreed count. A small product often has one area, and that is fine. The states also say what follows from a transition, such as a closed round whose assessments can no longer be changed.

The other skills carry the areas forward. The technical frame decides whether an area becomes a module or a service and how the build checks that one area does not reach into another. Every story names the area it changes, and the project files tell the building agent which module owns what.

Read Domain model.

Diagrams you can read

The domain model and technical frame skills now draw their diagrams as images. The domain model shows every entity with its attributes and the cardinalities on the lines, and where two lines cross, one of them hops over the other. Confluence opens the picture full screen, and you can zoom in.

You no longer need the PlantUML app in your Confluence. A page written before keeps its old diagram until you run the skill on it again, and then the image replaces it.

Read Domain model.

One config file for your machine

monoceros-config.env is now the only machine-wide config file. The proxy port is MONOCEROS_HOST_PORT there, and the upgrade reminder is MONOCEROS_UPGRADE_STALE_DAYS. Your git identity and shared credentials go there too.

Do you still have a monoceros-config.yml? The install script moves its settings into monoceros-config.env when you update, and tells you what moved. The old file stays behind as monoceros-config.yml.migrated. You can delete it.

Read Workbench configuration.

The agent can look at the app it builds

The new browser feature puts a headless Chromium into your workbench. The agent opens your app on localhost, clicks through it, and checks the console and the network requests itself. It no longer has to ask you whether the page works.

You add it with monoceros add-feature <name> browser. apply registers the Playwright MCP server with every agent. You don’t need an extra line in the yml. The same browser also runs your project’s own Playwright tests.

Read Browser.

Your apps come back on their own

The servers you start now come back after a reboot, a Docker Desktop restart and every monoceros start. If one needs a service that is still starting, Monoceros tries again for up to two minutes. Only monoceros stop <name> <app> keeps a server down. Existing workbenches get this with monoceros upgrade.

monoceros stop <name> --down removes the containers and keeps your data.

On a Mac with bash, run the install script again for Tab completion.

Read Long-running app servers.

Start from a template, and get asked for what only you know

monoceros init acme --template=web-app gives you a workbench that is already put together: a Node front end, a Java back end, Postgres behind it and Keycloak for the logins, plus Claude Code. Any --with-* entries you pass are added on top.

Four templates ship. Two carry a way of working, two a stack you edit down. A template is an ordinary workbench yml, so your own ones go into $MONOCEROS_HOME/templates/workbenches/, and Tab completion offers them next to the shipped ones.

init, add-feature and add-mcp-server now also ask for the credentials they need, instead of leaving blank keys for you to find later.

Read monoceros init for the flags and for writing your own template.

Discovery, from an idea to a backlog your agent can build

Monoceros Discovery is a Claude plugin. It works a raw idea out with you and writes the result into Confluence and Jira: a brief, personas and journeys, a domain model, a design brief, a technical frame, and a cut backlog. It ends where the workbench starts. The technical frame hands you a ready monoceros init command, and the stories hold the context and the acceptance criteria the three build roles work from.

Read Discovery for the whole chain, or from an idea to a built feature for how it meets the roles.

Your features are current after every apply

Every monoceros apply now brings the features in your workbench up to date before you get a shell, instead of serving whatever was current when the image layer was cached. A feature you pinned in the yml is left alone, and service images move only on monoceros upgrade, because your data lives there. A workbench you already have needs one monoceros upgrade to pick this up.

Read monoceros apply for what moves when.

Your Claude plugins come with the workbench

You can now name Claude Code plugins in the claude feature’s plugins: block. A fresh workbench then comes up with them installed, and you do not retype the /plugin commands after every rebuild. Later applies fetch the marketplace again and update the plugins, so a fix someone pushes reaches you the next time you apply.

Read Claude Code for the full block, including private and local marketplaces.

Upgrade brings the services along

monoceros upgrade now moves your services forward too. A service added from the catalog kept the image tag it was created with, so a fix upstream never reached a workbench that already existed. Upgrade now writes the tag the catalog ships today into your yml and names every change in its output. It also pulls the images again, so a fix inside an unchanged tag reaches you as well. An image you chose yourself stays as it is.

Keycloak moves to 26.7 with this release, which closes a critical account-takeover flaw in the reset-credentials flow (CVE-2026-18963). The 26.6 line will not be patched, so if you run Keycloak, run monoceros upgrade.

Read monoceros upgrade for what it refreshes and what it leaves alone.

One address for your app and its services

monoceros share now takes the workbench’s HTTP services with it. A phone that opens your app also reaches the Keycloak it logs in against, the Mailpit inbox and the RustFS console. One line in the yml decides which services those are: httpPort. The catalog fills it in where it makes sense and leaves it out on every database, because sharing a Postgres over HTTP would only return nonsense. Delete the line to keep a service to yourself.

Caddy joins the curated services as a reverse proxy, for the case where you need one origin: app and login server behind a single address, so cookies stay scoped and the OIDC issuer keeps matching the page. You keep its configuration as a Caddyfile in your repo, and saving the file is enough to apply a change.

On the host that same line gives a service a permanent address, acme-keycloak.localhost and the like. The proxy routes it, and you keep nothing running for it. monoceros status prints it on the service’s row.

Read Caddy for the mount and an example Caddyfile, and monoceros share for what goes out and how to move a busy port.

One role set per workbench, and removing it clears up after itself

claude-code-roles and opencode-roles ship the same role names, and OpenCode reads Claude Code’s skills directory as well as its own. In a workbench with both, an OpenCode run picked up a skill written for Claude Code and ran it on its default agent. Neither the role nor its permission guard applied, and the run edited a file it should not have touched. monoceros apply now refuses a workbench that has both, before it builds anything, and it names the command that drops one.

Removing a role feature from your yml now also removes its files from the container. Until this release the agents, skills and commands stayed where an earlier apply had put them. The roles kept working in a workbench that no longer declared them, and you had to delete them by hand. Skills and agents from other features stay as they are, and nothing touches your plans.

Give the agent a map of your code, not a grep

The new graphify feature parses your workspace into a knowledge graph that the agent can query. Instead of opening five files to work out what calls what, it asks one question and gets back the part of the graph that answers it. Add it with monoceros add-feature acme graphify.

The parsing runs in the container with tree-sitter. So you need no API key and no account, and your code stays where it is. If Claude Code or OpenCode is in the same workbench, graphify finds it and registers itself there as a skill on every start. Then /graphify . in the agent is the whole setup. On the shell, graphify . --code-only builds the same graph without a model.

The results land in graphify-out/, which is build output and belongs in your .gitignore.

Paste a screenshot into the agent in your workbench

Copy a screenshot on your desktop and paste it with Ctrl+V into Claude Code, OpenCode or anything else running in a workbench. The image arrives, so you can ask what is wrong with the layout you just captured instead of describing it.

Copying out of a workbench already reached your clipboard; now the way back carries images too, in every terminal and in an IDE attached over SSH. Run monoceros upgrade and start a fresh session to pick it up.

MCP servers for your agents, from the yml

The workbench yml has an mcpServers: block now, so the agents in a container get their MCP servers from the config instead of from you registering them inside. monoceros add-mcp-server acme rovo adds one.

Seven connectors are curated: Context7, Atlassian Rovo, Atlassian Forge, Notion, Linear, Figma and Microsoft Learn. Any other server goes in the same block with the config its provider publishes. MCP servers has the catalog, the credentials, and the ones you sign in to.

Rovo Dev needs its own Atlassian token

Rovo Dev only accepts a token scoped to its own app, not the one twg and Forge use. The atlassian feature has a rovodevToken option for it, filled from ATLASSIAN_ROVODEV_TOKEN, and a token it rejects now warns instead of leaving the container half built.

The feature page has the steps for all three Atlassian tokens.

Each role gets its own effort dial

The planner, the implementer and the reviewer could already each take their own model. Now each takes its own effort level too, with plannerEffort, implementEffort and reviewEffort.

Planning and reviewing are thinking work. The implementer works from a plan that already names the files and the command that decides pass or fail, so that is the cheapest place to turn the dial down.

What the values are and how to check yours arrived: Claude Code roles and OpenCode roles.

Claude Code gets the three roles

The plan, implement and review split existed only for OpenCode. The new claude-code-roles feature brings the same three roles to Claude Code. A planner turns your task into a plan file and writes no code. An implementer follows that plan and cannot change it. A reviewer runs the acceptance command itself and compares the result with the plan.

The questions happen in your own session, not inside the planner, because a Claude Code subagent cannot reach you. /monoceros-plan asks one thing at a time, each with the answer it will assume if you say nothing, and hands your answers to the planner. You read the plan. Then /monoceros-ship runs the implementer and the review, and it only goes on when the acceptance command comes back green.

Each role takes its own model, so plannerModel: opus and implementModel: sonnet put the reasoning and the typing in different places. The limits that keep the roles apart hold in every permission mode, including the Auto Mode a Monoceros container turns on by default. The planner cannot touch source. The implementer cannot edit the plan it is measured against. The reviewer cannot write at all.

Add it with monoceros add-feature acme claude-code-roles. Details on the Claude Code roles page.

Starting in a project that does not exist yet

monoceros run acme --in projects/shop -- opencode died on cd: projects/shop: No such file or directory when the directory was not there yet. That is exactly the first run for a new app: the agent is supposed to create the project, and you have to start it somewhere.

It now asks whether to create it, and yes is the default. Answer no and nothing runs, so a typo still does not start a command in the wrong place. In a script there is nobody to ask, so a missing directory stays an error there. Pass --yes to skip the question. Details on the run page.

Starting one level up is not the same thing, which is why this was worth fixing. A language server looks for its markers in the directory it was started in, and OpenCode sorts its session list by that directory too.

Two more things OpenCode brings along

A theme you picked with /theme lives in that one container, so every new workbench started over in the default colours. The opencode feature takes a theme option now, written into ~/.config/opencode/tui.json on apply, and each workbench comes up the way you like it. system follows your terminal’s background, which is usually what you want over SSH.

The second one is worth more than it looks. OpenCode can pass a language server’s diagnostics to the agent, so the agent sees a type error or an unresolved import the moment it writes one, and not when the tests run. It ships with servers for TypeScript, Go, Python, Java, Rust and about thirty more, and they are off by default. lsp: true switches them on. A server whose toolchain is not in the container does not start, and the ones that download themselves now survive an apply instead of coming back every time.

TypeScript needed one extra step. The container ships TypeScript 7, the native port, and OpenCode’s built-in TypeScript server cannot launch it, so the switch would have done nothing for the language most people write here. It registers TypeScript 7’s own protocol support instead. The bash server got a companion it was missing too: shellcheck is now in the image, without which that server starts and reports nothing. Details on the OpenCode page.

Every container can commit

A workbench without repositories could end up with no git identity, and nothing said so. The container started, git ran, and the first commit failed with “Please tell me who you are”, usually inside an agent that had been told to commit its work, where it reads like the agent’s fault.

Put GIT_USER_NAME and GIT_USER_EMAIL in monoceros-config.env once, and every workbench you build from then on has them, whether it clones anything or not. A single workbench that should commit under a different name gets them in its own acme.env. Neither needs an entry in the yml. A name and an address are personal data, the env files are gitignored, and the yml is the part you share.

Removing them works the same way. Take the identity out of the file you put it in and apply. The container no longer has one, and monoceros check reports that. It sounds obvious, and it did not work before: the identity was also read back from the file apply writes inside the container, so it survived the removal of everything that declared it. Details on Git and repos.

The three OpenCode roles use this. When a plan scaffolds a new project, its first step is now git init plus a .gitignore, so the implementer can commit each round and the reviewer reads a diff instead of every file in full. In a measured run that cut the review from 18 minutes to under two. A project that was already there is left alone.

Three roles instead of one agent

When a single agent plans a change, writes it and then checks it, it is checking its own work. If it misunderstood the task at the start, it will still misunderstand it at the end, because nothing in between looked at the task again.

The new opencode-roles feature splits that across three agents. A planner turns your task into a plan file and writes no code, asking you about anything the task leaves open before it starts. An implementer follows that plan and cannot change it. A reviewer runs the acceptance command itself and compares the result against the plan. Whichever of the three commands you call leads the rest, so you can start with a fresh task or with a plan from yesterday.

Each role runs on its own model, so you can put a model that reasons well where the thinking happens and a cheaper one where the code gets written. Add it with monoceros add-feature acme opencode-roles. Details on the OpenCode roles page.

Check finds a launch target that cannot start

A launch config can be wrong in a way that only shows up when you start the server. The entry runs npm run dev while your project calls that script start, and you find out as an npm error at the moment you wanted to look at the app.

monoceros check now compares the target’s command with your project. It reports a script that does not exist and lists the ones that do. It does the same for a working directory that is missing. It decides both from the files on your machine, so you can fix them before you start anything. Details on the check page.

Copying in the workbench now reaches your clipboard

Copying inside a workbench used to go nowhere, and nothing told you so. You copied an error message out of your agent, pasted it into a chat window, and got whatever you had copied a minute earlier.

Monoceros now carries the copy to your desktop clipboard. It works in monoceros shell, in monoceros run and in an IDE attached over SSH, in every terminal including Apple Terminal, with nothing to switch on. Run monoceros upgrade and start a fresh session to pick it up.

Go builds reuse their cache across rebuilds

A Go project used to pay for every monoceros apply: both caches sat outside the workspace, so a mid-sized project re-downloaded more than a gigabyte and recompiled its whole dependency tree afterwards.

The build cache and the module cache now live in a volume shared by every workbench on the machine. A dependency is downloaded and compiled once and then reused, by the next build and after the next apply. Tools you install with go install stay per workbench, so two projects can pin different versions of the same linter. Details on the Go page.

Apply a changed Keycloak realm while you work

Editing your realm.json used to have no effect until the next apply recreated the service, because Keycloak only imports a realm into an empty database. That made every change to a client or a role a rebuild.

The new .monoceros/bin/keycloak-realm applies a changed file to the running Keycloak instead. The Keycloak page explains what that replacement costs.

Ready-made compose blocks for your pipeline

Your services run one way in the dev container and another way in a pipeline, and until now an agent asked to write the pipeline had to work out the difference on its own. The results were unusable: dev credentials as fallback values, and a Keycloak that loses everything on restart.

Every curated service now hands over a finished block for the pipeline. Each apply writes .monoceros/deploy.md for the services you configured, so the agent copies a verified block instead of inventing one. Those blocks require every value and default nothing. A variable you forget then stops the pipeline and names itself, instead of quietly starting a reachable database on credentials from our catalog. Details on the agent briefing page.

Service data now lives in a Docker volume

The data of a service is no longer stored under container/<name>/data/ but in a Docker volume, which behaves the same way on macOS, Linux and Windows. Existing workbenches move their data across on the next monoceros apply, and backups still contain plain files, so monoceros restore works as before.

What changes for you is how you look at the live files. The Services overview has the one-line Docker command that opens a volume.

Share works even when your IDE forwards the same ports

monoceros share no longer trips over your editor. An attached IDE (VS Code, Codium, JetBrains over Remote-SSH) forwards the container’s ports to localhost on your machine, and you cannot switch that off reliably. Share needs the same ports on 0.0.0.0 to reach your other devices, so the two collided and share stopped.

Now it explains the collision instead of failing cryptically. When a port is taken, share names the real cause: your IDE holds it on 127.0.0.1. Then it offers two ways past it. Right-click the port in the IDE’s PORTS panel and choose “Stop Forwarding Port”, which stays gone across reconnects. Or publish the busy port on a different host port with the new --forward-ports flag, as in monoceros share acme web --forward-ports 15173:5173.

It reads in Docker -p order (host:container), takes a comma-separated list, and remaps only the busy ports. Everything else keeps its number. The bind stays on 0.0.0.0, so your phone and tablet reach the app exactly as before.

Tab completion that works on Windows PowerShell

Press Tab in PowerShell and monoceros now finishes what you are typing, instantly.

It completes the things you actually reach for. Subcommands (monoceros ap<Tab>), flags and their values (--with-features=<Tab>, --open <Tab>), and your own names, read straight from %USERPROFILE%\.monoceros: your container names, the apps inside a container (monoceros start <name> <Tab>), workspace folders for run --in, and the targets of a launch config. Nothing calls back into the Linux side on each keystroke, so the suggestions appear with no lag, even when the container is stopped.

It is set up for you. The Windows installer writes the completion into your PowerShell profile automatically. If you are already on Windows, re-run the installer and open a new terminal to pick it up - see Installation. Completion inside monoceros shell, and on macOS and Linux, keeps working as before.

Share to your phone over HTTPS - logins and installable PWAs included

monoceros share puts your app on your phone in one command, and it now does so over HTTPS. That is what a modern web app needs once it leaves your desk.

Logins and installable PWAs work on the phone now. A browser only unlocks sign-in cryptography, service workers, offline mode and “add to home screen” on pages it trusts, and a plain http:// address on your network is not one of them. Share now serves HTTPS, so a Keycloak login goes through and a PWA installs on your phone, the way it already did on your desktop.

The certificate is yours and stays local. Monoceros creates a small certificate authority on your machine; its private key never leaves the host and nothing is sent anywhere. Each device trusts it once - see Trusting the local certificate for the per-platform steps (macOS, Windows, Linux, iOS, iPadOS, Android).

Backends behind share get the scheme right. share tells your app it is being reached over HTTPS, so an OIDC issuer or any other absolute URL comes out as https://… and the login round-trip completes.

Run monoceros share <name> <app> and open the printed https:// URL on any device on your Wi-Fi.

Your repos, cloned and signed in with one token

Working with private repositories inside a workbench used to mean setting up git credentials by hand. Now you declare them, like everything else.

Point a workbench at your repos and they clone themselves. List HTTPS repos

  • GitHub, GitLab or Bitbucket - in the yml, and apply clones each one into the workspace. No git tooling on your host.

One Personal Access Token per provider does it all. The token that clones your repos also signs in the provider CLIs inside the container. So gh and glab, and the agents that use them, are authenticated the moment the workbench comes up. Add a provider CLI without a repo, and Monoceros still picks the right token.

The token never touches the yml. It lives in a private, gitignored env file next to the config, so the yml stays safe to commit and share.

See Git and repos for the token model and how to create a PAT for each provider.

A first-class Windows installer

Windows is now a one-command install, with none of the WSL setup you would otherwise do by hand.

The PowerShell installer sets up its own managed monoceros WSL distro, turns on Docker Desktop’s WSL integration for it, and adds the monoceros command to your PATH. You run monoceros straight from PowerShell, and it runs in Linux underneath. The installer links %USERPROFILE%\.monoceros into it, so your configs and containers land where you expect them.

You never run wsl --install, pick a distro, or flip an integration toggle. Re-running the installer reuses the distro and preserves your config. See Installation for the one line to paste.

One-command uninstall, everywhere

Installing Monoceros is now cleanly reversible. A matching uninstaller ships for macOS, Linux and Windows.

One command tears down every workbench, deletes the runtime images, and removes the CLI and its shell setup. On Windows it also removes the managed distro’s Docker integration, the monoceros shim and the %USERPROFILE%\.monoceros link. It asks whether to keep your configs and backups, so a later reinstall picks up where you left off, or to wipe everything.

It touches only Monoceros’ own objects. Images and volumes from other tools stay as they are, and you can run it again safely. See Uninstall.

See your apps, keep them across applies, and share them to your phone

Three changes make the apps you run inside a workbench easier to live with.

monoceros status is now a whole-stack overview. One glance shows the container, its services and its apps: which are up, which are not (✓ / ·), the URLs they answer on, and what the yml built in (languages, features, ports). Pass an app or service name to narrow it down to that one.

Your running apps come back after monoceros apply. Applying a yml change recreates the container, and that used to kill every dev server you had running. Now Monoceros restarts the ones that were up. The rest of the stack already behaved that way.

monoceros share <name> <app> puts an app on your phone. It opens the app’s ports to your local network, so any device on the same Wi-Fi can open it, with hot-reload working. It runs in the foreground. Ctrl+C stops sharing, and nothing stays exposed in the background.

The status app-state and the apply-restore need runtime 1.6.0 - upgrade an existing workbench to pick them up. See monoceros status, monoceros apply and monoceros share.

Start and stop long-running app servers by name

Long-running servers inside a workbench, a web app or an API, are now first class. Each app declares its servers once in a launch config. You can then start, stop or tail them by name from the host, and the build agent does the same from inside the container. Monoceros brings the container up if it has to, runs the server detached so it survives the session, and waits until its port really listens before it reports the server as up.

An app that needs several servers, an API and a web frontend for example, marks them all. One monoceros start brings them up together, in the order you declared, and each one is ready before the next starts.

Needs runtime 1.5.0 - upgrade an existing workbench to pick it up. See Long-running app servers for the details.

Monoceros is now Apache-2.0

Monoceros is now licensed under Apache-2.0 - fully open source, free to use privately and commercially, with an explicit patent grant. Take your setup and walk away anytime; there is nothing proprietary locking you in.

Connect the Claude Code desktop app

The Claude Code desktop app can now attach to a running workbench through its “Connect to SSH host” flow, Windows included. The host keys are stable, so it connects cleanly every time instead of tripping over a changed key. The agent runs inside the container, not on your host. See the Claude Code guide for the setup.

A Docker restart no longer leaves the workbench half-up

After a Docker Desktop restart or a reboot, a workbench used to come back half up. Services ran without their workspace, or the shared proxy and the SSH endpoint were gone, so port routing and IDE attach broke without saying so. Now the whole container group stays down together until you run monoceros start. The proxy and the SSH endpoint survive a restart, so ports and editor attach keep working.

Existing containers still carry the old restart: unless-stopped line on their services in the yml. Remove it from those services and run monoceros apply <name> again to get the new behaviour. You can still set restart per service when you want it.

Attach JetBrains IDEs

IntelliJ, WebStorm and the other JetBrains IDEs attach to a running workbench over SSH through the Toolbox App. Your IDE state - indexes, settings - persists across rebuilds via a shared backend, so you are not re-indexing the project every time you build. See the JetBrains guide for the setup.

Tab-completion for run --in

monoceros run --in <TAB> now completes the workspace directories inside the container, so you can target a subfolder of your workspace without typing the path by hand.

Keycloak as a curated service

Add a local Keycloak to your workbench like any other service. It starts once the workspace is up, and it can import a realm from a file you mount in. Your clients, users and roles are then there from the start, instead of you clicking them together in the admin console every time. See the Keycloak guide for the setup.

Attach any IDE over SSH

Open the running workbench in your editor over plain SSH. You need no proprietary container plugin. monoceros open <name> launches VS Code or VS Codium for you. JetBrains IDEs (IntelliJ, WebStorm and the rest) and a plain terminal attach to the same endpoint, and the Claude Code desktop app can connect too. Windows included. You work inside the container, and your host stays as it is.

Per-editor setup on the Use an IDE pages.

See every version's technical detail in the GitHub Releases →