Integrations · GitHub Actions

Fail the build when your agent's tool calls drift.

Record a skill once with any capture agent, commit the SKILL.md, and replay it in CI. A recorded step whose assertion no longer holds turns the check red — a regression gate for agent tool calls, at 0 tokens.

How capture works on GitHub Actions

This page is different from the others: GitHub Actions is a place to RUN a recorded skill, not a place Reelier captures from. reelier scan has no CI transcript directory to read — nothing here is recorded. You record the skill locally on one of the capture agents, commit the .skill.md file, and this is where you replay it as a gate.

Record first on the agent you actually work in — freeze a Claude Code session from ~/.claude/projects (see /for/claude-code), or wrap an MCP server with reelier mcp --wrap on Cursor, Codex or Windsurf — then commit the compiled SKILL.md to the repo you want to guard.

In CI, the seldonframe/reelier@v1 action runs reelier run <skill>: it re-executes the recorded MCP and tool-call steps, checks each recorded assertion, and exits non-zero when one fails. Drift surfaces as a failed assertion, which fails the job — regression testing for agent tool calls without a model in the loop.

Wire it up

.github/workflows/reelier.yml — replay a recorded skill as a gate
name: Reelier replay
on:
  pull_request:
    paths: ["my-job.skill.md"]   # gate only when the skill changes
  schedule:
    - cron: "0 8 * * *"          # daily, UTC — a standing dated proof
jobs:
  replay:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: seldonframe/reelier@v1
        with:
          skill: my-job.skill.md
          max-level: "0"          # 0 LLM tokens — pure deterministic replay
          cloud-key: ${{ secrets.REELIER_CLOUD_KEY }}  # optional receipt push

The action is a composite step published at seldonframe/reelier, tag @v1. It installs reelier@^0.12, runs reelier run my-job.skill.md --max-level 0, writes the receipt as the job summary, and fails the check on the run's exit code. On pull_request a drifted step blocks the merge; the schedule trigger turns a public repo's green check into a live, dated proof that the replay still passes.

action inputs — with: keys
with:
  skill: my-job.skill.md          # required — path to one .skill.md (one per step)
  max-level: "0"                  # default "0": never calls a model, 0 tokens
  cloud-url: https://www.reelier.com   # default; receipt-ledger base URL
  cloud-key: ${{ secrets.REELIER_CLOUD_KEY }}  # optional — push receipt on pass
  vars: |                         # optional — forwarded as --var name=value
    projectId=497925

skill is the only required input. max-level "1" or "2" enables opt-in self-healing and then needs BYOK LLM credentials in the runner — the action does not set those for you. cloud-key only pushes the receipt after a passing run; unset means a local-only replay that still writes the job summary.

action outputs — steps.<id>.outputs
# outputs you can read from a later step:
passed:           # "true" or "false" — the run record's own passed field
run-record-path:  # path to .reelier/runs/<skill>.jsonl written by this run

Wire passed into a downstream step (comment on the PR, open an issue) — but you don't need to check it to gate: the action already fails the job from reelier run's exit code, so a red check means the replay genuinely drifted.

First receipt in 60 seconds

  1. Record locally first — freeze a real run into my-job.skill.md on a capture agent (record on /for/claude-code, or wrap an MCP server on Cursor/Codex/Windsurf). CI never records; it only replays.reelier from-session <transcript.jsonl> --name my-job
  2. Commit the SKILL.md into the repo you want to guard — it's a plain markdown file with a per-step assertion, versioned alongside your code.git add my-job.skill.md && git commit
  3. Add the .github/workflows/reelier.yml above (the seldonframe/reelier@v1 action) with skill: my-job.skill.md and max-level: "0".
  4. Open a PR. The action replays the skill; a recorded tool call whose assertion no longer holds fails reelier run, and the check turns red before the change can merge.

For a run-to-run comparison instead of a single-run gate, reelier diff <skill> reports SAME or DRIFTED between the last two runs and exits 1 on drift — see /learn/tool-call-drift.

A real receipt

Verbatim output of a portfolio replay, run on 2026-07-21 with the CLI pinned to the version that recorded the seed (npx -y reelier@0.12.1, so it reproduces verbatim). The run record confirms passed: true and 0 LLM tokens. Nothing platform-specific about it — the same skill file replays from any shell, including yours:

Reelier · replay receipt
=== registry-latest ===
✓ Step 1 — Latest dist-tag from the registry [passed] 152ms

PASSED: 1/1 steps ok, 0 failed, 152ms total
seed receipt · examples/portfolio · reelier@0.12.1 · 2026-07-21

Replay it yourself: npx -y reelier@0.12.1 run examples/portfolio/registry-latest.skill.md (from a checkout of the repo — read-only, no account, no key).

FAQ

Does the CI replay cost tokens?

Not at max-level: "0", the action's default — reelier run never constructs or calls a model at level 0, so the replay of MCP and tool-call steps is 0 LLM tokens. Levels 1 and 2 add opt-in self-healing and then require BYOK LLM credentials in the runner.

What does the check actually gate on?

On the recorded assertions. reelier run re-executes each recorded tool call and checks its assertion; if a step that had a clean recorded result now returns something different, that assertion fails, reelier run exits non-zero, and the action fails the job. Steps recorded without a clean result stay unchecked rather than being force-asserted — the gate fires on real drift, not on noise.

Regression testing for AI agents

Is the replay read-only in CI?

Yes — replays are read-only by default. Idempotent write steps only re-fire with --allow-writes, and destructive steps need --yes; the action passes neither, so a scheduled or PR replay reads and asserts without mutating anything. That's what makes it safe to run on every push.

Which steps replay in CI, and which don't?

Reelier deterministically replays MCP tool calls and its own http.get/http.post builtins. Bash, Read, Edit, Write, Grep and other non-deterministic steps are not replayed and stay unchecked — a session that was mostly file edits has little to gate here. Record the jobs that were sequences of API/MCP calls: data pulls, status checks, report generation, CRUD sequences.

Agent drift and tool-call drift, defined

Why would an agent's tool calls drift between commits?

An upstream API changes a field, a model upgrade shifts how the agent shapes a call, a dependency bump alters a response. A recorded skill replayed in CI catches that the moment it lands — the same regression a model upgrade can introduce silently.

When a model upgrade quietly breaks a working agent

Reading as an agent? This page has a markdown twin: /for/github-actions/md