Skip to content

Set up a development environment

Elitea’s platform code lives in one monorepo: Go and Rust services, and TypeScript clients. This page covers what to install and how the repository is organized. See Run the standalone stack to bring the platform up locally, and elitea-web development or Backend services for the day-to-day edit loop.

  1. Containers: podman

    Install podman and its podman compose provider. Every compose command in this documentation set — and in the repository’s own scripts — assumes podman; the docker CLI is not required and is not what CI uses locally either.

  2. Go

    Install the Go toolchain the workspace pins (go.work at the repository root). services/elitea-llm-gateway pins its own, newer Go release and is deliberately outside the workspace — its Containerfile builds it with GOWORK=off, and task test/task vet/task lint never open it. Run its own test suite from inside services/elitea-llm-gateway/.

  3. Node

    Install Node 26 or newer (and npm 11 or newer) for apps/elitea-web — the versions are enforced by the engines field in its package.json, so an older toolchain fails npm install before it fails anything else.

  4. Python

    Install python3 for the stack’s helper scripts (deploy/scripts/*.py, the inline python3 -c calls in deploy/scripts/standalone-stack.sh). No service in the repository is built from Python; the agent worker is the Rust one.

  5. Rust

    Install a Rust toolchain for services/elitea-worker-rust (edition 2024). services/elitea-worker-rust/Cargo.toml pins the minimum rust-version; rustup picks it up automatically if you run rustup show inside that directory.

  6. kind, Helm, kubectl

    Install kind v0.33 or newer, kubectl, and Helm (4.3 or newer recommended; 3.8 or newer also works) if you plan to exercise the Kubernetes path locally — see Run a local Kubernetes cluster. You will also need python3 and curl on your PATH.

PathWhat’s there
services/Go services (elitea-main, elitea-scheduler, elitea-subapp-host, elitea-egress-proxy), the standalone elitea-llm-gateway, and the Rust services: the agent worker (elitea-worker-rust), the DeepWiki and Inventory engines, elitea-vector, elitea-code-runner and elitea-doc-extractor
apps/elitea-web (the frontend, a Vite/React monorepo of its own), elitea-desktop and elitea-mobile
libs/Shared code: libs/go (Go libraries consumed across services), libs/rust (Rust crates), libs/ts (client-core, shared by the three clients, with the brand tokens), libs/proto (versioned cross-language contracts), libs/jsonschema, libs/provider
gen/Generated Go bindings from libs/proto
deploy/Compose files, the standalone-stack and e2e-stack scripts, Helm charts, ArgoCD manifests, the kind stack and cert-generation scripts
brand/The brand guide’s sources (BRAND.md, the site build), published at /brand/ beside these docs
tools/Repository-local developer scripts
conformance/, testdata/Cross-language conformance fixtures and byte vectors the workers and Go services test against

Each Go service under services/ and each library under libs/go/ is its own module in the root go.work (elitea-llm-gateway excepted, as above); apps/elitea-web is an independent npm/Vite project.

The root Taskfile.yml wraps the checks CI runs:

Terminal window
task test # go test across every workspace module (scripts/go/workspace-run.sh test)
task vet # go vet, same aggregation
task lint # golangci-lint, same aggregation
task build # builds elitea-main's binaries (elitea-main, elitea-migrate, cutover-ctl, …)

task test, task vet, and task lint all run through scripts/go/workspace-run.sh, which iterates every module, prints a per-module result, and exits non-zero if any module failed — a bare shell loop over modules used to report only its last iteration’s status, so a failing module could hide behind a later pass. Read the run’s summary rather than its exit code alone: a NOT COVERED line names a module on disk the command did not open (this is how elitea-llm-gateway shows up, since it sits outside go.work), and a workspace-run skip ledger line lists every test that skipped itself and why — a suite where every test called t.Skip prints ok, identical to a suite that ran and passed.

For apps/elitea-web, run npm run typecheck, npm run lint, and npm run test:unit from inside the directory — see elitea-web development for the fuller gate list.

The repository’s AGENTS.md sets the architectural rules: explicit constructor dependencies rather than service locators; a versioned contract in libs/proto/ before any cross-language map or event name is relied on; typed API errors, with internal causes logged alongside trace and execution identifiers rather than returned across a trust boundary; authentication, project authorization and tenant context enforced before a product, admin or storage handler is mounted; gRPC over mTLS for every synchronous internal call (HTTP/JSON is for browser- and client-facing APIs only), and the NATS JetStream command bus for durable asynchronous worker commands; PostgreSQL as the source of truth for execution state, with the command bus as transport only; and no credentials, private URLs or development defaults that act as secrets. Read the full document before touching services/elitea-main or the runtime plane.

The standalone compose stack is the shape every local deployment path in this section builds on:

flowchart LR
    Browser -->|HTTP| Main[elitea-main]
    Browser -->|HTTP| OIDC[oidc-mock]
    Main -->|"/app, /docs (relayed)"| Web[elitea-web]
    Main -->|mTLS| Gateway[elitea-llm-gateway]
    Main -->|NATS JetStream| Worker[agent worker, Rust]
    Gateway --> Worker
    Gateway --> LLMMock[llm-mock / a real model]
    Main --> DB[(postgres)]
    Main -->|live updates| NATS[(nats)]
    Worker --> DB

Continue to Run the standalone stack to bring this topology up.