Workspace
The top-level container — a single repo, its configuration, provider keys, budgets, and the memory graph. Everything lives under .frontal/.
Everything you need to ship with Frontal.
From clean clone to a live workspace in minutes. Run each command in order — copy with one click.
| 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.
Every Frontal run is composed from the same primitives. Understand these and the rest of the system follows.
The top-level container — a single repo, its configuration, provider keys, budgets, and the memory graph. Everything lives under .frontal/.
A goal-oriented unit inside a workspace. Has its own trunk branch, intake dialogue, plan history, and budget allocation. One workspace holds many projects.
An atomic, Bernstein-scoped unit of work: a description, file scope, acceptance criteria, model tier, and tool allowlist. The smallest thing an agent executes.
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.
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.
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.
From a natural-language goal to a deterministic merge — observable and reversible at every step.
A goal in any language. A short clarification dialogue (or voice) refines ambiguous intent into a canonical English description.
The canonical English Product Requirements Document — the source of truth. Translation happens only at the locale boundary, never in core logic.
The PRD is split into Bernstein-scoped task cards with file scopes, acceptance criteria, and a serialized dependency DAG for parallel-safe execution.
See every task, its cost, and dependencies. Approve once — the single human gate. Everything after this is autonomous, observable, and reversible.
Each task spawns in its own git worktree + Docker sandbox. The Pi engine reaches models only through the gateway. The watchdog keeps agents alive.
Acceptance criteria are checked beyond green tests — in a default-deny sandbox. Live preview the running app before anything merges.
Trunk-locked, serialized merge with one rebase-repair attempt. One click rolls back any merge with a new commit — history is never rewritten.
The core runs entirely locally. Provider keys never leave your machine — the engine only sees the local gateway.
With uv as the package manager.
For the frontend and the Pi engine runtime.
For default-deny test sandboxes and ArangoDB.
Worktree-per-task isolation and trunk-locked merges.
.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.
Confirm the stack is healthy:
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.
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.
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.
When spend reaches 80% of the budget, the governance layer emits a warning event visible in the UI and the event log. Execution continues.
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.
If something is broken, start here. Every fix maps to a real subsystem.
.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.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..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 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.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.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.No GPL or paid-license dependencies. Built for commercialization.
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.
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.
Every subsystem is documented in the repo's README.md, DECISIONS.md, and PROGRESS.md.