About

A local environment

The whole platform on one machine, with data on every page of the web UI, for seeing and changing the web UI.

For: Contributors developing the web UI.

Run the local development environment to work on the web UI with populated pages. It starts a dev server with embedded Temporal, two nodes, a stand-in model API and the Vite development server, then seeds sample records. No model key or paid model call is needed.

This environment binds to loopback on one machine. Use the quickstart to try an agent first.

With Tilt

Tilt runs each part as a resource with its own log and status, rebuilds the binaries and the runtime bundle when Go or runtime files change, and restarts the server and the nodes after.

Terminal
tilt up                 # the Tilt UI: http://localhost:10350
tilt up -- --no-docs    # without the docs' dev server
tilt up -- --no-web     # without the web UI on Vite
tilt down               # stop everything; the data stays

The Tilt UI links to the web UI, the Temporal UI and the docs. Tilt's update check and usage statistics are off in the Tiltfile.

To install Tilt, run its official install script, or take a pinned release and check it against the release's checksums.txt:

Terminal
curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
Terminal
curl -fsSLO https://github.com/tilt-dev/tilt/releases/download/v0.36.0/tilt.0.36.0.linux.x86_64.tar.gz
echo "9ce610083efc76ffa518ec9b001ddb1711b652adce3333f57ffff6be50ad9719  tilt.0.36.0.linux.x86_64.tar.gz" | sha256sum -c
tar -xzf tilt.0.36.0.linux.x86_64.tar.gz tilt && install tilt ~/.local/bin/tilt

Without Tilt

make dev-ui runs the same parts in one terminal, with their logs in .oz0/dev-env/logs, and prints the addresses once the seed is done. Ctrl-C stops all of it, the nodes' runtimes and plugin servers too.

Terminal
make dev-ui

It does not rebuild on changes; stop it and run it again. Vite reloads the web UI either way. OZ0_DEV_DOCS=1 make dev-ui also starts the docs' dev server.

What a build serves, and what it leaves

Each build also rebuilds dist/ for your machine's platform, the way make dist PLATFORMS=<os>/<arch> TOOLCHAIN=0 does, whenever the node binary or the runtime changed. The dev server serves dist/ to its nodes as a cluster's edge does, so the nodes update through the same path a real install uses, and you never run make dist by hand.

A build cleans up after itself, so rebuilds do not fill the disk:

  • dist/runtime/ keeps the three newest runtimes. Older tarballs and bundle folders go before the manifest is signed, and older node binaries go when it is published.
  • The nodes' installed runtimes, in ~/.cache/orchestrator-zero/dev-env/node/runtimes, keep the one just built, any a running process still uses, and the three newest. An install in progress is never touched.
  • Go's build cache is pruned at most every six hours: entries unused for 72 hours, then the least recently used until it is under 100 GB.
  • At the same time, the nodes' uv cache is pruned once it passes 2 GB (OZ0_DEV_UV_CACHE_MB); the next runtime install then fetches its packages again.

OZ0_DEV_KEEP_RUNTIMES changes how many runtimes stay. make go-cache-prune prunes Go's cache at any time; GO_CACHE_MAX_AGE_HOURS and GO_CACHE_MAX_GB change its limits.

Two addresses, one web UI

The local environment serves the same web UI at two addresses. Both talk to the same dev server and show the same data; what differs is which build of the app you get.

AddressWhat it servesUse it to
http://127.0.0.1:15173The app from its sources in web/, on Vite's dev server, which reloads the page when you save a fileChange the web UI
https://127.0.0.1:18443The copy built into the server binary, on the management port, as every install serves itCheck the app as it ships: the production build, its Content-Security-Policy, HTTPS and the secure session cookie

15173 exists only in a checkout, for working on the web UI. An install has no Vite: its operators open the management port. Without Vite, every change to the UI would wait for a production build, a server build and a restart. If you are not changing the UI, leave Vite out with tilt up -- --no-web or OZ0_DEV_WEB=0 make dev-ui, and use 18443.

The copy on 18443 is only as new as your last make web. The server embeds whatever is in web/dist when it is built, and only make web fills web/dist; tilt up and make dev-ui build the server but not the web UI, so that a change to Go code does not also wait for a production build of the UI.

When 18443 looks older than 15173, or newer after a build on another branch, it is an earlier build of the same app, not a different one. To bring it up to date:

