9.6 KiB
Local Setup
This guide runs the active Zopu stack locally, including the browser chat and the AgentOS issue-to-PR path.
What runs
Browser (React Router/Vite, :5173)
-> Convex Cloud (durable product state, auth, workflows)
-> Flue agent server + in-process AgentOS registry (:3585)
-> Rivet Engine control plane (:6420)
-> AgentOS workspace actor (Git + repo clone mounted from the local checkout)
-> Gitea branch and pull request
The active stack does not use repos/; that directory is archived reference code. In particular, the old standalone server on port 3590 is not part of this setup.
Requirements
- macOS or Linux
- Bun and Node.js matching the repository toolchain (
packages/agentsrequires Node>=22.18 <23 || >=23.6) - pnpm 11
- Git with SSH access to
git.openputer.com - Tea authenticated to
https://git.openputer.com - a Convex account with access to the development deployment
- an OpenAI-completions-compatible model endpoint and API key
Install dependencies from the repository root:
bun install --frozen-lockfile
Confirm Git and Tea access before testing issue or PR tools:
git ls-remote origin HEAD
tea login list
tea issues list
The default Tea login should target https://git.openputer.com. Never put credentials in committed files.
Environment
Create the local environment file:
cp .env.example .env
At minimum, configure these groups.
Application and Convex
CONVEX_DEPLOYMENT=dev:<deployment-name>
CONVEX_URL=https://<deployment>.convex.cloud
CONVEX_SITE_URL=https://<deployment>.convex.site
SITE_URL=http://localhost:5173
VITE_AUTH_URL=http://localhost:5173
VITE_CONVEX_URL=https://<deployment>.convex.cloud
Flue and model provider
FLUE_DB_TOKEN=<shared-random-token>
FLUE_URL=http://127.0.0.1:3585
AGENT_MODEL_PROVIDER=<provider-name>
AGENT_MODEL_NAME=<model-name>
AGENT_MODEL_API=openai-completions
AGENT_MODEL_BASE_URL=https://<model-endpoint>/v1
AGENT_MODEL_API_KEY=<model-api-key>
AGENT_MODEL_CONTEXT_WINDOW=<positive-integer>
AGENT_MODEL_MAX_TOKENS=<positive-integer>
FLUE_DB_TOKEN must match the value stored in the Convex deployment.
Rivet and AgentOS
# The private Engine control plane this process connects to.
RIVET_ENDPOINT=http://127.0.0.1:6420
# The path where the Engine calls the registry co-hosted in Flue.
RIVET_SERVERLESS_ENDPOINT=http://127.0.0.1:3585/internal/rivet
RIVET_WORKSPACE_TOKEN=<shared-random-workspace-token>
AGENT_WORKSPACE_ROOT=/absolute/path/to/zopu-agent-workspaces
The registry runs in the Flue process; there is no standalone AgentOS runner. RIVET_ENDPOINT and RIVET_SERVERLESS_ENDPOINT have opposite directions and are not interchangeable. Port 6421 is an internal Engine API-peer port and must not be used as RIVET_ENDPOINT.
Gitea
GITEA_URL=https://git.openputer.com
GITEA_TOKEN=<personal-access-token>
GITEA_TOKEN is optional for read-only agent startup but required for the complete issue-to-PR flow unless Tea and Git already have sufficient local credentials.
The legacy variables VITE_FLUE_URL and VITE_ZOPU_SERVER_URL are not used by the active web chat path.
One-time Convex setup
On a new machine, authenticate and configure the Convex development deployment:
bun run dev:setup
Then configure the deployment-scoped values from packages/backend:
cd packages/backend
bunx convex env set SITE_URL 'http://localhost:5173'
bunx convex env set FLUE_DB_TOKEN '<same value as .env>'
bunx convex env set FLUE_URL 'http://<tailscale-ip>:3585'
Convex runs in the cloud, so FLUE_URL must be reachable from the deployment. 127.0.0.1 and localhost point at Convex's machine, not your laptop. For the current Mac setup, expose Flue on the Mac's Tailscale address, for example http://100.x.y.z:3585.
SITE_URL is deployment-scoped and single-valued. Set it to the exact browser origin currently being tested:
# Browser opened locally
bunx convex env set SITE_URL 'http://localhost:5173'
# Browser opened from another device over Tailscale
bunx convex env set SITE_URL 'http://<tailscale-ip>:5173'
If work execution uses a separate agent URL, set AGENT_BACKEND_URL; otherwise it falls back to FLUE_URL.
Start the stack
Run each process in its own terminal. The Engine must be healthy before Flue starts because Flue serves the in-process registry that uses it.
1. Start Convex development
# Publish once after backend changes
pnpm --filter @code/backend dev:once
# Watch and republish while developing
pnpm dev:server
Both commands run from packages/backend and explicitly load the repository-root .env with --env-file=../../.env. packages/backend/.env.local remains Convex CLI metadata for the selected deployment; keep the shared runtime settings in the root .env.
2. Start the Rivet Engine
Start exactly one Engine listening on 127.0.0.1:6420 using the local Engine deployment mechanism. Do not use port 6421 as the application endpoint.
3. Start Flue and the in-process registry
# Laptop-only access
pnpm --filter @code/agents dev -- --port 3585
# Convex callbacks or access from another device
HOST=0.0.0.0 \
RIVET_ENDPOINT=http://127.0.0.1:6420 \
RIVET_SERVERLESS_ENDPOINT=http://127.0.0.1:3585/internal/rivet \
pnpm --filter @code/agents dev -- --port 3585
The Flue development server serves both agent routes and the AgentOS registry at /internal/rivet/*; never start a separate registry runner. If shell exports override .env, set both endpoints explicitly as shown.
4. Start the web application
If you are not using the root dev script, start the web app separately.
For laptop-only access:
pnpm dev:web
For phone or other Tailscale-device access:
pnpm dev:tailscale:web
Open http://localhost:5173, or http://<tailscale-ip>:5173 when using the Tailscale command.
Verify the setup
Check the listeners:
curl -fsS http://127.0.0.1:6420/health
curl -fsS http://127.0.0.1:3585/health
curl -I http://127.0.0.1:5173
The first two commands must return a successful health response; the web root may redirect or return 404 if its functional routes live elsewhere.
Then verify behavior in order:
- Open the web app and sign in.
- Send a simple chat message and confirm the response streams back through Convex.
- Ask Zopu to list open Gitea issues.
- For the full execution path, send
Create a PR for issue #Nfor an open, unassigned test issue. - Confirm chat immediately reports that the issue was accepted.
- Follow the Flue server logs for
[create_pr_for_issue]and wait for acompletedline with the PR URL. - Confirm the branch and pull request in Gitea.
The PR pipeline is asynchronous: the initial chat turn acknowledges acceptance, while AgentOS implements, commits, pushes, and opens the pull request in the background.
Request flow
Web sends a conversation mutation to Convex
-> Convex persists the exact message
-> Convex dispatches to FLUE_URL/agents/zopu/<organizationId>
-> Flue runs the Zopu agent and its typed tools
-> responses return to Convex
-> the web observes Convex's reactive projection
For code execution:
-> Flue calls the local AgentOS harness
-> the harness creates an isolated Git worktree
-> a Rivet actor boots an AgentOS VM and mounts the worktree
-> Pi implements the issue and produces a candidate revision
-> the host pushes a unique branch
-> Tea creates a Gitea pull request
Common failures
Chat stays pending or reports that Flue is unavailable
- Confirm Flue is listening on
3585. - Confirm the Convex deployment's
FLUE_URLuses a host-reachable address, notlocalhost. - Confirm
FLUE_DB_TOKENis identical in.envand the Convex deployment.
Sign-in fails or the browser reports CORS errors
Set Convex SITE_URL to the exact browser origin. The shared development deployment trusts only the current single value.
AgentOS fails while mounting the repository
- Confirm the Engine is healthy at
http://127.0.0.1:6420/health. - Confirm Flue is running with
RIVET_ENDPOINT=http://127.0.0.1:6420. - Confirm
RIVET_SERVERLESS_ENDPOINTpoints back to the active Flue listener with/internal/rivetappended. - Confirm
AGENT_WORKSPACE_ROOTis writable. - Restart Flue after changing registry configuration; its development server owns the in-process registry.
The harness clients require CBOR encoding for actor RPC. Do not remove the encoding: "cbor" configuration in packages/agents/src/adapters/agentos.ts.
AgentOS reports an ACP completed-message resource limit
Restart Flue so the in-process registry picks up its updated actor configuration.
Flue connects to a remote Rivet deployment unexpectedly
Environment variables exported by the shell override values loaded from .env. Start Flue with explicit RIVET_ENDPOINT=http://127.0.0.1:6420 and RIVET_SERVERLESS_ENDPOINT=http://127.0.0.1:3585/internal/rivet.
Gitea issue or PR commands fail
Run:
tea login list
git ls-remote origin HEAD
tea issues list
Confirm the default Tea login, SSH key, repository remote, and token all target git.openputer.com.
Repository checks
After changing source or configuration:
bunx ultracite check <changed-files>
bun run check-types
bun run check
For agent-only changes, run bun run check-types from packages/agents before the root check.
See also:
DEPLOYMENT_PLAN.mdfor the staging topology and VDS release path- Rivet AgentOS quickstart
- Flue Node deployment