Forge · Developer guide
Inside Forge: A Private Build Daemon and Five API Calls
Opening a project spawns a build daemon of its own, on its own ports, with its own data directory. What sits above it — the Studio, config-as-code, the Lab — the five API calls underneath, and what ends up inside the .centram-module zip.
Run it
Forge is a desktop app. With the Centram daemon installed, launch it and create a project — or do the whole thing headless with the centram-forge CLI:
# desktop (in forge/) flutter run -d macos # or headless centram-forge init my-medical-module centram-forge build my-medical-module --dry-run centram-forge package my-medical-module
Either way, opening a project does one important thing for you that we'll come back to: it spins up an isolated build daemon just for that project.
The Studio
The desktop UI is a four-region "Studio": a left rail of pipeline stages, a center panel for the active stage, a right rail (run history and a genome inspector), and a console that streams the build daemon's logs live. The pipeline runs five stages, left to right:
- Import — choose a local dataset. It is referenced into the project's workspace and never copied off your machine.
- Configure — base model and hyperparameters, editable as code (below).
- Train — kick off LoRA training; logs stream into the console.
- Evaluate — the same test prompts through the base model and your new genome, side by side.
- Package — write the
.centram-module.
Configure: config as code
Every setting in the Configure stage is backed by a single JSON document, so a run is reproducible and shareable. The GUI form and the JSON stay in sync:
{
"base": "TinyLlama-1.1B",
"lora": { "r": 8, "alpha": 16, "dropout": 0.05, "target": ["q","k","v","o"] },
"train": { "lr": 2e-4, "steps": 100, "batch": 16, "weight_decay": 0.01, "seed": 42 },
"system": { "precision": "bf16", "device": "mps" }
}
Forge forwards these to the daemon's training endpoint. As of the latest daemon, lr, steps, batch, weight_decay, lora.r and lora.alpha all take effect; dropout, target and seed are accepted but not yet applied — Forge reports that distinction honestly rather than pretending every knob works.
Under the hood: an isolated build daemon
This is the core mechanism. When you open a project, Forge does not drive your everyday Centram node. It spawns a dedicated centram-daemon process configured as a private build sandbox:
CENTRAM_DATA_DIR=<project>/.workspace # isolated state, datasets, genomes CENTRAM_API_PORT=<auto-picked free port> # loopback only CENTRAM_P2P_PORT=<auto-picked free port> CENTRAM_PAIRING_PORT=<auto-picked free port>
The app picks free ports, waits for the daemon's /api/health to come up, then reads the api_token the daemon wrote into the workspace and uses it to authenticate every subsequent call. Because the data directory and ports are per-project, two projects — or a build versus your real node — never collide, and your dataset stays inside that one workspace.
The pipeline is just API calls
Whether you click through the Studio or script the CLI, the same sequence runs against the build daemon:
POST /api/ai/lora/init
POST /api/ai/train { use_lora, lora_rank, learning_rate, max_steps, ... }
GET /api/ai/train/status (poll until terminal)
POST /api/ai/genome/active/extract -> genome bytes
POST /api/ai/genome/evaluate -> before / after
The desktop app and the CLI are two front-ends over the identical engine; the Dart client mirrors the Python one method for method.
The artifact: .centram-module
Package writes a single zip you own:
my-medical-module.centram-module genome.safetensors # the LoRA weights manifest.json # id, base-model requirement, domain, I/O, license forge.config.json # the exact config that produced it (reproducible) eval_card.json # base-vs-genome metrics + sample outputs
Any Centram daemon can load it. Nothing about your training data is inside — only the delta and its provenance.
The Lab: operate on genomes directly
Beyond a single run, the Lab lets you treat genomes as genetic material. Refresh to list them, select one to mutate, or select two to crossover with a chosen merge operator:
POST /api/ai/genome/crossover
{ "genome_id_a": "...", "genome_id_b": "...", "operator": "slerp" }
linear is a plain weighted average; slerp interpolates along the weight-space hypersphere to dodge the loss barrier a naive average hits; ties and dare_ties reduce interference between merged parameters. Pick an operator in the dropdown, pick two parents, and read the offspring's fitness.
Local-first, by construction
Isolation isn't a checkbox; it's the architecture. Your dataset is read only inside the per-project workspace. The single thing that can ever leave — if and when you choose to publish — is a differentially-private genome delta, never the raw data. That is the whole point of manufacturing modules on your own machine instead of renting an endpoint.