Skip to content
Documentation

Documentation

Everything you need to ship with Frontal.

Quick start

Up and running in four commands.

From clean clone to a live workspace in minutes. Run each command in order — copy with one click.

$ docker compose --env-file .env up -d arangodb
$ python scripts/bootstrap_pi.py
$ cd backend && uv sync && uv run uvicorn app.main:create_app --factory --port 8400
$ cd frontend && npm install && npm run dev

Default ports

Port Service
8400 Backend — FastAPI orchestrator (app.main:create_app)
5173 Frontend — Vue 3 + Vite dev server (npm run dev)
8500 Voice agent — standalone STT/TTS microservice
8529 ArangoDB — memory graph (optional, degrades gracefully)

The Vite dev proxy (frontend/vite.config.ts) forwards /api and /gw to 8400, and /voice-agent to 8500. Live updates arrive over SSE — no polling.

Core concepts

The six building blocks.

Every Frontal run is composed from the same primitives. Understand these and the rest of the system follows.

Workspace

The top-level container — a single repo, its configuration, provider keys, budgets, and the memory graph. Everything lives under .frontal/.

Project

A goal-oriented unit inside a workspace. Has its own trunk branch, intake dialogue, plan history, and budget allocation. One workspace holds many projects.

Task Card

An atomic, Bernstein-scoped unit of work: a description, file scope, acceptance criteria, model tier, and tool allowlist. The smallest thing an agent executes.

Plan

The decomposed set of task cards with dependencies, a pre-flight cost estimate, and a dependency DAG. Reviewed and approved once — your single human gate.

Session

A live execution of a task card: the pinned Pi engine running in RPC mode inside an isolated git worktree + Docker sandbox, watched by the liveness watchdog.

Event Log

The append-only, HMAC-chained source of truth. Every decision, tool call, test result, and merge is an event. The ArangoDB memory graph is a rebuildable view of this.

The pipeline

Seven stages, one human gate.

From a natural-language goal to a deterministic merge — observable and reversible at every step.

01

Intake

A goal in any language. A short clarification dialogue (or voice) refines ambiguous intent into a canonical English description.

02

PRD

The canonical English Product Requirements Document — the source of truth. Translation happens only at the locale boundary, never in core logic.

03

Decomposition

The PRD is split into Bernstein-scoped task cards with file scopes, acceptance criteria, and a serialized dependency DAG for parallel-safe execution.

04

Plan Review

See every task, its cost, and dependencies. Approve once — the single human gate. Everything after this is autonomous, observable, and reversible.

05

Execution

Each task spawns in its own git worktree + Docker sandbox. The Pi engine reaches models only through the gateway. The watchdog keeps agents alive.

06

Validation

Acceptance criteria are checked beyond green tests — in a default-deny sandbox. Live preview the running app before anything merges.

07

Merge

Trunk-locked, serialized merge with one rebase-repair attempt. One click rolls back any merge with a new commit — history is never rewritten.

Self-host guide

Run the whole stack on your machine.

The core runs entirely locally. Provider keys never leave your machine — the engine only sees the local gateway.

Prerequisites

Python 3.12+

With uv as the package manager.

Node.js 20+

For the frontend and the Pi engine runtime.

Docker

For default-deny test sandboxes and ArangoDB.

Git

Worktree-per-task isolation and trunk-locked merges.

Environment variables (.env)

Copy .env.example to .env and fill in the values below. Keys are published into os.environ at startup and never sent to the engine.

Variable Purpose Required
GLM_API_KEY GLM provider key (first in the failover chain). Yes*
MINIMAX_API_KEY MiniMax provider key (failover tier). No
OPENCODE_API_KEY OpenCode provider key (failover tier). No
ARANGO_PASSWORD Password for the ArangoDB memory graph instance. No**
FRONTAL_MASTER_KEY Master key for the local vault (secrets encryption). Yes
USER_LOCALE Display locale (e.g. tr, en). Drives translation at the boundary. No

* At least one provider key is required for agent execution. ** ArangoDB is optional — the backend degrades gracefully and the graph rebuilds on the next start.

First-run validation

Confirm the stack is healthy:

$ cd backend && uv run pytest

