The repair loop
What mainsdk check --json --agent prints, how a coding agent reads each field, when it must ask a person, and how to use the same output in CI.
Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.
Stability The promise an interface ships with.
- Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
- Beta Usable in production; may change before it becomes stable.
- Experimental May change or go away; needs an explicit opt-in in main.yaml.
A coding agent fixes what the check finds, runs the check again, and stops after three unresolved rounds on the same finding. This page shows the output it reads and what each field means. It takes about five minutes.
mainsdk check --json --agent is planned for 0.3 (spec fast-start). MainSDK is pre-release and the command does not run yet.
You need
- A project with
main.yaml(npx mainsdk init). - A coding agent that can run a shell command and read JSON.
1. Run the check in agent mode
npx mainsdk check --json --agentThe output is the same document as mainsdk check --json, with the fix and the file on every finding and a hint for how many rounds to try. Exit codes: 0 passed, 1 a gate failed, 2 a usage or configuration error (with a MAIN-CONFIG- code).
{ "version": 1, "project": "prj_01JC8Q…", "env": "prod", "passed": false,
"gates": [{ "id": "secrets", "passed": false, "findings": [
{ "code": "MAIN-SECRET-0002", "severity": "critical", "file": "app/lib/pay.ts", "line": 3,
"rule": "secrets.no_literal", "fix": "Move the key to secrets and use secret:STRIPE_KEY" } ] }] }2. Read each field
| Field | What the agent does with it |
|---|---|
passed | true means stop and report. false means there is at least one finding. |
gates[].id | The gate that failed (secrets above). Fix the failed gates in the order printed. |
code | The finding. Run npx mainsdk explain <code> for the full explanation, offline. |
severity | How serious it is. Fix every severity; do not skip low ones. |
file and line | Where to change code. Change only what the finding names. |
rule | The rule that fired. Never edit the rule to make the finding go away. |
fix | What to do. Apply it, then re-run. |
ask | person means stop. See step 4. |
The max-iterations hint that --agent adds (its field name and place in the document) is not decided yet: the spec fixes the behaviour, not the field. Until it is fixed, count rounds yourself: stop at three.
3. An example of two rounds
Round 1. The agent runs the check and gets the finding above. It moves the key into main.yaml as secret:STRIPE_KEY and reads it through the interface, then runs the check again.
Round 2. The secret is gone, but a new finding in a different gate appears:
{ "version": 1, "project": "prj_01JC8Q…", "env": "prod", "passed": false,
"gates": [{ "id": "data", "passed": false, "findings": [
{ "code": "MAIN-DATA-0007", "severity": "critical", "file": "app/api/orders/route.ts", "line": 12,
"rule": "[to be decided]", "fix": "Query with db.orders.for(user)" } ] }] }The agent changes line 12 to db.orders.for(session.user).list() and runs the check a third time:
{ "version": 1, "project": "prj_01JC8Q…", "env": "prod", "passed": true, "gates": [] }Exit code 0. The agent reports what changed in main.yaml and the result. (The gates list for a passing run is shown empty here; its exact content on a pass is not decided yet.)
4. When the check says ask: person
If the same finding is still unresolved after three runs, the fourth run returns the finding with ask: person and no further fix text (fast-start.AC4). The agent stops editing. It tells the developer which finding is stuck, what it tried in each round, and what it thinks the blocker is.
{ "code": "MAIN-DATA-0007", "severity": "critical", "file": "app/api/orders/route.ts", "line": 12,
"ask": "person" }The agent does not try a fourth fix, and it does not reach for an exception or raw(). A person decides: change the design, or accept the finding as an exception with an owner and an expiry date.
How the check knows a round is "the same finding" (by code and file, or code, file and line) and where it keeps the count is not decided yet.
5. Explain a code
npx mainsdk explain MAIN-DATA-0007explain takes a code or a trace id, and --json for machine output. It runs offline. Use it when a fix is not clear enough; do not use it to find a way around a rule.
6. Use it in CI
Run the same command on every pull request. A non-zero exit fails the build.
npx mainsdk check --json --sarif out.sarif--sarif <file> writes SARIF 2.1.0 so code scanning shows each finding inline at its file and line. --agent is the stable output for repair loops. --fail-on <severity> sets the severity that fails the run; the severity names are not decided yet.
Verify
npx mainsdk check --json --agentYou should see "passed": true and exit code 0.
If it fails
| Code | Cause | Fix |
|---|---|---|
MAIN-CONFIG-… (exit 2) | main.yaml or the command is wrong | Read the code's fix, then run npx mainsdk explain <code> |
MAIN-CHECK-0026 | An interface still resolves to a local driver in production | Set a real driver in main.env.prod.yaml |
ask: person | Three unresolved rounds | Stop and ask the developer |
For agents
Goal: Reach "passed": true without changing any rule.
Loop: run `npx mainsdk check --json --agent`; for each finding open `file` at `line`,
apply `fix`, run `npx mainsdk explain <code>` if unclear; run the check again.
Stop: after three unresolved rounds on one finding, or when a finding has
`ask: "person"`. Tell the developer the code, file, line and what you tried.
Never: edit `rule`, lower a severity, add an exception, delete a test or use raw().Next
Open questions
Was this page helpful?