Model Loops
Use Model Loops to follow a model-improvement experiment across rounds: read progress, compare candidate versions and send guidance for the next round. These recursive self-improvement (RSI) loops use feedback from each round to plan the next. Open RSI LOOPS → Model in the Console to view progress; use the CLI, REST API or MCP steps below to start and control a loop.
Improvement targets in RSI LOOPS
Compare the baseline and candidate versions using the same evaluation protocol. The page shows the versions, scores, checks and reviews reported for the experiment. Open the evaluation details to read score coverage; — means that a value was not provided.
Use Model Loops to compare model versions and training methods, including loops that generate data as part of the experiment.
Console shows the loop’s progress and results. el job run list / get groups training Jobs by their run label, so use it to inspect the training work associated with an experiment.
Open the Console section
- Select the workspace and project where the loop runs.
- Open RSI LOOPS → Model in the sidebar.
- Review each run's state, round out of its target, best version and last update, newest first. Use Refresh for a current view, and All columns to see every column on a narrow screen.
- Search by run name or filter by state. The URL keeps these filters; clear them to see every loop.
- Use the shared pagination footer to move through the list or change the number of rows. Last update shows the full date and time in your browser's time zone.
- Open a run name or View for its details.
A run appears in this list when either a training Job in the selected project carries the run's rsi_run label, or the run was started by a caller in your workspace and project. The second rule means a freshly started run, for example one started through MCP, is listed before its first training Job exists. Runs started before owners were recorded appear through their tagged training Jobs only.
If the loop service is not connected to the deployment, the page says so. If it cannot be reached, the page says that agent runs are unavailable and offers Retry.
Read a run
The run page shows state, round, best version and machine above its tabs.
- Overview combines the classic-example steps and live progress. Progress includes the phase, current role and tool, recent activity (newest first), steering history with delivery status and jobs started by the loop. It refreshes about every three seconds while Overview is visible and stops once the loop has finished, failed or stopped. Existing
?tab=livelinks open Overview too. - Evaluations shows scores by version (trained rows and evaluation suites/splits, with mean, interval and sample size when supplied) and the final gate (candidate score and change relative to the baseline).
- Rounds shows decisions and summaries; Details opens a round's plan and interventions.
- Audits shows audit type, version, approval or rejection and first reason.
- Owner directives shows guidance already submitted to the run as text.
- Cost, the rightmost tab, shows spend, its cap and GPU spend reported by the loop. Use the page’s Refresh button to read the latest amounts.
Values shown as — were not provided. A "Best" label, gate or audit is evidence reported by the loop; inspect its evaluation coverage and protocol before making an improvement claim. Keep each observation’s source and scope.
A training Job created by an RSI loop also has a Loop progress tab in Experiment → Jobs, with a link to the Agent Run page.
Inspect related training Jobs
el job run list
el job run get RUN_NAME
el job run get RUN_NAME --json
Replace RUN_NAME with the exact run label returned by the list. These commands group visible training Jobs and show rounds, their Jobs and recorded checkpoints. The default output is a table; --json preserves the full response. There are no --cursor or --limit flags on this complete-list command, and it does not create or stop a loop. Loop-specific scores, audits, directives and live progress come from the separate RSI API.
Preview client: when el job run --help lists start, live, steer and stop, use the following commands to control a loop. For a client without them, use the REST or MCP steps below (see Start a loop):
el job run start arith-carry-1 --brief "Improve multi-digit carries." --max-model-cost-usd 5 --dry-run
el job run live arith-carry-1 --follow
el job run steer arith-carry-1 "Prefer held-out families."
el job run stop arith-carry-1
start takes the fields of rsi_start_run as options (--brief or --brief-file, --max-model-cost-usd, --max-cost-usd, --max-model-requests, --domain, --rounds, --dry-run, --student-model). The three limit options set limits.max_model_cost_usd, limits.max_cost_usd and limits.max_model_requests. live prints the live view as JSON, or with --follow one seq kind: text line per new event until the run ends; Ctrl-C leaves the run running. stop needs training.stop as well. A refused command prints a fixed explanation and the error code, not the service's message; the API shows that message.
Start a loop
Start with the preview CLI, REST API or MCP. Starting a loop allocates resources; honor the requested limits and start only when intended.
You need a project API key that holds the training.run capability (the Project automation preset has it, and training.stop), or a signed-in Developer or Admin session. Read-only keys and Viewers receive 403 ACCESS_DENIED.
From a coding agent (MCP)
Connect Claude Code or Codex to the RSI MCP endpoint with your API key, then ask it to start and follow a run.
# Claude Code
claude mcp add --transport http envloop-rsi https://api.envloop.ai/v1/agent-runs/rsi/mcp \
--header "Authorization: Bearer $ENVLOOP_API_KEY"
# Codex: ~/.codex/config.toml (the key stays in the environment)
[mcp_servers.envloop-rsi]
url = "https://api.envloop.ai/v1/agent-runs/rsi/mcp"
bearer_token_env_var = "ENVLOOP_API_KEY"
Any MCP client that supports Streamable HTTP and a bearer header works the same way. The server is stateless and answers JSON, and tools/list returns every tool with its exact input schema. The tools:
| Tool | What it does | Needs |
|---|---|---|
rsi_list_runs | The runs of your project: state, round, target, best version, spend, owner. | read |
rsi_run_status | One run in detail: summary line, steps of the classic example, versions with scores, audits, rounds, spend. compact: true returns only the summary fields (cheap to poll). | read |
rsi_status | What a run does right now, as in the live view below. since is the previous next_cursor. | read |
rsi_round | One round: decision, plan, interventions, audits, summary (round is 1 or higher). | read |
rsi_start_run | Starts a new run (see below). | training.run |
rsi_add_directive | Appends a standing instruction (1 to 4000 characters) to the run's owner directives. | training.run |
rsi_steer | Sends guidance to the running loop (1 to 4000 characters). | training.run |
rsi_control | extend (set the target rounds), stop (after the current round) or resume. extend and resume start paid work. | training.run; stop needs training.stop |
rsi_start_run takes:
| Field | Meaning |
|---|---|
run (required) | A new run id: 1 to 64 lower-case letters, digits and dashes, for example arith-carry-1. An id that exists returns a conflict. |
brief (required) | The goal, up to 4000 characters, added to every round of the run. |
limits.max_model_cost_usd (required) | The spend cap in USD of the strong-model API: the hard stop. |
limits.max_cost_usd | Cap in USD for model plus GPU training together. Set it to bound a live run's whole cost. |
limits.max_model_requests | Cap on model requests. |
other limits keys | Optional positive-number tuning keys (counts are integers): request_cap, student_request_cap, diag_per_family, dev_n, collect_tasks, collect_k, admission_n, blind_n, max_rows_per_family, dev_use_cap, eval_limit, calib_n. There is no separate GPU cap: GPU spend is max_cost_usd minus model spend. An unknown key is rejected. |
domain | The task family. One of arith, code, spatial or finance; default arith. |
rounds | Target rounds, 1 to 1000; default 3. A very high target is effectively unbounded: the spend caps then stop the run. |
dry_run | true starts a GPU-free run: nothing is trained and the student is answered through the model gateway, so it exercises the loop and does not improve a model. It still spends model budget. |
student_model | The gateway student of a dry run; only with dry_run: true. |
The finance domain asks the student to pick an option ID and grades it with judge finance-option-v2. An answer counts only as a bare option ID, or as reasoning whose last non-empty line is exactly one marker ANSWER: <ID>. A hedge, a second option, two markers or a marker that is not last names no option and scores 0.
A start returns state: "starting", the run's mode (live or dry), its owner and the caps it will enforce. The run appears in the Console list at once. Follow it with rsi_status or the Console page, and stop it with rsi_control.
From a script (REST)
The same operations are plain HTTP routes under https://api.envloop.ai/v1/agent-runs/rsi:
curl -X POST -H "Authorization: Bearer $ENVLOOP_API_KEY" -H "Content-Type: application/json" \
-d '{"run": "arith-carry-1", "brief": "Improve multi-digit carries.", "limits": {"max_model_cost_usd": 5}, "dry_run": true}' \
"https://api.envloop.ai/v1/agent-runs/rsi/runs"
curl -X POST -H "Authorization: Bearer $ENVLOOP_API_KEY" -H "Content-Type: application/json" \
-d '{"action": "stop"}' "https://api.envloop.ai/v1/agent-runs/rsi/runs/arith-carry-1/control"
POST /runs returns 201 and takes the fields of rsi_start_run. POST /runs/RUN_NAME/control takes action (extend, stop or resume) and, for extend, rounds (1 to 1000). A rejected request returns 422 INVALID_RSI_REQUEST, or 409 RSI_CONFLICT when the run id exists, the run is in the wrong state or no machine is free, and the message says which field or condition. GET /runs returns an empty items list with a start hint when your project has no runs.
The el CLI wraps these routes: el job run start, live, steer and stop (see the CLI section).
Steer a running loop with the API or MCP
Use the preview CLI, REST API or RSI MCP endpoint to send guidance or stop a loop. Follow progress in the read-only Console.
The live view is available through the API with an EnvLoop API key that can read training Jobs in the project that owns the run:
curl -H "Authorization: Bearer $ENVLOOP_API_KEY" \
"https://api.envloop.ai/v1/agent-runs/rsi/runs/RUN_NAME/live"
curl -H "Authorization: Bearer $ENVLOOP_API_KEY" \
"https://api.envloop.ai/v1/agent-runs/rsi/runs/RUN_NAME/live?since=43"
The response contains state, round, rounds_target, phase, current (role, tool and start time), events, next_cursor, steers, jobs, spend and updated_at. events are ordered oldest to newest, at most 200 per response, each with a seq, a kind (message, tool_call, tool_result, steer, round, job or error) and a short summary text. Pass the previous next_cursor as since to receive only newer events; since must be a non-negative integer. An unknown run, or one that is not visible to your project, returns 404 RSI_RUN_NOT_FOUND.
A run is visible to you when either of these is true: a training Job in your project carries the run's rsi_run label, or the run was started by a caller in your workspace and project (the RSI service records that owner when the run starts). The second rule makes a freshly started run, for example one started through MCP, visible before its first training Job exists. Runs started before owners were recorded are visible through their tagged training Jobs only. The same rule applies to the run list, detail, rounds, live progress, steering and directives; steering and directives still need the permissions described below.
To steer a loop that is starting, running or paused, send text of 1 to 4000 characters. This needs the Developer or Admin role in a signed-in session, or an API key with the training.run capability; read-only keys and Viewers receive 403 ACCESS_DENIED.
curl -X POST -H "Authorization: Bearer $ENVLOOP_API_KEY" -H "Content-Type: application/json" \
-d '{"text": "Prefer held-out families when choosing data."}' \
"https://api.envloop.ai/v1/agent-runs/rsi/runs/RUN_NAME/steer"
The request returns 202 with the steering message's id, status (queued) and time. The loop delivers queued messages at its next turn boundary, so the message appears in steers first as queued and later as delivered, or as dropped if it could not be delivered. The author is recorded from your authenticated identity, not from the request body. A run that is not active returns 409 RSI_RUN_NOT_ACTIVE, and empty or oversized text returns 422 INVALID_STEER.
External agents use the same operations through the RSI MCP endpoint (see Start a loop): the rsi_status tool (run and optional since) and the rsi_steer tool (run and text). Steering through MCP follows the same permission rules.
How Jobs join a run
The training Job's tags field supplies the grouping information. Generic agent_* fields take precedence over corresponding rsi_* fields when both are present.
A Job uses its tags for grouping; historical Jobs fall back to session user_metadata. When session metadata is absent and exactly one training model exists, that model’s metadata is used. Per-model metadata remains available in the Job’s training-run detail. Recover a specific Job from a trainer by matching trainer.model_id against training.model_ids in the paginated client.jobs.list(type="train") response; the run label is a grouping tag, not a Job ID.
{
"agent_run": "example-evaluation-loop",
"agent_round": "2",
"agent_purpose": "train candidate",
"agent_method": "sft",
"agent_checkpoint": "candidate-2",
"agent": "example-agent"
}
This is a metadata example, not a standalone submission. Supply it through the training workflow supported by your client; see Training. agent_run / rsi_run names the group, agent_round / rsi_round names the round, and the purpose, method and checkpoint keys label the corresponding training. Tags do not independently verify that a training step, checkpoint or evaluation succeeded. A managed Qwen/Qwen3.8-27B Job takes these keys as its tags field (options) and returns them as training.tags and training.user_metadata, which is where the run lists read rsi_run and rsi_round. Open each linked Job to inspect its training result, checkpoints and evaluation.
Inspect individual resources
Use el job get JOB_ID or the Console Jobs page for an individual training Job. Inspect Checkpoints for saved weights and Inference for serving. Compare held-out evaluation scores and coverage across versions to measure improvement.