Kiln server kiln-v0.4.0 — embedded pi agent
·
1207 commits
to main
since this release
The flywheel closes by itself: kiln now spawns and drives pi as a managed
child process — submit a task over HTTP, watch the trajectory stream, and the
finished session lands in the agent-trace layer the self-improvement loop
trains on. Plus Muon becomes the default optimizer across every training mode.
- agent: embedded pi runs (
POST /v1/agent/runs) — the server spawns
pi --mode rpcagainst its own OpenAI-compatible endpoint (same
non-destructivepi-setupconfig merge as the embedded terminal, now
serialized + atomic + skip-if-unchanged), streams the full agent event
trajectory, and auto-merges the finished session JSONL into
agent_traces.jsonunder a cross-process file lock. Runs queue FIFO
([agent].max_concurrent_runs, default 2;run_timeout_secs, default 900;
32-active backstop enforced atomically), persist to
<adapter_dir>/agent_runs/runs.jsonacross restarts (in-flight runs come
backinterrupted), and write sessions to per-run directories so a run
that dies before flushing can never adopt a sibling's session. - agent: mid-run control —
POST /v1/agent/runs/{id}/steer,/follow_up,
and/abort. Messages sent while a run is still queued are buffered and
delivered the moment it starts. The live feed is
GET /v1/agent/runs/{id}/events?after=<seq>(inclusive cursor; pass the
response'snext_afterback;truncated/first_available_seqflag replay
gaps after ring-buffer prunes or restarts). - agent: honest outcomes — a run whose final assistant turn ended in an error
reportsfailedwith the error text, never a hollowcompleted; sessions
from aborted/timed-out runs still index (partial trajectories are data). - agent: security posture matches the embedded terminal — enabled on loopback
binds only,KILN_AGENT_RUNS=1opts in on network binds,=0
force-disables — and the gate covers the read endpoints too, since run
records and event feeds carry task prompts, server paths, and raw tool
output.KILN_PI_BINoverrides pi discovery for non-PATH installs. - dashboard: new Distill → Agent runs tab — launch form (task / cwd /
label), live run list, and a drill modal with a 1s-polled event feed
(assistant text, tool calls and results, errors), steer/follow-up/abort,
and#distill/runs/{id}deep links on the shared modal conventions. - traces:
POST /v1/agent/traces/discoveralso sweeps
<adapter_dir>/agent_runs/sessions/, so rebuilding the index from
~/.pinever drops the rollouts kiln generated itself. - training: learning rates now resolve per optimizer.
learning_rateis
optional in the SFT/GRPO/OPD configs; when omitted, the trainer picks the
selected optimizer's band — Muon (the default): SFT 2e-2, GRPO/OPD 2e-3;
AdamW/SGD keep the legacy defaults (SFT 1e-4, GRPO/OPD 1e-5). This fixes a
silent foot-gun from the Muon flip: the old AdamW-era defaults trained Muon
100–400x too cold. Explicit values still deserialize and are used verbatim
(full wire back-compat), train receipts record the resolved value, and an
explicit lr more than 50x outside the optimizer's band logs a warning at
run start. The dashboard's SFT/GRPO/OPD learning-rate fields now default to
blank ("auto (per optimizer)") and omit the field from the request when
blank;kiln train sft --lris likewise optional. The Muon GRPO/OPD band
scales the legacy AdamW SFT:GRPO ratio and is an initial heuristic pending
an empirical sweep. - training: Muon is now the default optimizer for every training mode
(SFT, GRPO, on-policy distillation / OPD, and the judge-LoRA flywheel that
rides the OPD path). Muon is momentum-orthogonalized SGD — it keeps one
per-parameter heavy-ball momentum buffer (vs AdamW's two moments), takes a
Nesterov look-ahead, and projects the LoRA A/B weight-matrix updates onto
the nearest semi-orthogonal matrix via a Newton-Schulz iteration before
stepping, rescaling bysqrt(max(rows, cols))so the update magnitude is
shape-independent. It converges LoRA fine-tunes in fewer steps than AdamW at
roughly half the optimizer state. - training: fused on-device Muon kernels for every backend — CUDA, ROCm,
Vulkan, and Metal — implementing the whole step (heavy-ball momentum +
Newton-Schulz orthogonalization + decoupled-weight-decay descent) in a
single fused per-matrix launch. Newton-Schulz is computed in gram space via
ak×kP-accumulator (k= LoRA rank), so the cost is dominated by two
skinny GEMMs over the large matrix dimension. The portable CPU reference in
kiln-optimis the parity oracle the GPU kernels are validated against. - API: the optimizer is still selected per training request. Omit the
optimizerfield to get Muon; opt back into the old behaviour with
{"optimizer": {"kind": "adam_w"}}or{"optimizer": {"kind": "sgd"}}.
Muon acceptsmomentum(0.95),nesterov(true),ns_iters(5), and
weight_decay(0.0). Note Muon wants a larger learning rate than AdamW
(~2e-2 vs ~1e-4 for LoRA), since its update is orthogonalized and
RMS-matched to unit scale.
Install: prebuilt binaries below (Linux CUDA 12.4 / ROCm 7.2.4 / Vulkan 1.2, macOS Apple Silicon Metal, Windows CUDA 12.4), or ghcr.io/ericflo/kiln-server:0.4.0 / latest.
supported_sm: [80, 86, 89, 90]
min_cuda: 12.4
rocm: 7.2.4
rocm_archs: [gfx90a, gfx942, gfx1100, gfx1151]
vulkan: 1.2