Terminal
make web             # build the web UI into web/dist
tilt trigger build   # under Tilt: rebuild the server with it and restart; without Tilt, run make dev-ui again

Sign in

Open the web UI on Vite at http://127.0.0.1:15173 and sign in as admin. The password is in the server's data folder, and works on 18443 too:

Terminal
cat .oz0/dev-env/server/admin-password

Vite's dev server passes the API calls, the sign-in and the session cookie on to the dev server, so the app runs from its sources while the data comes from the server.

To see the chat drawer with chats in it, sign in as one of the seed's people, alex or maya, operators who see content. Their passwords are made by the seed and kept in the data folder, like the admin's (dev only):

Terminal
cat .oz0/dev-env/seed/alex-password .oz0/dev-env/seed/maya-password

For the CLI, point it at the dev server:

Terminal
export OZ0_CONTEXT=.oz0/dev-env/server/operator/context.json
oz0 job list

What the seed makes

WhereWhat
Tenantsdefault, and acme with no node of its own
Nodesdev-a (pool=general) and dev-b (pool=batch)
Pluginssupport (support-triage, support-refunds, support-reporter) and hiring (hiring-screener); support in acme too
Jobsfinished ones, a conversation of two turns, one that failed on its step limit, an export that runs for most of a day, a refund that waits for a person's approval, and a job in acme that waits for a node
Findingsa possible loop, and a job that spent 90% of its budget
Costthe tenant's monthly budget, 85% spent: the CV parser reports what it costs
Rolloutssupport 0.2.0 on its canary, soaking for a day
Governancethe inventory, with hiring-screener as high risk; a kill switch in acme
Chatsalex's pinned chat about an order, one that waits for a person to approve a refund, and one shared with maya; maya's chat about an applicant. The seed makes them by signing in as each person, since a chat is a person's and the CLI acts as its operator
Alsoteams with a quota, a routine with a fire, a reader account riley, an API key, model aliases, and the audit entries all of it wrote

A stand-in for the model API, scripts/fakellm, answers every model call from a script, scripts/dev-env/fakellm.json, and the plugins in scripts/dev-env/plugins work on made-up orders and applicants.

The seed only adds what is missing, so it can run again on a seeded server, and does each time the environment starts. What waits and runs ends with time: the approvals are denied after 24 hours (alex's next seed then starts another refund chat), and the export, the wait in acme and the rollout's soak end within a day. The next seed starts a new one of each. To seed a running environment again by hand:

Terminal
make dev-seed

To start over, stop the environment and delete .oz0/dev-env. A rollout in progress keeps the tenant's other plugin updates waiting; oz0 rollout abort <id> ends it.

Ports

Every port and the data folder can be changed, with environment variables for both ways of running it, or Tilt's arguments, such as tilt up -- --web-port 25173. The defaults stay clear of make dev's ports and of the docs' and website's dev servers.

VariableDefaultWhat
OZ0_DEV_WEB_PORT15173The web UI on Vite, from its sources, for changing it
OZ0_DEV_MANAGEMENT_PORT18443Management: the admin API and the web UI built into the server, as of the last make web
OZ0_DEV_EDGE_API_PORT17443The edge's HTTPS API, for the nodes
OZ0_DEV_EDGE_TEMPORAL_PORT17233The edge's Temporal proxy, for the nodes
OZ0_DEV_TEMPORAL_PORT17234The embedded Temporal frontend
OZ0_DEV_TEMPORAL_UI_PORT18233The Temporal UI
OZ0_DEV_FAKELLM_PORT18090The stand-in for the model API
OZ0_DEV_DOCS_PORT13001The docs' dev server
OZ0_DEV_DIR.oz0/dev-envThe server's and the nodes' data
OZ0_DEV_NODE_CACHE~/.cache/orchestrator-zero/dev-env/nodeuv, Python and runtimes the nodes install, kept between runs

What reaches the internet

The seed and the platform call nothing outside the machine: the gateway's model calls go to the stand-in. The first start of a node downloads uv and Python, as every node does, and installs the plugins' Python packages; both are cached. The docs' dev server downloads its fonts once.

Test it

make e2e-dev-env runs make dev-ui on free ports and a fresh data folder, checks the seeded data through the API and the web UI through Vite's proxy, stops it with Ctrl-C and checks that nothing is left running. When Tilt is installed, it then runs tilt ci on the same data.

Copyright © 2026