▶ flow.transition idle → scope │ ✓ flow.acceptance.passed I-3 trackingIssueExists │ ✗ flow.acceptance.failed I-7 conventional commit format │ ⚠ flow.bypass I-3 — spike, issue not yet filed │ ▶ flow.transition branch → spec │ ✓ flow.acceptance.passed I-4 branchMatchesPrefix │ ▶ flow.tool.invoked Bash │ ✗ flow.guard.block no-edit-on-integration refused git commit on main │ ✓ flow.transition pr → review │ ▶ task.completed #1234 closed via PR #5678▶ flow.transition idle → scope │ ✓ flow.acceptance.passed I-3 trackingIssueExists │ ✗ flow.acceptance.failed I-7 conventional commit format │ ⚠ flow.bypass I-3 — spike, issue not yet filed │ ▶ flow.transition branch → spec │ ✓ flow.acceptance.passed I-4 branchMatchesPrefix │ ▶ flow.tool.invoked Bash │ ✗ flow.guard.block no-edit-on-integration refused git commit on main │ ✓ flow.transition pr → review │ ▶ task.completed #1234 closed via PR #5678
xcoder · v0.1 · operational

the shock collar
for your
coding agent.

Your LLM agent is brilliant and undisciplined. Left alone it commits straight to main, ships without a PR, skips the build. xCoder is the kernel-level zap that won't let it.

Mechanism, not vibes. A declared flow graphintercepts every tool call. Pre/post hooks gate each action. Acceptance fails → state can't advance. Every override is named, scoped, and logged.

v0.1 alpha · 4 policies armedClaude CodeCursorCodexOpenCode
xc i — agent supervisorREC ●

▼ live event stream — what xCoder writes to .xcoder/flow-events.jsonl

// architecture

three layers, one shape.

Each layer is independently mechanical — no LLM in the path of decision-making. They compose so an undisciplined agent stays disciplined by default.

01 / hooks

Kernel-level guardrails.

PreToolUse and Stop hooks intercept actions at the moment they happen — edit on main, commit without typecheck, end session without a PR. Exit code 2 = blocked. The LLM cannot prompt its way around.

  • no-edit-on-integration — refuses edits on main
  • branch-prefix-must-match — refuses non-conventional branches
  • commit-must-reference-issue — refuses commits lacking #N
  • typecheck-must-pass-before-commit — refuses commits failing QA
02 / engine

Deterministic state machine.

@xcoder/flow-engine — a typed FlowState walked through 12 phases. Each phase exit runs an acceptance check the engine evaluates itself in TypeScript. No prompt drift can move state forward without satisfying the gate.

  • FlowEngine.tick() — drives one phase forward, atomically
  • checksForPhase() — pure-function acceptance per gate
  • BypassRecord — every override named, scoped, logged
  • LangGraph compile() — for hosts wanting native checkpointing
03 / autopilot

Continuous autonomous loop.

Set a goal, walk away. xCoder analyzes the repo, builds a roadmap, drives a coding-agent through every phase of every item, runs the merge gate, opens PRs, and texts you on configurable events. Stuck sessions get killed and restarted.

  • 9-phase tick: analyze → plan → branch → implement → verify → merge
  • merge-gate verdict before any merge
  • supervisor protocol: non-blocking questions, budget caps
  • self-benchmark: routes new tasks by success-rate-by-tier

// kernel hooks

four hooks. zero ceremony.

Each one is a self-contained Node script reading JSON on stdin, exiting 0 (allow) or 2 (block). Drop into .claude/settings.json, restart your agent, done.

no-edit-on-integration

PreToolUseI-1I-2

blocks

Edit / Write / MultiEdit / NotebookEdit / git commit / git push on integration branch

bypass paths (named, scoped, logged)

  • XCODER_ALLOW_INTEGRATION_EDIT=1 (one shell invocation)
  • workflow.commitDirectly: true (repo opt-in)

typecheck-must-pass-before-commit

PreToolUseI-6

blocks

git commit when `npx tsc --noEmit` returns non-zero (30s budget)

bypass paths (named, scoped, logged)

  • XCODER_SKIP_QA_GATE=1 (one shell invocation)
  • git commit --no-verify (standard escape hatch)

commit-must-reference-issue

PreToolUseI-8

blocks

git commit -m "msg" without #N · closes #N · fixes #N · resolves #N

bypass paths (named, scoped, logged)

  • XCODER_SKIP_ISSUE_REF=1 (one shell invocation)
  • git commit --no-verify

session-end-pr-backstop

StopI-9

blocks

Notifies (or auto-opens) when agent ends with commits ahead of integration but no PR

bypass paths (named, scoped, logged)

  • XCODER_AUTO_PR=1 (auto-opens via gh pr create)
  • (no-op when PR already exists or gh missing)

▸ install all four

# detects your runtime, writes .claude/settings.json
$ xc hooks deploy

// flow-engine

12 phases. 5 gates. 0 ceremony.

A typed FlowState walked deterministically. Every phase exit runs an acceptance check the engine evaluates itself in TypeScript. No prompt drift can move state forward without satisfying the gate.

▸ canonical phase set

