Review and land
The points where a run waits for a person: its spec, its plan and its acceptance criteria. Then how a finished change lands, and what to do when a landing is held.
A run can stop twice for a person. First before it builds, so you can check its spec and plan. Then after it builds, if its change is held before it lands. This page covers both, and says at each step who may act.
Every path below starts with https://api.syndai.ai/api/v1/external/coding.
Who may act
Some steps take an API key. Others need a person who is signed in at app.syndai.ai.
| step | API key | signed-in person |
|---|---|---|
| read the spec, plan, criteria and held diff | yes | yes |
| confirm, edit, skip or extend the spec review | no: 401 | the person who started the run, or an owner or admin |
| ask for changes to the spec or plan | no: 401 | the same |
| co-sign criteria that were approved on their own | no: 401 | a person allowed to review the run |
| go live with a change that is not held | yes | an owner or admin |
| retry or close a held landing | yes | an owner or admin |
| go live anyway with a held change | no: 403 HUMAN_APPROVAL_REQUIRED | an owner or admin |
| revert a change that went live | yes | an owner or admin |
When a key gets HUMAN_APPROVAL_REQUIRED, the error has a review_url. Send that link to the owner. Nothing changed. See Actions only a person can take.
1. The spec review
Before it builds, a run drafts a spec: a brief, a goal and a list of acceptance criteria. The run's spec_review policy says if it waits for you:
spec_review | what the run does |
|---|---|
| not set | builds at once. A large plan waits like timed. |
auto | never waits |
timed | waits for you, then builds on its own if no one acts in time |
hold | waits until a person confirms. If no one does, the run ends without building. |
A run with no one to answer never waits. That covers scheduled runs and unattended runs. See Policy.
When the spec is ready, Syndai sends coding.run.spec_review_ready. Read it from GET /runs/{id}:
spec_review.roundis the round you are looking at. The review calls below take it asbase_round.criterialists each criterion with itscriterion_key,textandstatus.spec_review_wait_untilis when atimedreview builds on its own.
A person then does one of these:
| call | what it does |
|---|---|
POST /runs/{id}/criteria/ratify?base_round=N | confirms the criteria, signs the spec and starts the build now |
POST /runs/{id}/criteria/{key}/edit | rewrites one criterion. A timed wait starts again. |
POST /runs/{id}/spec/request-changes | sends notes. The run writes the next round. |
POST /runs/{id}/spec/skip-review?base_round=N | builds now on the spec as it is. The criteria stay drafted. |
POST /runs/{id}/spec/extend-review | gives a timed review 15 more minutes |
A stale base_round, a closed review or a cancelled run answers 409. Read the run again and use the new round. Each call is on the Run review reference page.
When no one confirmed
A timed review that runs out builds on the drafted criteria. A person can sign them later with POST /runs/{id}/criteria/cosign. If the run already delivered, its receipt is issued again with the signed criteria. It is safe to call twice.
2. The plan review
The same wait covers the plan the agent writes. Read it in engineering_plan on GET /runs/{id}. When it is cut short, GET /runs/{id}/plan/{plan_sha256} returns the whole text.
To ask for a new plan, a person sends notes to POST /runs/{id}/plan/request-changes. The body has the plan_sha256 they read, an idempotency_key, and an overall_comment or notes on parts of the text.
The run wakes and writes a new plan. The same idempotency_key with the same notes does nothing twice. Confirming the criteria is what ends the wait. See Request changes to a run's plan.
3. The build
Now the run builds, checks its work and passes its review gates. It needs no one here, unless it asks a question. See Run lifecycle.
4. Land
The autonomy policy says what happens once the checks pass:
autonomy | what happens |
|---|---|
auto | opens a pull request for you to review |
gated | stops before the pull request until a person approves it |
merge | opens the pull request and merges it once every gate is green |
push | moves the default branch to the checked commit (API only) |
run.land on GET /runs/{id} tracks the change from there. Its state is an open string. Syndai sends coding.run.land_changed when it turns held, live, failed or reverted. On live, read land.live_url.
Go live
For a finished change on a project Syndai hosts, POST /runs/{id}/land/go-live puts it live. It answers 202 with the landing, which then runs every check. Follow the run until land.state moves on.
A 409 names one of three cases: the change is still too early, already live, or already landing. See Send a finished change live.
A held landing
Syndai holds a change before it lands when a check is red, or when it touches protected files or agent settings. land.reason says why, and land.can_merge_anyway says if a person may push past it.
| call | who | what it does |
|---|---|---|
GET /runs/{id}/land/held-diff | key or person | each held file with its diff, and the head_sha an approval must name |
POST /runs/{id}/land/retry | key or person | starts the landing again. It never merges twice. |
POST /runs/{id}/land/close | key or person | gives up and marks the landing failed. An open pull request stays open. |
POST /runs/{id}/land/merge-anyway | person only | lands it past the checks that held it, then checks it live |
Reading the diff is not approving it. To go live anyway, a person sends the head_sha they read as {"head_sha": "…"}. They do this from the run page in the app, or from the review_url a key was given.
409 means the change moved since they read it, or the hold is not one a person may push past. A retry drops an earlier go-live-anyway. Each call is on the Landing reference page.
After it is live
To undo a change that went live, see Undo a change that went live.