Skip to content

Add components to a workbench

You don’t design the whole workbench up front. You start with what you need today and add the rest when you actually need it. This guide follows one workbench, called acme, as it grows from a plain Node project into one with a database and GitHub access. Every step is the same loop: change the config, then apply.

On day one you know two things: it’s a Node app, and you want Claude Code in the workbench to help you build it. So that’s what you start with.

Terminal window
monoceros init acme --with-languages=node --with-features=claude

init doesn’t build anything yet. It writes two files and stops, both under ~/.monoceros/container-configs/: acme.yml describes the workbench, and acme.env holds the secrets the yml points at. You can open and edit them by hand any time, though most of the time you let the add- commands do it. Here is what you get (the real files also carry comments that explain each field, dropped here for brevity):

schemaVersion: 1
name: acme
runtimeVersion: 1.8.0
languages:
- node:22
features:
- ref: ghcr.io/getmonoceros/monoceros-features/claude-code:1
options:
permissionMode: auto
apiKey: ${CLAUDE_CODE_API_KEY}

The yml is the source of truth. Node is pinned to a major version, and Claude Code comes in as a feature. Notice its apiKey: it points at ${CLAUDE_CODE_API_KEY} in the env file, and that key is empty. That is fine. Leave it blank and Claude Code asks you to log in through your browser on first run. If you would rather use an API key, paste it there.

When the config looks right, build it:

Terminal window
monoceros apply acme

apply reads the yml, builds the workbench, and prints the command to get inside.

The workbench is up. There are a few ways to get to work, and you will mix them.

Open a shell and do whatever you would do on your own machine:

Terminal window
monoceros shell acme

You land in a bash session inside the workbench. Your tools are all there, Claude Code included: type claude and it starts right in the workspace.

Run a single command without leaving a session behind. This is how you hand the agent a task, run a build, or start a dev server:

Terminal window
monoceros run acme --in projects/web -- claude "Add a health-check endpoint at /healthz"

Everything after -- runs inside the workbench, and run exits when it does. --in sets the working directory, so point it at your project under projects/.

Or connect your editor. open attaches VS Code (or VS Codium) to the workbench over SSH, so you edit the code inside it with your normal IDE while your host stays clean:

Terminal window
monoceros open acme code

Prefer Claude Code as a desktop app? It attaches the same way. Point its Connect to SSH host feature at the host monoceros apply set up, and Claude Code runs inside the workbench while the app stays on your host. See Claude Code for the walkthrough.

Pick whichever fits the moment. However you work, it all runs inside the workbench, against its tools and services, never on your host. For editor setup and other tools, see Use an IDE.

Here it is on screen: apply builds the workbench, then open attaches the editor straight to it.

Apply, then open the editor on the workbench

The app needs to store things, so you add Postgres. You don’t edit the yml by hand. You let Monoceros do it:

Terminal window
monoceros add-service acme postgres

Two things change. The yml gets a services section, and acme.env gets three new values with working defaults:

services:
- name: postgres
image: postgres:18
port: 5432
env:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- data:/var/lib/postgresql
healthcheck:
test:
['CMD', 'pg_isready', '-U', '${POSTGRES_USER}', '-d', '${POSTGRES_DB}']
interval: 10s
timeout: 5s
retries: 5
connectionEnv:
URL: 'postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${host}:${port}/${POSTGRES_DB}'
HOST: '${host}'
PORT: '${port}'
USER: '${POSTGRES_USER}'
PASSWORD: '${POSTGRES_PASSWORD}'
DB: '${POSTGRES_DB}'

The useful part is connectionEnv. Monoceros writes ready-made connection values for the service, including a full URL, so you never build a connection string by hand or guess the hostname. Inside the workbench Postgres answers at postgres:5432, and your app reads these values from the environment. The credentials sit in acme.env if you want to change them.

Nothing is running yet. add-service only changed the files. Bring Postgres up with another apply:

Terminal window
monoceros apply acme

Here is the whole loop start to finish, the edit and then the build:

Adding Postgres, then applying (not a video, so you can select and copy any line)

Time to get the code off your machine. You want the gh CLI in the workbench so you can push and open pull requests from the shell. Same move:

Terminal window
monoceros add-feature acme github

The yml gets a second feature, and acme.env gets an empty token to fill in:

features:
# ... the claude-code feature from before, still here ...
- ref: ghcr.io/getmonoceros/monoceros-features/github-cli:1
options:
apiToken: ${GITHUB_API_TOKEN}

The github feature reads GITHUB_API_TOKEN. Paste a personal access token there and gh is signed in as soon as the workbench starts. Leave it empty and run gh auth login yourself on first run. Either way the login survives rebuilds, so you do it once.

Need to create the token first? Git and repositories walks through it and lists the scopes gh needs: repo, read:org, gist, and read:user.

And again, it takes effect on the next apply:

Terminal window
monoceros apply acme

On GitLab it is the same move: monoceros add-feature acme gitlab brings in the glab CLI, with its token set in acme.env just like the GitHub one. See GitLab CLI for its token and scopes.

Every step was the same two commands: an add- command to change the config, then apply to make it real. There is one for each kind of component: add-language, add-service, add-feature, add-repo, add-port, and a few more, each with a remove- counterpart. The yml holds all of it, so anyone who checks it out and runs apply gets the same workbench you have.

  • Lifecycle commands - init, apply, run, shell, and the rest of a workbench’s life.
  • Config commands - every add- and remove- editing command, with its options.
  • Utility commands - listing the catalog, URLs, tunnels, sharing, logs, and upgrades.
  • Git and repositories - the full workflow behind add-repo: create an access token, store it, clone, and juggle multiple accounts.