// Product

One local process: the fence, the collector, the grader.

xorcise.core stands up the target, records every action your agent takes and scores the sealed record: one inspectable record per run, the trace, the verdict and the report. Not a leaderboard number.

pip install xorcise

// Quickstart

Zero to a graded run.

Register the agent you already run, pull a real target, then launch your agent into the run and grade the full record of what it did. XORCISE never runs the agent for you: run launch-cmd prints the block you paste into your own harness. Python ≥3.12 and Docker.

bash
$ xorcise up$ xorcise agent register --name my-agent --kind claude-code$ xorcise mission pull aviary-access$ xorcise run create --agent my-agent --mission aviary-access$ xorcise run launch-cmd <run-id> # paste into your agent run_a1f2c9d4 · fence up · trace streaming graded 86% (deterministic 100 · judge 72) PASS$ xorcise run report run_a1f2c9d4 --format md

// Where it fits

Fits the stack you already run.

xorcise.core is one local process, with no SaaS and no account. It sits in your inner loop beside your editor and your agent, and drops into CI as an evidence gate. This is the setup we recommend.

Inner loop · your machine
Your editorVS Code · JetBrains · Neovim
Your agent harnessClaude Code · Codex · OpenHands

Iterate on the agent you already build.

xorcise.core
pip install xorciseCLI · REST · collector · fence · grader · one host process

Registers the agent, runs it against a real target, grades the evidence.

Gate · CI/CD
CI pipelineGitHub Actions · GitLab CI

Headless xorcise run create fails the build under threshold; evidence uploads as an artifact.

// The agent

Any OTLP-emitting, tailnet-joining agent.

XORCISE evaluates agents it doesn't build or run, so it depends on just two open standards the harness already speaks: OpenTelemetry to observe what the agent did, and a Headscale/Tailscale tailnet to give it a fenced network to act in.

XORCISE runtime architectureYour Cyber Agent runs in your own sandbox. XORCISE.CORE, which you run, prompts the agent and deploys the Mission target, while your BYO LLM provides grading. The agent's trace streams back to XORCISE and its traffic reaches the target across a network fence.YOUR SANDBOXXORCISE.AITRACEEVALPROMPTTRACE · OTELDEPLOYTARGET TRAFFICNTWK FENCEBYO LLMYOUR MODELCyber AgentYOUR SANDBOXXORCISE.COREYOU RUN ITMissionTHE TARGET
  • from XORCISE (prompt · deploy)
  • live data from agent (trace · attack)
  • your model (trace ↑ / eval ↓)

Telemetry: the embedded OTLP collector

xorcise.core carries its own in-process OTLP receiver: a FastAPI app, ingress-only, no external otelcol. It accepts OTLP/HTTP in JSON or protobuf (gzip-aware), writes the RAW trace verbatim, and seals it at terminal; every other view is a rebuildable projection over that record.

otel/ingest/embedded.py
# the entire ingress surface, bound to XORCISE_OTLP_PORT (4318)POST /v1/traces the traces signalPOST /v1/logs assistant responses · api bodiesGET /healthz # a registered harness stamps this on every batch (full fidelity)OTEL_RESOURCE_ATTRIBUTES=xorcise.run_id=run_a1f2c9d4

Network: the Headscale / Tailscale fence

Headscale is a self-hosted Tailscale control server: it mints a per-run pre-auth key and pushes an ACL, then revokes both at teardown. Agent↔target traffic is peer-to-peer WireGuard and never transits Headscale. The ACL is the hard boundary: isolation is enforced at L3, not by trusting the agent.

runs/join.py · POSIX sh, no root
$ curl -fsS -H "Authorization: Bearer $KEY" $BASE/join.sh | sh tailscale up --accept-routes --accept-dns=false joined run-a1f2c9d4-agent · target reachable by IP

Compatible harnesses

Claude Codeclaude-code
Codex CLIcodex
OpenHandsopenhands
generic floorany OTLP agent

Any harness qualifies by meeting those two hard requirements: emit OpenTelemetry over OTLP/HTTP to the run's :4318 collector, and join the fenced tailnet via the POSIX join script, then speaking run-control: bearer-authed POST /artifacts (the flag is an artifact named flag) and POST /complete. Registered harnesses add first-class run_id correlation and a smart replay adapter; an unknown agent still runs on the generic floor, at lower fidelity.

// Missions

Real, contained targets.

A mission is a self-contained evaluation unit; everything keys off a single authored mission.json. Two axes define the space: how it runs, and where it comes from.

24missions
installed3 / 24
21 available to pull
specialty
forensics4
detection3
web3
+12 more
difficulty
beginner0
intermediate1
hard2
expert21
▢ labinstalled

Inline Sentinel

A smart-city web server is under sustained, multi-vector attack from a fenced adversary.

network defense●●●● expert
suricataiptablesnfqueue+8
▢ labavailable

Aviary Access

You are assessing a bird-themed social-network web application server for access-control flaws.

vuln assessment●●●● expert
apache-httpdhttpcurl+1
▤ staticavailable

Derelict Manifest

You are handed a single offline artifact: no network, no live environment. Recover what it hides.

reverse engineering●●●● expert
pe32x86windows+4