The default suite excludes live and contract markers. To drive the real Pi binary: uv run pytest -m contract. To hit live providers: uv run pytest -m live (needs funded keys).

Note — ArangoDB is optional. If it is down or absent, the backend continues to function using the event log as the sole source of truth. On the next successful start, Reconciler.run() rebuilds the memory graph from the event log. Never treat ArangoDB as primary state.

Configuration

Model routing and budgets.

Agents reach models only through the built-in gateway. Virtual tiers resolve to an ordered provider chain with automatic failover — provider keys never reach the engine.

Model routing tiers

Configured in backend/config/model_routing.json. Each tier falls through the chain until a provider's circuit breaker is closed.

Tier Used for Failover chain
frontal/heavy PRD authoring, decomposition, complex reasoning. GLM → MiniMax → OpenCode
frontal/standard Day-to-day task execution by coding agents. GLM → MiniMax → OpenCode
frontal/utility Summaries, narration, lightweight classification. GLM → MiniMax → OpenCode
frontal/asr Speech-to-text for the voice agent microservice. GLM → MiniMax

Each provider has its own circuit breaker (breaker.py). On repeated failures the breaker opens and the gateway fails over to the next provider transparently.

80% — Warn

When spend reaches 80% of the budget, the governance layer emits a warning event visible in the UI and the event log. Execution continues.

100% — Pause

At 100% the budget pauses all new task dispatches. In-flight sessions finish safely. The meter is fed by a single metering point in the gateway.

Troubleshooting

Common issues, quick fixes.

If something is broken, start here. Every fix maps to a real subsystem.

Pi engine not found — "engine binary missing"
The pinned Pi engine lives under .frontal/engine/. Run python scripts/bootstrap_pi.py to install it (idempotent). If it still fails, confirm Node.js 20+ is on your PATH and that .frontal/engine/node_modules/@earendil-works/pi-coding-agent/ exists. The contract test test_pi_rpc_contract.py verifies the wire format against the real binary.
ArangoDB connection refused
This is non-fatal. The backend degrades gracefully and runs off the event log alone. To enable the memory graph, start it with docker compose --env-file .env up -d arangodb and confirm port 8529 is free. On the next backend start, Reconciler.run() rebuilds the graph from the event log automatically.
Provider returns 401 Unauthorized
Check the provider key in your .env (GLM_API_KEY, MINIMAX_API_KEY, OPENCODE_API_KEY). Keys are read at startup — restart the backend after editing. The gateway will fail over to the next provider in the tier chain if a key is invalid, so a 401 often surfaces only when all providers are exhausted.
Docker sandbox fails to start
Tests run in a default-deny Docker container. Confirm the Docker daemon is running (docker info). On macOS, ensure Docker Desktop has permission to mount the project directory. The sandbox image is cached under .frontal/; if a build is corrupted, remove the cache and let it rebuild on the next run.
Port conflicts (8400 / 5173 / 8500)
Find what is holding the port with lsof -i :8400 (or :5173 / :8500). The backend and voice-agent ports are set via the uvicorn --port flag. The frontend dev server port is configured in frontend/vite.config.ts — remember to update the proxy targets if you change the backend port.
Worktree left in dirty state
Each task gets its own git worktree. If a session crashes mid-execution, the worktree may retain uncommitted changes. The manager cleans up worktrees on the next run_plan; for a manual reset, remove the stale directory under .frontal/worktrees/ and run git worktree prune in the repo root. The event log retains the full session history either way.
License

Permissive and commercial-friendly.

No GPL or paid-license dependencies. Built for commercialization.

License — Apache 2.0 core (on public release)

The orchestrator backend, frontend, and voice agent will be licensed under Apache 2.0 upon public release. Commercial use, modification, and distribution permitted with attribution. See docs/LICENSING.md for full terms.

MIT — Pi Engine

The pinned Pi coding agent (@earendil-works/pi-coding-agent) is MIT-licensed. It runs in RPC mode behind PiAdapter — the only module that knows its wire format.

Adding a dependency that changes a lockfile triggers the license-check CI step. Regenerate notices with python scripts/generate-notices.py and record new license decisions in DECISIONS.md.

Still stuck?
Read the source.

Every subsystem is documented in the repo's README.md, DECISIONS.md, and PROGRESS.md.