idlescopeissuebranchI-3·I-4specI-5implementtestcommitI-7qaprI-9reviewmerge

highlighted phases run engine acceptance · others are agent-driven (iter loop between implement ↔ test)

▸ tick mode (deterministic)

engine.ts — tick()TS strict
import { FlowEngine } from '@xcoder/flow-engine'const engine = new FlowEngine({  cwd: process.cwd(),  integrationBranch: 'main',})engine.startTask('build-auth')engine.patch({ issueNumber: 42, branch: 'feat/build-auth' })const r = await engine.tick()// {//   advanced: true,//   from: 'branch',//   to: 'spec',//   reason: 'Branch matches prefix "feat/".',// }

▸ outcomes

  • advanced: true

    Acceptance passed. State.phase advances. Event flow.transition emitted.

  • bypass converted

    Acceptance failed but a recorded bypass matches. State advances. Event flow.bypass emitted with reason + source.

  • advanced: false

    Acceptance failed. State stays put. lastError set. Event flow.acceptance.failed emitted.

// the contract

15 invariants. 1 logged event each.

Every overridable check has a named bypass. Every bypass emits a flow.bypass event with source + reason. You can't quietly skip a gate — only loudly skip it.

live coverage
11 / 15
idinvariantmechanismstatus
I-1no edits on integration branchno-edit-on-integration policylive
I-2no commit/push on integration branchno-edit-on-integration policylive
I-3tracking issue exists before BRANCHengine acceptancelive
I-4branch matches branchPrefixengine acceptancelive
I-5spec file exists if specsRequiredengine acceptancelive
I-6build / types pass before COMMITtypecheck-must-pass-before-commit policylive
I-7conventional-commit formatengine acceptancelive
I-8commit message references tracking issuecommit-must-reference-issue policylive
I-9PR opened before "done"engine + Stop hooklive
I-10removals match stated intentmerge-gate analyzerlive
I-11autopilot transitions through engineautopilot adapterpartial
I-12every state-mutating tool call observabletrack-tool-calls + flow.tool.invokedpartial
I-13every bypass is loggedstructural — flow.bypasslive
I-14autopilot questions never block queuesupervisor protocolpost-v1
I-15resource caps are honoredsupervisor protocolpost-v1

Full reference at xagent.wtf/docs/xcoder/invariants — mechanism, strength, bypass, and event schema for every row.

// why this exists

mechanism, not vibes.

Most agent frameworks are prompt frameworks. They tell the LLM what to do and hope. xCoder is structurally different — the rules are in the kernel, not the context window.

before / after
prompts decay
mechanism doesn't

Your "always create a feature branch first" instruction is a whisper that gets drowned out by 80k tokens of immediate task. The no-edit-on-integration policy fires every single time `git commit` is invoked. There is no "I forgot."

before / after
advisory ≠ enforcement
PreToolUse exit 2 is enforcement

An LLM saying "I won't commit to main" is performance. A hook returning exit code 2 is the kernel saying no. The difference is structural — and it's the difference between an agent that occasionally drifts and one that can't.

before / after
silent failures
audit-grade events

Prompts fail silently — the agent thinks it followed the rule but didn't. Mechanism failures emit a typed event (flow.guard.block / flow.acceptance.failed / flow.bypass) you can `jq` and ship to anywhere.

◌ contrast: OpenSpec / GitHub Spec Kit

Strong on artifacts, weak on enforcement. xCoder uses the same artifacts (specs, branches, PRs) but verifies adherence with code, not convention.

◌ contrast: LangGraph / Open SWE

Powerful state machines, but no SWE-specific gates. xCoder is built on top of LangGraph TS — adds the 15-invariant contract that turns a graph into flow discipline.

◌ contrast: bmad-method, agentic prompting

Prompt-only methodologies. They assume the model will hold its own. xCoder assumes it won't and builds the floor.

// access

private alpha. four steps to operational.

xCoder is in private alpha — limited access while we harden the kernel before public release. v1 ships with an npm-published binary; the alpha is invite-only.

  1. 01request access
    # email — short note about your repo + why xCoder
    to:      hello@decoperations.com
    subject: xCoder alpha access

    we're shipping access to a small set of dev teams during alpha. private repo today; npm-published binary lands with v1.

  2. 02install (after access)
    # you'll get a pinned install command + access token
    $ npm i -g @xcoder/xcoder@alpha
    $ which xc
    /Users/.../bin/xc

    xc and xcoder are the same binary. pick whichever fits your typing reflexes.

  3. 03wire hooks into your repo
    cd ~/code/your-project
    xc hooks deploy
    # writes .claude/settings.json with all 4 hooks + boot context

    detects your runtime (Claude Code today; cursor / codex / opencode wrappers in flight) and writes the right config.

  4. 04boot a session
    xc i                          # interactive
    # or
    xc autopilot start --goal "harden flow adherence"

    interactive = you stay in the loop. autopilot = set goal, walk away.

▸ ready to try the alpha?

Drop a short note about your repo and the agent runtime you use. We respond within a business day.

REQUEST ACCESS →

invariants live

11

of 15

hooks shipped

4

kernel-level

runtimes wrapped

5+

claude · cursor · codex · opencode · zed