Type: how it runs. A lab is a live, fenced environment: on run-create XORCISE reserves a subnet, fences it with Headscale, deploys the mission's containers and router, and the agent joins the tailnet. A static mission is attachment-only, with no runtime. The agent works purely from the attached files and submits artifacts.

Source: where it comes from. Your Own are bundles you author locally; installing ingests and fuses the environment into a per-mission OCI image. The Library is the remote XORCISE catalog: prebuilt fused images, so installing is a docker pull, and library missions auto-pull on run.

Inside the manifest: metadata (a catalog summary plus the agent-facing objective), environment (lab only), artifacts to submit, and the two graders the author declares: checks (deterministic) and rubric (judge). Those last two are exactly what the grade runs on.

// Grading

Your agent. Your judge.

Every run gets a 50/50 grade over a sealed evidence record: half reproducible machine checks, half a rubric-bound LLM judge running on your own model. It measures how the agent worked; completion is not quality.

The deterministic half is a pure function of the sealed evidence, credited only against XORCISE-owned observed facts, so a forged trace can't inflate it. The judge half is an in-house G-Eval (no DeepEval dependency) scoring the mission's fixed rubric. Both are just injected functions:

eval/judge.py · eval/grade.py
# the judge is a Protocol you inject; grade_judge() never hits the networkclass JudgeModel(Protocol): def score(self, system: str, user: str) -> str: ... # eval/grade.py · the 50/50 combine over one SealedContextoverall = 0.5 * deterministic_sub_score + 0.5 * judge_sub_score

Point it at any OpenAI-compatible endpoint: OpenAI, Azure, vLLM, Ollama. The key persists at 0600 and is never sent to XORCISE.

If the judge has no key, errors, or overruns the model's own context window, its half contributes 0.0 and discloses judge_status. There is no pre-flight token ceiling by default — judge_transcript_max_tokens ships at 0, so the call is attempted and the provider's error is what surfaces, which keeps a failed judge re-gradeable. The deterministic anchor always stands. The exact judge prompt and every per-criterion score and reason are preserved on the result.

bash
$ xorcise config set-model --key sk-… --base-url https://api.openai.com/v1 --name gpt-4o-mini$ xorcise config test judge reachable · gpt-4o-mini · 0.8s

// Results

One inspectable record per run.

The graded result isn't a number; it's an evidence-anchored page. Every panel ties back to what was recorded; nothing about the verdict is hidden.

Scorecard
The overall ring plus the two half-score bars and a checks-passed line. The judge bar mutes when the judge degraded, so you always see the anchor.
Grading detail
Per-check verdicts (source / ref / op / resolved value / pass) and the per-criterion score + reason, alongside the exact preserved judge prompt.
Terrain map
The agent's path projected on the mission's authored graph: how far through the intended route it got, with a short operator note per step.
Conditions
Model, token budget, sandbox, judge status: the run conditions so every result is read in context, plus KPI strip, activity and this agent's cross-run track record.

Export the report as md, html or jsonl, or re-evaluate from the page. Cards the agent submits are labelled agent-claimed; the verdict comes only from the grade.

// Built on

What's inside xorcise.core.

One pip install pulls a dependency-light stack: open standards at the seams, no heavyweight frameworks in the OSS grader.

Python ≥3.12the core language
FastAPIREST + in-process OTLP receiver
OpenTelemetrythe evidence standard
Dockerephemeral mission targets
Tailscale · Headscaleself-hosted mesh control
WireGuardpeer-to-peer data plane
SQLiteRAW trace + logs store
Reactresults & replay UI
Pydantictyped evidence contracts

// The CLI

One entrypoint.

Same install everywhere, and today that install is one machine: xorcise up boots every service together. The agent always runs in your own sandbox, and that never changes.

xorcise --help
$ xorcise --help Usage: xorcise [OPTIONS] COMMAND [ARGS]... XORCISE — evaluate cyber AI agents. Options
--versionShow the xorcise version and exit.--install-completionInstall completion for the current shell.--show-completionShow completion for the current shell, to copy it or customize the installation.--help -hShow this message and exit.
Getting started
upStart XORCISE in the background and print the interface URL.uiPrint the local interface URL (warns when XORCISE is not running).statusCheck whether the local XORCISE services are running (non-zero if anything is down).doctorDiagnose setup problems and say exactly how to fix them (non-zero on failure).downStop XORCISE and clean up (safe to re-run).
Evaluate
leaderboardRank agents by their recorded results.agentRegister and manage the agents you evaluate.missionBrowse, install, and manage missions.runCreate and manage evaluation runs.
Configuration
systemShow detailed information about the running XORCISE instance.configView and set evaluation settings (judge model, terrain model, network).catalogConnect or disconnect the online mission library.
Advanced
serveRun XORCISE in the foreground (advanced; see also: up, which runs it in the background).roleShow or list the service roles serve can boot (advanced, EXPERIMENTAL).dbDatabase maintenance (advanced).

Splitting the stack across machines is experimental. xorcise serve --role boots a named subset of the services, but only the default role — all — is a complete install. The other four start, and the CLI names what each one is missing as it does: multi-machine deployment is unfinished.

Full command reference →

Start evaluating in one command.

pip install xorcise

Prove it on your own agent.

pip install xorcise

Apache-2.0 · Python 3.12+ · runs locally · no phone-home.