Skip to content

EN Team Try Locally

wanoo edited this page Oct 23, 2026 · 1 revision

Trying it locally with compose.yml

Français · Type: tutorial · Audience: admin · Context: hosted Studio · Status: ready · Applies from: 4.2.3

The Studio Server (hosted team Studio) · contract: experimental · verified by CI (support matrix of 4.4.0, 2026-10-23): Postgres, S3 and Keycloak in CI; Chromium and Firefox (job studio-hosted); WebKit on macOS, by hand only · automated checks: jobs studio-hosted, studio-install-smoke; CI plan studioHosted; 3 test files · people's passes: studio-hosted not run (#149), studio-collab not run (#150), studio-preview not run (#166), studio-assets-hosted not run (#167), studio-mcp-remote not run (#196), studio-oidc-generic not run (#197) · known limits: no-oidc-mode, compose-not-verified

You want to see the Studio Server work before hosting it. In ten minutes, on your machine, you will run it in its simplest mode (no login, SQLite and a folder), import a game, write through its API, watch the journal, and export the game back. Then you will see what ops/studio/compose.yml adds to try the full team mode.

What you will build

A Studio Server on 127.0.0.1:8787 holding one game at revision 1, then 2 after your first write, and a folder with that game exported at its head. Every step prints something you can check.

What you need

  • The engine repository with its dependencies installed (npm ci), and Node 22.12 or newer (see Requirements).
  • curl. Docker is never required; it only serves the optional part at the end.

Steps

  1. Write a configuration without oidc: the server is then the local one, on the loopback only, with SQLite and a folder for the contents. Save it as /tmp/studio-try/studio.config.json:

    {
      "publicUrl": "http://127.0.0.1:8787",
      "playUrl": "http://127.0.0.1:8788",
      "game": "template",
      "workDir": "/tmp/studio-try/work",
      "host": "127.0.0.1",
      "port": 8787,
      "store": { "kind": "sqlite", "file": "/tmp/studio-try/work/journal.sqlite" },
      "blobs": { "kind": "fs", "dir": "/tmp/studio-try/work/blobs" }
    }
    

    playUrl must be another origin than publicUrl, even here. Then create the folder:

    # anywhere
    mkdir -p /tmp/studio-try/work
  1. Import a game.

    # in the engine repository
    npm run studio-server -- import games/_template --config /tmp/studio-try/studio.config.json

    You see {"event":"imported","game":"template","revision":1}.

  1. Start the server (it stays in the foreground; use a second terminal for the next steps):

    # in the engine repository
    npm run studio-server -- serve --config /tmp/studio-try/studio.config.json

    You see {"event":"lease-taken",…} then {"event":"listening","host":"127.0.0.1","port":8787,…}.

  1. Ask it how it is.

    # anywhere on the machine
    curl http://127.0.0.1:8787/readyz
    curl http://127.0.0.1:8787/api/revision

    You see {"ok":true,"writes":"served"} (this instance serves writes) and {"epoch":"…","revision":1}.

  1. Write through the API, with an operation id, twice:

    # anywhere on the machine
    curl -i -X POST -H 'content-type: application/json' -H 'x-studio-op: try-local-0001' \
      -d '{"text":"hello from curl"}' http://127.0.0.1:8787/api/notes
    curl -i -X POST -H 'content-type: application/json' -H 'x-studio-op: try-local-0001' \
      -d '{"text":"hello from curl"}' http://127.0.0.1:8787/api/notes

    You see the first answer with x-studio-revision: 2; the second, the same answer with x-studio-replayed: 1: the write was applied once.

  1. Read the journal and the diff.

    # anywhere on the machine
    curl "http://127.0.0.1:8787/api/ops?after=1"
    curl http://127.0.0.1:8787/api/diff/1..2

    You see operation 2 writing notes.json, and the diff naming the note's fields added.

  1. Stop the server with Ctrl+C in its terminal. You see {"event":"stopping","signal":"SIGINT"}.
  1. Export the game at its head:

    # in the engine repository
    npm run studio-server -- export /tmp/studio-try/exported --config /tmp/studio-try/studio.config.json

    You see {"event":"exported","revision":2,"files":…}, and /tmp/studio-try/exported/export-manifest.json with each file's hash. Delete /tmp/studio-try when you are done.

Limit · no-oidc-mode Without OIDC there is no login, no member and no role: anything that can reach the loopback writes. So the server refuses any address but the loopback. There are no spans, leases, comments, previews nor published builds (they need a team Studio), and the Studio's browser page needs a login this mode does not have: use the API here, and npm run studio for a local Studio in the browser.

The full team mode with compose.yml

ops/studio/compose.yml starts, on the loopback only, Postgres (127.0.0.1:55432, user studio), MinIO, an S3 store (127.0.0.1:59000), and Keycloak (127.0.0.1:58080) with the test realm web-scumm and one test user, lea@example.org, password lea-local-only, email verified:

# in the engine repository
docker compose -f ops/studio/compose.yml up -d

It is a starting point, not a turnkey setup. On top of it you still need:

  • a configuration with oidc (issuer http://127.0.0.1:58080/realms/web-scumm, clients studio and web-scumm-cli) and oidc.allowInsecure: true, since the provider answers over http; the realm's studio client expects its callback at http://localhost:8080/auth/callback, so publicUrl is http://localhost:8080 unless you edit the realm;
  • store.kind postgres with STUDIO_DATABASE_URL, and blobs.kind s3 on MinIO with a bucket you create and STUDIO_S3_KEY_ID / STUDIO_S3_KEY_SECRET;
  • the secrets STUDIO_OIDC_CLIENT_SECRET (the realm's) and STUDIO_SESSION_KEY;
  • a worker (npm run studio-worker, with WORKER_PUBLIC_KEY and WORKER_INSTANCE), its keys made by worker-keys, and worker in the configuration with STUDIO_WORKER_KEY;
  • the Studio's page built: npm run studio-client;
  • trustProxy if the server listens beyond the loopback.

Limit · compose-not-verified This full local mode is not exercised end to end by the project's tests: CI's hosted e2e runs the server with a test provider in its own process. Browsers keep Secure cookies over http on the loopback unevenly (WebKit keeps none); the e2e serves Firefox and WebKit over https with a certificate made for the run. The reference deployment is Clever Cloud: see First deployment.

What you learned

Where to go next


Edit the source of this page · Report an error

Home

Index (6)
Start (6)
Play (9)
Install (17)
Create a game (55)
Engine (4)
Local Studio (24)
Team Studio (21)
Clever Cloud (23)
Reality Bridge and connectors (16)
Contribute (25)
Reference (7)

Clone this wiki locally