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.
Install the toolchain
Section titled “Install the toolchain”Containers: podman
Install podman and its
podman composeprovider. Every compose command in this documentation set — and in the repository’s own scripts — assumes podman; thedockerCLI is not required and is not what CI uses locally either.Go
Install the Go toolchain the workspace pins (
go.workat the repository root).services/elitea-llm-gatewaypins its own, newer Go release and is deliberately outside the workspace — itsContainerfilebuilds it withGOWORK=off, andtask test/task vet/task lintnever open it. Run its own test suite from insideservices/elitea-llm-gateway/.Node
Install Node 26 or newer (and npm 11 or newer) for
apps/elitea-web— the versions are enforced by theenginesfield in itspackage.json, so an older toolchain failsnpm installbefore it fails anything else.Python
Install
python3for the stack’s helper scripts (deploy/scripts/*.py, the inlinepython3 -ccalls indeploy/scripts/standalone-stack.sh). No service in the repository is built from Python; the agent worker is the Rust one.Rust
Install a Rust toolchain for
services/elitea-worker-rust(edition 2024).services/elitea-worker-rust/Cargo.tomlpins the minimumrust-version;rustuppicks it up automatically if you runrustup showinside that directory.kind, Helm, kubectl
Install
kindv0.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 needpython3andcurlon yourPATH.
Repository layout
Section titled “Repository layout”| Path | What’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.
Run the checks
Section titled “Run the checks”The root Taskfile.yml wraps the checks CI runs:
task test # go test across every workspace module (scripts/go/workspace-run.sh test)task vet # go vet, same aggregationtask lint # golangci-lint, same aggregationtask 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.
Guardrails
Section titled “Guardrails”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.
One-host stack topology
Section titled “One-host stack topology”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 --> DBContinue to Run the standalone stack to bring this topology up.