Pi SVG walkthrough#
This walkthrough composes Harbor’s native Pi agent, the SVG task adapter and AReno’s GSPO trainer. Use it as a working example of Integrate a harness with Harbor and Adapt a task: change the loader or grading rubric for your data, or replace the harness while retaining the task adapter.
Prepare the runtime#
Start from the Python 3.12+/Harbor 0.24.0 setup in Integrate a harness with Harbor.
Pi, Node, Chromium and Python must be available inside the selected task environment.
The integration has been exercised with Node 22.19 and Pi 1.2.0. For that Pi
version, the npm package is @earendil-works/pi-coding-agent. The controller
also needs the example’s data/image dependencies: ModelScope, PyArrow and
Pillow. The example reuses preinstalled tools during rollouts.
For local execution, check the host tools and choose the provider:
node --version
pi --version
export ARENO_HARBOR_ENVIRONMENT=local
export ARENO_PI_PYTHON="$(command -v python)"
export ARENO_PI_CHROMIUM="$(command -v chromium)"
Set ARENO_PI_CHROMIUM to the actual executable if your system calls it
chromium-browser or installs it elsewhere. The local Pi wrapper gives
each sample separate home, config and temporary directories, disables GPU
visibility for its tools and keeps judge credentials out of its inherited
environment. It shares the host filesystem; it is not an OS sandbox.
For Docker execution, use an image containing those tools:
export ARENO_HARBOR_ENVIRONMENT=docker
export ARENO_HARBOR_IMAGE=my-pi-runtime:1.2.0
export ARENO_PI_PYTHON=python
export ARENO_PI_CHROMIUM=/usr/bin/chromium
The image name above is a user-built image, not a published AReno artifact.
Native Harbor Pi sources ~/.nvm/nvm.sh when launching; ensure that setup
works in the image as well as pi --version. Paths in these variables
refer to executables inside the task environment. A local run ignores a
leftover ARENO_HARBOR_IMAGE value. Pass extra native provider settings
through ARENO_HARBOR_ENVIRONMENT_OPTIONS as a JSON object; for example,
{"proxy_connect_host": "controller.example.com"} when containers reach
the controller through that hostname. See Integrate a harness with Harbor for
routing details.
Configure the controller-side judge#
Use an OpenAI-compatible VLM that accepts images and JSON-schema responses. The VLM grades task outputs; AReno’s policy model runs the agent. Configure the judge independently in the controller shell:
export ARENO_VLM_BASE_URL=https://vlm.example.com/v1
export ARENO_VLM_MODEL=your-vision-model
: "${ARENO_VLM_API_KEY:?Set the judge key in your shell or secret manager}"
export ARENO_VLM_API_KEY
export ARENO_VLM_TIMEOUT=300
export ARENO_PI_GRADING_CONCURRENCY=8
Replace the example endpoint and model with your provider. Optional
ARENO_VLM_REQUEST_OPTIONS is a JSON object of additional request fields.
The default request timeout is 60 seconds; the setting above uses 300 seconds.
Judge concurrency is shared across samples, separately from
--max-running-prompts. Keep keys out of data records, task files and agent
configuration.
Prepare ModelScope data#
From the repository root, generate 10,000 short icon tasks:
export DATASET_PATH="$PWD/data/svg.jsonl"
python examples/agentic/pi/generate_dataset.py \
--output "$DATASET_PATH" --limit 10000 --seed 0 --max-turns 8
The generator selects OmniSVG/MMSVG-Icon from ModelScope at revision
0224c19f60f16ac3f3e7828eb418060fccfd634a. It filters malformed, blank,
duplicate and overly long examples, writes the task JSONL and a provenance
report, and saves reference PNGs beside it in svg-references/. For an
offline machine, supply local shards with repeated --parquet shard.parquet
arguments. Move the reference files with the JSONL and update their absolute
paths if the destination changes.
Each task asks Pi to write icon.svg, run the provided preview helper and
refine its output. The agent sees an empty starting SVG and preview tools.
The judge receives the original source prompt, reference image, rendered
candidate and rendering evidence. Reference images stay controller-side.
Generation defaults to eight turns and 900-second execution/verification
budgets. For a large concurrent run, adjust budgets in the task records; the
eight-GPU validation used timeout=1800 and verify_timeout=3600.
Check normalized records before loading the model:
python .agents/skills/areno-run-training/scripts/inspect_dataset.py \
--dataset-path "$DATASET_PATH" \
--loader examples/agentic/pi/dataset_loader.py --algo gspo
Require ok: true and inspect the prompt, entrypoint, source metadata,
turn budget and reference paths in a record.
Customize the data and reward#
For your own CSV with a brief column and optional reference_png
column, save this as custom_pi.py. It reuses SVG rendering and scoring;
only source mapping and the rubric change:
import csv
from pathlib import Path
from areno.api import register_dataset
from examples.agentic.pi.run_agent import create_runner
from examples.agentic.pi.svg_dataset import SVGIconDataset
from examples.agentic.pi.visual_reward import RubricDimension
def read_icons(dataset_path):
path = Path(dataset_path).resolve()
with path.open(newline="") as source:
for row in csv.DictReader(source):
brief = row["brief"].strip()
reference = row.get("reference_png", "").strip()
yield {
"prompt": f"Create an SVG icon: {brief}\nWrite icon.svg in the workspace.",
"source_prompt": brief,
"files": {"icon.svg": ""},
"reference_images": (
{"icon": str((path.parent / reference).resolve())} if reference else {}
),
"max_turns": 8,
"timeout": 900,
"verify_timeout": 900,
}
def icon_adapter(**options):
return SVGIconDataset(dimensions={
"accuracy": RubricDimension("Match the original prompt's subject and style.", 0.7),
"aesthetics": RubricDimension("Balanced, clean and legible as a small icon.", 0.3),
}, **options)
register_dataset("custom-icons", icon_adapter, replace=True)
workflow = create_runner(dataset="custom-icons", loader_fn=read_icons)
def load_training_dataset(dataset_path, **kwargs):
return workflow.dataset_loader(dataset_path, **kwargs)
async def run_agent(ctx, batch):
return await workflow(ctx, batch)
def reward_fn(record):
return workflow.reward_fn(record)
Pass custom_pi.py for all three CLI hooks and your CSV as
--dataset-path. Missing, malformed, unrenderable or blank SVG submissions
receive zero before a VLM request. Visible submissions receive a weighted
continuous score; the built-in rubric covers semantic match, composition,
geometry, style and aesthetics. The custom example instead uses accuracy
and aesthetics. Rendering and VLM logic live under examples/agentic/pi/;
they are not requirements of the reusable harness runtime.
Launch training#
Set artifact locations in the controller. With an external Docker daemon, the staging path must also exist on its host at the same path:
export RUN_DIR="$PWD/runs/pi-svg"
export ARENO_PI_RESULT_DIR="$RUN_DIR/results"
export ARENO_HARBOR_ATTEMPT_DIR="$RUN_DIR/staging"
The following full-parameter configuration was exercised on eight H20 GPUs
with a local Qwen3.5-4B checkpoint. Set MODEL_PATH to your checkpoint.
Adapt GPU topology and batch/concurrency limits to available memory:
: "${MODEL_PATH:?Set the local policy checkpoint path}"
bash examples/agentic/pi/train.sh \
--ckpt "$MODEL_PATH" --dataset-path "$DATASET_PATH" \
--world-size 8 --tp-size 4 \
--batch-size 32 --n-samples 8 --max-running-prompts 256 \
--mini-bs 8 --score-micro-bs 8 \
--max-context-len 16384 --max-prompt-tokens 12288 --max-new-tokens 4096 \
--disable-thinking --drop-rollout-state --mem-frac 0.7 \
--lr 1e-6 --epochs 4 --max-steps 1000 --save-interval 50 \
--save-path "$RUN_DIR/checkpoints" --metrics-log-dir "$RUN_DIR/metrics"
The script selects GSPO, ModelScope and the example’s dataset/agent/reward
hooks. For a first integration check, use a small dataset and override
--max-steps 2; retain multiple samples per prompt to check reward variation.
AReno’s generation limit applies to each model request, while the task’s
max_turns controls the number of requests.
Inspect trajectories and the training signal#
For each attempt, $ARENO_PI_RESULT_DIR/<attempt>.json contains its
prompt_index, sample_index, result and exact model trace. The
matching directory contains Harbor logs and grading artifacts, including:
agent/trajectory.json: native Pi’s ATIF export, when available.agent/pi.txtand Pi session logs: raw tool arguments and observations.artifacts/grading.json: rendering evidence and rubric details.artifacts/submission/icon.svg: the delivered submission, when captured.
Check valid and error before interpreting a reward. For zero scores,
inspect page_valid, zero_reasons and verify_timed_out. A missing
SVG caused by malformed tool arguments is a task failure. Browser startup,
judge transport and authentication errors are infrastructure failures; a
verification-budget timeout follows the zero-reward path described in
Adapt a task.
Read optimizer and reward metrics with the repository helper:
python .agents/skills/areno-run-training/scripts/read_metrics.py "$RUN_DIR/metrics" \
--metric rollout/rewards_mean --metric rollout/rewards_std \
--metric train/grad_norm --metric train/lr --metric train/logp_abs_diff_mean \
--last 2
Confirm two optimizer updates, finite gradients and variation within at least
some prompt groups. The full-parameter integration validation completed two
updates with nonzero gradients and reward standard deviations of about
0.226 and 0.221. This establishes a working training signal; it does not
establish sustained reward improvement. A batch average can hide prompt
groups whose rewards are all identical, so group saved summaries by
prompt_index when diagnosing zero advantages.
Symptom |
Inspect or change |
|---|---|
Every reward is zero |
Inspect delivered SVGs, tool |
Judge requests fail or time out |
Check controller endpoint/model/key and service limits. The judge has bounded retries for HTTP 429/502/503/504. Lower grading concurrency; budget verification time for queueing as well as requests. |
Docker agent cannot reach the policy |
Check the container-to-controller route and
|
Workspace or container remains after a trial |
Inspect cleanup logs and native retention settings. Staging is temporary; inspect saved results after cleanup rather than relying on a live task environment. |