10 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 (:3585)
-> Rivet Engine guard endpoint (:6420)
-> AgentOS registry runner
-> isolated Pi workspace mounted from the local repository
-> 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
RIVET_ENDPOINT=http://127.0.0.1:6420
RIVET_PUBLIC_ENDPOINT=http://127.0.0.1:6420
RIVET_WORKSPACE_TOKEN=<random-string-at-least-32-characters>
ZOPU_SOURCE_REPOSITORY=/absolute/path/to/zopu-code
AGENT_WORKSPACE_ROOT=/absolute/path/to/zopu-agent-workspaces
Use the same repository checkout for ZOPU_SOURCE_REPOSITORY. The harness creates Git worktrees beneath AGENT_WORKSPACE_ROOT, copies the source checkout's .env, installs dependencies, and mounts the isolated checkout into AgentOS.
Port 6420 is the Rivet Engine guard endpoint used by the application. 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 order matters for the AgentOS path.
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 whole stack
The root dev script starts Rivet Engine, the AgentOS registry runner, Convex, Flue agents, and the web app in one terminal:
pnpm dev
For phone or Tailscale-device access, start the stack with the web server bound to all interfaces:
pnpm dev:tailscale
3. Start Rivet Engine
If you prefer separate terminals, start the engine from the agents package:
cd packages/agents
bun run dev:engine
There must be exactly one local engine listening on 127.0.0.1:6420. Do not start a second engine, and do not use npx rivetkit dev; that command is unavailable in the installed version.
4. Start the AgentOS registry runner
cd packages/agents
bun run runner
The runner registers the AgentOS workspace actor with Rivet Engine. Keep it running whenever a coding attempt or issue-to-PR request may execute.
5. Start Flue agents
For laptop-only access:
pnpm dev:agents
For Convex callbacks or access from another device, bind Flue to all interfaces:
pnpm dev:tailscale:agents
The dev scripts already use port 3585; the Flue CLI defaults to 3583, but the current Zopu configuration and Convex environment use 3585.
If the shell already exports remote Rivet values, shell values override .env. Start Flue with explicit local values:
RIVET_ENDPOINT=http://127.0.0.1:6420 \
RIVET_PUBLIC_ENDPOINT=http://127.0.0.1:6420 \
bun run dev:tailscale:agents -- --port 3585
6. 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 -I http://127.0.0.1:6420
curl -I http://127.0.0.1:3585
curl -I http://127.0.0.1:5173
Any HTTP response confirms the process is reachable; these roots may redirect or return 404 because their 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 both Rivet endpoints use port
6420. - Confirm the engine and
bun run runnerare both running. - Confirm
ZOPU_SOURCE_REPOSITORYcontains.git. - Confirm
AGENT_WORKSPACE_ROOTis writable. - Restart the runner after changing AgentOS registry configuration; Flue hot reload is not enough.
The harness clients require CBOR encoding for host-directory mount descriptors. Do not remove the encoding: "cbor" configuration in packages/agents/src/runtime/agent-os.ts.
AgentOS reports an ACP completed-message resource limit
The workspace registry raises limits.acp.maxCompletedMessageBytes for long Pi coding runs. Restart the runner so the updated registry configuration is registered with Rivet Engine.
Flue connects to a remote Rivet deployment unexpectedly
Environment variables exported by the shell override values loaded from .env. Start Flue and the runner with explicit RIVET_ENDPOINT and RIVET_PUBLIC_ENDPOINT values pointing to 127.0.0.1:6420.
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:
TECH.mdfor architecture and ownership boundariesdeployment.mdfor the shared staging deployment- Rivet AgentOS quickstart
- Flue local development