Authoring your own mission bundle is coming soon, so
xorcise mission ingest is not enabled in this release and the Ingest a bundle button on the Missions page opens a preview of the feature rather than installing anything. Missions come from the free XORCISE library today — browse them with xorcise mission list, install one with xorcise mission pull <id>, or use the Missions page. Their checks are graded exactly as described below, and this page is the spec to write against while you prepare a bundle of your own.Sources and ops at a glance
Three sources exist. Anything else is rejected by manifest validation.
Four ops exist. The
args key set is exact for each one: a missing or extra key fails at ingest.
How a check is evaluated
XORCISE resolvesref against source to get a value, then applies op to that value using args. Fetching and asserting are independent, which is why any op is accepted with any source.
string
required
Your name for the check. Appears in the result breakdown.
string
required
Which store to read.
string
required
The lookup key into that store — an artifact name, a stat key, a fact name.
string
required
The assertion to apply.
object
The value compared against, under the exact key the op requires. Defaults to
{}.ref and args carry different things and are frequently confused. ref is the lookup key into the source; args carries the value compared against. In {"ref": "flag", "op": "equals", "args": {"expected": "XORCISE{...}"}}, flag is the name of the artifact to look up and XORCISE{...} is what its content must equal. A ref that names nothing resolves to null rather than raising, so the op decides the verdict.
A check never crashes grading. An unknown op, or an exception inside a resolver or an op, records passed: false with an error string on the verdict, and the check consumes its weight as a failure. A failing check that carries an error is an authoring bug, not an agent failure.
The examples below are entries in the manifest’s checks array. They omit weight, which is legal as long as no check in the array declares one.
Sources
artifacts
- What it does — reads the artifacts the agent submitted over run-control with
POST /artifacts. The flag is the artifact namedflag; there is no separate flag field. - Arguments —
refis the artifact name as the agent submitted it. Every value is a string. - Passes when — the agent submitted an artifact under exactly that name and the op returns true for its string value.
- Fails when — no submission carries that name, so the value resolves to
nulland every op fails on it; or the op returns false. A name mismatch records no error on the verdict.
otel-stats
- What it does — reads a projection over the run’s sealed raw trace. The values are derived from what the agent exported, so they are forgeable: treat
otel-statsas a convenience, not an anchor. - Arguments —
refis a stat key. Exactly two exist, and both equal the number of stored raw trace records:turn-countandspan-payload-count. - Passes when —
refnames one of those two keys and the op returns true for the count. - Fails when —
refnames anything else, so the value resolves tonull; or the count fails the op.
observed-facts
- What it does — reads the facts XORCISE recorded about the run itself. The agent cannot write these, which makes this the anti-forgery source.
- Arguments —
refis a fact name from the closed list below. Two facts recorded under the same name are last-writer-wins. - Passes when — XORCISE recorded that fact for this run and the op returns true for its value.
- Fails when —
refis not a name XORCISE records, or this run never produced that fact. A static mission has no network or targets, so it records onlyprompt,attachmentandcollector.
Ops
equals
- What it does — compares the resolved value with a declared literal for exact equality.
- Arguments —
expected, the literal to compare against. No other key is accepted. - Passes when — the resolved value equals
expected, type included. - Fails when — the values differ in content or in type. Artifacts are always strings, so
{"expected": 3}never matches a submitted"3".
matches_format
- What it does — matches the resolved value against a regular expression.
- Arguments —
pattern, the regex. Escape backslashes for JSON:XORCISE\\{.+\\}. - Passes when — the value is a string and the pattern matches the whole of it.
- Fails when — the value is not a string, including
null; or the pattern matches only part of the value. This is a full match, not a search, so an anchor-free pattern must still span the entire value.
observed
- What it does — asserts that the value is present and non-empty.
- Arguments — none. Omit
argsor declare it as{}. - Passes when — the value exists and is truthy.
- Fails when — the
refresolved tonull, or the value is"",0,false, or an empty list.
lesser_than
- What it does — compares the resolved value numerically against a threshold.
- Arguments —
value, the threshold. The argument really is namedvalue; the resolved value reaches the op positionally, so the two do not collide. - Passes when — the resolved value and the threshold are both numeric and the resolved value is strictly smaller.
- Fails when — either side is not numeric, or the value is greater than or equal to the threshold. An artifact is always a string and is therefore never numeric.
Pairing a source with an op
Ingest accepts every combination, because the source and the op are validated independently. Three of these 12 combinations can never pass, because the value the source produces is the wrong type for the op.otel-stats is the only source that supports a numeric comparison.
Weighting
Either every check declares aweight or none does. Mixing the two is rejected at ingest with checks must ALL declare weight or NONE declare it (no mix).
- All checks declare
weight— the declared numbers are used as-is. Each must be greater than0and at most1, and they must sum to1.0. A sum that misses is rejected withcheck weights must sum to 1.0, got 0.9000. - No check declares
weight— every check gets1/n. The resolved weight is written back onto each verdict, so the result breakdown always shows real numbers.
0.0, which caps the overall score at 50%; see How grading works for how the two halves combine.
Traps that fail silently
Each of these produces a check that ingests cleanly, records no error, and fails on every run.Observed-fact names that are never recorded
Artifact names the agent did not use
An artifact check’sref is keyed on the name the agent submitted, and nothing validates it against the artifacts your manifest declares. If the agent submits Flag or flag against a check with ref: "flag", the lookup misses, the check fails, and the verdict carries no error to explain it — it reads as an ordinary failed check.
The mission prompt is the only channel that tells the agent the names, and GET /mission does not repeat them, so put the exact artifact names in metadata.objective as well. Resubmission under the same name is last-writer-wins.
required: true does not gate anything
required on a declared artifact is advisory. Grading never reads manifest.artifacts — it reads checks and rubric only. A missing required artifact resolves to null, the check written against it forfeits its weight, and the run grades and terminates normally. There is no incomplete-submission verdict. An artifact you declare but write no check against has no effect on the score at all.
Related pages
- How grading works — how passing weights become half the score.
- Mission manifest — where
checkssits inmission.json.