Ingesting your own mission bundle is coming soon. Everything below — the manifest format, artifacts, checks, rubric, terrain — is the spec you author against, but neither surface that would install one is available yet:
xorcise mission ingest prints a coming-soon notice, and the Ingest a bundle button on the Missions page opens a preview of the feature rather than a directory picker.To get missions today, pull them from the free XORCISE library: xorcise mission list to browse, xorcise mission pull <id> to install, or the same thing from the Missions page. No account, no key, no sign-in.Lab or static
Decide this first.metadata.type is required, it takes exactly two values, and it changes what you author, how the run works, and what the agent is told.
Pick
lab when the point is reaching and exploiting something. Pick static when the point is analysis — a capture, a binary, a disk image, a log set. This guide builds the lab first and shows the static difference at each step.
1. Create the bundle directory
Name the directory after the mission id you intend to use. Nothing enforces that locally, but it keeps the two in step, and the XORCISE library requires the id to match the display name.Output
2. Build what the agent works against
For a lab, write a compose file. Give every network an explicit name — the agent reaches the mission through the networks you list as entry networks, so an unnamed network is unreachable.docker-compose.yml
services/web/Dockerfile
player under networks. An error here is a compose error, and ingestion will report it later and less clearly.
3. Write the manifest
Createmission.json at the bundle root. Start with identity and the mission — the two blocks that are always required.
mission.json
objectiveis the agent’s whole brief.summaryis for you and the catalog; the agent never sees it.<web-target-ip->is a placeholder XORCISE substitutes with the resolved address of thewebservice. Compose service names do not resolve on the per-run network, so writinghttp://web:80gives the agent an address it cannot reach.static_ipsis what creates targets at all. It pinswebon theplayernetwork, which is an entry network, sowebbecomes a target and the placeholder resolves. A service pinned only on a non-entry network gets no address — that is how you build a pivot the agent has to earn.
environment block with attachments, and its objective stands alone because there is nothing to address:
mission.json
Output
4. Declare what the agent submits
Add anartifacts array. The flag is the artifact named flag — there is no separate flag mechanism.
mission.json
required: truedoes not gate anything. It prints(required)in the prompt and stops there. A missing artifact costs the score of the checks that read it, and nothing else. Declare an artifact and write no check against it, and it cannot affect the score at all.- The lookup key is the name the agent submits, not the name you declared. They line up only because the prompt told the agent what to call it. Name your artifacts something an agent will copy exactly, and repeat the name in the
objective— the mission prompt is the only place the agent is ever told.
Output
5. Define the grading
Every run is scored as0.5 × deterministic + 0.5 × judge, and the split is fixed. checks earn the first half; rubric earns the second. Ship both — a mission with only checks, or only a rubric, caps at 50%.
mission.json
source using ref as the lookup key, then asserts over it with an op. The full source, ref and op vocabulary is in Checks and ops; the rule to learn now is the weighting.
Check weights are all-or-none. Either every check declares one and they sum to 1.0, or none does and XORCISE splits the half equally. A mix fails at ingest with a clear message.
Write rubric criteria as things a reader of the transcript could confirm. The judge is a model reading your text against the run record, so “identified the injectable parameter” is gradable and “solved the mission well” is not.
You should see both weight sets total exactly one:
Output
6. Ingest the bundle (coming soon)
Installing a bundle from disk is not available in this release. Every form of the command — with a path, without one, pointing anywhere — prints a notice instead:Output
mission validate command and no scaffold command — so it is where every mistake surfaces. It validates the manifest, builds every service in the compose file, and installs the result as xorcise-fused/sqli-login:latest. A static mission skips the build entirely and installs in seconds.
7. Run it and read the score
Running a mission and reading its score works today — against a mission you pulled from the library (xorcise mission pull <id>). It is the same loop your own mission will use once ingestion ships, so walk it now with a pulled mission id in place of sqli-login.
Create a run against the mission with a registered agent, launch the agent, and read the result.
<run_id> below.
flag-correct, found-injection and read-flag show up — the loop closed, your rubric scoring a real agent.
If the judge half reads 0.0 with judge_status: "model-not-configured", the mission is fine and no judge model is set. Configure one and re-grade the sealed run rather than running it again.
Fix a rejected bundle
Ingestion reports the first rule a bundle breaks. These are the ones that catch new authors — write against them now and the bundle is ready when the feature ships.invalid mission.json: metadata.type
invalid mission.json: metadata.type
type is required and is either lab or static. The v1 values ctf, scenario and boot2root no longer exist.Extra inputs are not permitted
Extra inputs are not permitted
Every block rejects unknown keys. Usually a v1 name —
difficulty is now proficiency, competencies is now skills — or a typo.lab mission requires an 'environment' block
lab mission requires an 'environment' block
Add
environment, or change type to static.static mission requires at least one attachment
static mission requires at least one attachment
A static mission with nothing to analyse is not a mission. Add the file and declare it.
environment.compose_file not found
environment.compose_file not found
The path is relative to the bundle root, and it defaults to
docker-compose.yml.attachment '<name>' file not found
attachment '<name>' file not found
Same —
attachments[].path is relative to the bundle root, not to the manifest’s own directory.checks must ALL declare weight or NONE declare it
checks must ALL declare weight or NONE declare it
Remove every check weight, or give every check one.
check weights must sum to 1.0, got 0.9000
check weights must sum to 1.0, got 0.9000
Declared check weights must total exactly one.
check '<id>' op '<op>': missing args
check '<id>' op '<op>': missing args
Each op takes an exact set of
args. See Checks and ops.mission_id '<id>' is already published in the XORCISE library
mission_id '<id>' is already published in the XORCISE library
Rename your
mission_id. An id belongs to one source, and a local ingest would shadow the library’s.terrain key is never validated — the bundle passes and the map is silently wrong. And an unweighted rubric grades to 0.0 while reporting success.
Iterate on a mission
When ingestion ships, you edit the bundle and ingest it again. The samemission_id from the same source is a version bump with an atomic swap, so a failed re-ingest leaves the working install untouched.
Grading reads the installed manifest, never your bundle directory. Editing a check or a rubric criterion changes nothing until the bundle is ingested again. Existing runs keep the rules they were graded under.
What you just did
- Chose an execution class, which decided everything else — see Missions.
- Wrote an environment and pinned a target, which is what gives an agent somewhere to go.
- Declared artifacts, which is the only channel the agent has for reporting findings — see Connect any agent.
- Wrote one check and two rubric criteria, which are the two halves of every score — see Checks and ops.
- Produced a complete bundle, ready for the day ingestion ships. Until then, install missions from the free library with
xorcise mission pull <id>.
Next steps
How grading works
The arithmetic behind the number your mission just produced.