Planissue-criteria
PATCH/repositories/{repo_id}/issues/{issue_id}/criteria/{criterion_id}
Edit an acceptance criterion
update_issue_criterion
issue:update
A token needs theissue:updatescope: Update work items — status, fields, hierarchyGranted bymcp_agent_write,write_api,write_repository.Every operation this scope unlocksAudited · mutation
x-gitmoap-audit: {"kind":"audited","arg":"mutation"}
Quota · criteria per repo
x-gitmoap-quota: {"kind":"enforced","arg":"criteria_per_repo"}
Changes a criterion's text, description, binding, position, whether it is required to close, or
its tick; only the fields you send change, and a null binding makes it manual again. A new
binding resets the evidence gathered so far unless the issue settings say to keep it, and a
bound criterion cannot be ticked by hand. Developers and above may edit criteria; giving one a
binding counts against the repository's limit on bound criteria.
Parameters
Path
- repo_idRepositoryId (string · uuid)Repository ID
- issue_idIssueId (integer · int64)Work-item iid
- criterion_idCriterionId (string · uuid)Criterion ID
Request body
application/json- bindingCriterionBinding or nulloptional
{"binding": {...}}re-binds it and resets its evidence,{"binding": null}turns it into a manual checkbox, and omitting the key leaves the binding untouched. - checkedboolean or nulloptionalTick or untick a manual criterion. Refused with a
409for a bound one, whose state comes from its evidence. - descriptionstring or nulloptional
- ordinalinteger · int32 or nulloptional0–∞
- required_for_closeboolean or nulloptional
- textstring or nulloptional
Request body exampleSynthesized example
{}
Responses
200The updated criterion. Changing the binding resets the criterion's evidenceapplication/json
- created_atstring
- criterion_idCriterionId (string · uuid)The criterion's identifier. It never changes, so rewording or re-binding a criterion keeps its identity and its evidence.
- issue_uidIssueUid (string · uuid)
- satisfiedboolean
- stateCriterionStateunverifiedpassingfailingstalemanualA criterion's verdict.
- textstringThe human statement — the criterion's title. The label, not the identity.
- updated_atstring
- binding_exprstring or nulloptionalThe binding's
@-expression, as written. Absent for a manual criterion. - binding_keystring or nulloptionalThe normalised form of
binding_expr, which two equivalent spellings share. Absent for a manual criterion. - checkedbooleanoptionalWhether the box is ticked. Meaningful only for a manual criterion — a bound one is ticked by its
state, and ticking it by hand is refused with a409. - descriptionstring or nulloptionalAn optional longer description (markdown) — the per-criterion detail a flat checkbox could never hold.
evidenceEvidence or nulloptional
- The Evidence schema
- commit_shaCommitHash (string)
- observed_atstringWhen the run that produced the evidence finished, RFC 3339.
- pipeline_idPipelineId (string · uuid)
- pipeline_run_idPipelineRunId (string · uuid)
- node_run_idNodeRunId (string · uuid) or nulloptional
- valuenumber · double or nulloptional
- facet_categoryFacetCategory (string) or nulloptional
- facet_keyFacetKey (string) or nulloptionalThe blueprint facet this criterion belongs to, when a blueprint added it. Absent for a criterion written directly. A facet's state is rolled up from the criteria carrying its key.
- last_evidence_atstring or nulloptional
- last_evidence_commit_shaCommitHash (string) or nulloptional
- last_evidence_node_run_idNodeRunId (string · uuid) or nulloptional
- last_evidence_pipeline_idPipelineId (string · uuid) or nulloptionalThe pipeline whose run last provided evidence for this criterion. Only a later run of the same pipeline can make the criterion
stale. - last_evidence_run_idPipelineRunId (string · uuid) or nulloptional
- last_evidence_valuenumber · double or nulloptionalThe observed value, for a
MetricorCoveragebinding. - ordinalinteger · int32optional0–∞Position in the description, so the list round-trips in authoring order.
- required_for_closebooleanoptional
@optionalopts out. Everything else in a Definition of Done is required by definition.
200 exampleSynthesized example
{
"created_at": "2026-10-12T09:36:41Z",
"criterion_id": "dad175da-9686-4f61-9d25-085b5d0f53c8",
"issue_uid": "cb6f31d8-cbb5-436f-a54e-d115b77e330c",
"satisfied": false,
"state": "unverified",
"text": "text-95f7",
"updated_at": "2026-10-17T08:53:12Z",
"binding": {
"kind": "test",
"test_id": "f780eee8-721d-44df-b5a6-fc5c55dec320",
"suite": "suite-b122"
},
"binding_expr": "binding-expr-36ab",
"binding_key": "binding-key-a382",
"checked": false,
"description": "Renders each region as density contours of its operations.",
"evidence": {
"commit_sha": "5c7e3ced392a7e4dda299785b6d763359738ea43",
"observed_at": "2026-10-11T06:43:24Z",
"pipeline_id": "7caa491c-affb-4f8f-bd9f-a9677f4b09e2",
"pipeline_run_id": "9e2b7c41-3d5a-4f8e-b1c2-7a6d5e4f3c2b",
"node_run_id": "547b33fb-d3b8-4704-a451-ae90850d5b18",
"value": 3
},
"facet_category": "facet-category-7415",
"facet_key": "facet-key-4b71",
"last_evidence_at": "2026-10-17T08:27:53Z",
"last_evidence_commit_sha": "93ec118119f3e38e1641f4e2cb98ec3509796237",
"last_evidence_node_run_id": "def9ddec-55ab-4824-99c9-652527b678cc",
"last_evidence_pipeline_id": "c7a69cb0-4510-40f9-b740-f2710c296fb7",
"last_evidence_run_id": "9e2b7c41-3d5a-4f8e-b1c2-7a6d5e4f3c2b",
"last_evidence_value": 48,
"ordinal": 2,
"required_for_close": false
}
400The text is empty or too long, or the binding's arguments do not validateapplication/json
Error codes
- BAD_REQUESTThe request is malformed: a parameter or a body field is not a well-formed value of its type
errorErrorBody
- The ErrorBody schema
- codestringThe coarse category, tied to the status:
NOT_FOUND,CONFLICT,INSUFFICIENT_SCOPE. Every error has one; the API reference's error catalogue lists them all. - messagestringWhat went wrong, for a person. Written to be read, not parsed: match on
reasonorcode. - fieldstring or nulloptionalOn a
400that refused one field's value, the field, as its JSON path:email,items[0].name. Put the message under that input. Absent on every other error. - reasonstring or nulloptionalThe specific code, when the error has one:
LAST_ORGANIZATION_OWNER,BRANCH_PROTECTED. The message starts with it too. Match on this when it is present, and oncodeotherwise. - required_scopestring or nulloptionalThe scope the access token was missing, on
INSUFFICIENT_SCOPE. - violationsanyoptionalPresent on the structured-validation errors (
PROVIDER_VALIDATION_FAILEDper-node,PIPELINE_VALIDATION_FAILEDDAG): a JSON array of the offending elements, so a caller can fix every one in a single round-trip. Absent (omitted) on every other error.
400 exampleSynthesized example
{
"error": {
"code": "code-05ca",
"message": "Pin a page's payload to the build that rendered it"
}
}
401Unauthenticated — no credential, or an invalid oneapplication/json
Error codes
- UNAUTHORIZEDNo credential was sent, or the one sent is invalid, expired or revoked
errorErrorBody
- The ErrorBody schema
- codestringThe coarse category, tied to the status:
NOT_FOUND,CONFLICT,INSUFFICIENT_SCOPE. Every error has one; the API reference's error catalogue lists them all. - messagestringWhat went wrong, for a person. Written to be read, not parsed: match on
reasonorcode. - fieldstring or nulloptionalOn a
400that refused one field's value, the field, as its JSON path:email,items[0].name. Put the message under that input. Absent on every other error. - reasonstring or nulloptionalThe specific code, when the error has one:
LAST_ORGANIZATION_OWNER,BRANCH_PROTECTED. The message starts with it too. Match on this when it is present, and oncodeotherwise. - required_scopestring or nulloptionalThe scope the access token was missing, on
INSUFFICIENT_SCOPE. - violationsanyoptionalPresent on the structured-validation errors (
PROVIDER_VALIDATION_FAILEDper-node,PIPELINE_VALIDATION_FAILEDDAG): a JSON array of the offending elements, so a caller can fix every one in a single round-trip. Absent (omitted) on every other error.
401 exampleSynthesized example
{
"error": {
"code": "code-3a80",
"message": "Stream pipeline status into the run header"
}
}
403Forbidden — the caller's access level or token scope is insufficientapplication/json
Error codes
- FORBIDDENYou are signed in but may not do this here;
reasonnames the permission or the rule that refused it - INSUFFICIENT_SCOPEThe access token lacks the scope this operation needs;
required_scopenames it - PERMISSION_REQUIREDYou need a permission you do not hold here; the message names it
errorErrorBody
- The ErrorBody schema
- codestringThe coarse category, tied to the status:
NOT_FOUND,CONFLICT,INSUFFICIENT_SCOPE. Every error has one; the API reference's error catalogue lists them all. - messagestringWhat went wrong, for a person. Written to be read, not parsed: match on
reasonorcode. - fieldstring or nulloptionalOn a
400that refused one field's value, the field, as its JSON path:email,items[0].name. Put the message under that input. Absent on every other error. - reasonstring or nulloptionalThe specific code, when the error has one:
LAST_ORGANIZATION_OWNER,BRANCH_PROTECTED. The message starts with it too. Match on this when it is present, and oncodeotherwise. - required_scopestring or nulloptionalThe scope the access token was missing, on
INSUFFICIENT_SCOPE. - violationsanyoptionalPresent on the structured-validation errors (
PROVIDER_VALIDATION_FAILEDper-node,PIPELINE_VALIDATION_FAILEDDAG): a JSON array of the offending elements, so a caller can fix every one in a single round-trip. Absent (omitted) on every other error.
403 exampleSynthesized example
{
"error": {
"code": "code-9e1e",
"message": "Stream pipeline status into the run header"
}
}
404Work item or criterion not foundapplication/json
Error codes
- NOT_FOUNDThe resource does not exist — or exists and you cannot see it: a private resource you have no access to answers exactly as an absent one does
errorErrorBody
- The ErrorBody schema
- codestringThe coarse category, tied to the status:
NOT_FOUND,CONFLICT,INSUFFICIENT_SCOPE. Every error has one; the API reference's error catalogue lists them all. - messagestringWhat went wrong, for a person. Written to be read, not parsed: match on
reasonorcode. - fieldstring or nulloptionalOn a
400that refused one field's value, the field, as its JSON path:email,items[0].name. Put the message under that input. Absent on every other error. - reasonstring or nulloptionalThe specific code, when the error has one:
LAST_ORGANIZATION_OWNER,BRANCH_PROTECTED. The message starts with it too. Match on this when it is present, and oncodeotherwise. - required_scopestring or nulloptionalThe scope the access token was missing, on
INSUFFICIENT_SCOPE. - violationsanyoptionalPresent on the structured-validation errors (
PROVIDER_VALIDATION_FAILEDper-node,PIPELINE_VALIDATION_FAILEDDAG): a JSON array of the offending elements, so a caller can fix every one in a single round-trip. Absent (omitted) on every other error.
404 exampleSynthesized example
{
"error": {
"code": "code-3f46",
"message": "Pin a page's payload to the build that rendered it"
}
}
409A bound criterion cannot be ticked by hand; unbind it firstapplication/json
Error codes
- CONFLICTThe request conflicts with the resource's current state;
reasonsays how - CRITERION_IS_BOUNDThe criterion is bound to evidence a pipeline produces, so it cannot be ticked by hand; unbind it first
- LEGAL_ACCEPTANCE_REQUIREDAccept the current Terms of Service before changing anything; reading stays open
errorErrorBody
- The ErrorBody schema
- codestringThe coarse category, tied to the status:
NOT_FOUND,CONFLICT,INSUFFICIENT_SCOPE. Every error has one; the API reference's error catalogue lists them all. - messagestringWhat went wrong, for a person. Written to be read, not parsed: match on
reasonorcode. - fieldstring or nulloptionalOn a
400that refused one field's value, the field, as its JSON path:email,items[0].name. Put the message under that input. Absent on every other error. - reasonstring or nulloptionalThe specific code, when the error has one:
LAST_ORGANIZATION_OWNER,BRANCH_PROTECTED. The message starts with it too. Match on this when it is present, and oncodeotherwise. - required_scopestring or nulloptionalThe scope the access token was missing, on
INSUFFICIENT_SCOPE. - violationsanyoptionalPresent on the structured-validation errors (
PROVIDER_VALIDATION_FAILEDper-node,PIPELINE_VALIDATION_FAILEDDAG): a JSON array of the offending elements, so a caller can fix every one in a single round-trip. Absent (omitted) on every other error.
409 exampleSynthesized example
{
"error": {
"code": "code-3390",
"message": "Draw the region map from operation density"
}
}
429Bound-criterion limit reached for this repositoryapplication/json
Error codes
- TOO_MANY_REQUESTSRetryableA quota, a rate limit or a transfer budget is spent. When the response carries
Retry-After, retry after that many seconds
errorErrorBody
- The ErrorBody schema
- codestringThe coarse category, tied to the status:
NOT_FOUND,CONFLICT,INSUFFICIENT_SCOPE. Every error has one; the API reference's error catalogue lists them all. - messagestringWhat went wrong, for a person. Written to be read, not parsed: match on
reasonorcode. - fieldstring or nulloptionalOn a
400that refused one field's value, the field, as its JSON path:email,items[0].name. Put the message under that input. Absent on every other error. - reasonstring or nulloptionalThe specific code, when the error has one:
LAST_ORGANIZATION_OWNER,BRANCH_PROTECTED. The message starts with it too. Match on this when it is present, and oncodeotherwise. - required_scopestring or nulloptionalThe scope the access token was missing, on
INSUFFICIENT_SCOPE. - violationsanyoptionalPresent on the structured-validation errors (
PROVIDER_VALIDATION_FAILEDper-node,PIPELINE_VALIDATION_FAILEDDAG): a JSON array of the offending elements, so a caller can fix every one in a single round-trip. Absent (omitted) on every other error.
429 exampleSynthesized example
{
"error": {
"code": "code-0f32",
"message": "Inline scalar newtypes but keep their brand"
}
}
CLI
gitmoap issue-criteria update
- --repo-ididRepository ID (id or owner/repo path)
- --issue-ididWork-item iid
- --criterion-ididCriterion ID
- --bindingjsonoptional
- --checkedflagoptionalTick or untick a manual criterion. Refused with a `409` for a bound one, whose state comes from its evidence.
- --descriptionstringoptional
- --ordinalnumberoptional
- --required-for-closeflagoptional
- --textstringoptional