odu-mcp

SkillAI & models

odu MCP server launcher — drive CI from a coding agent. `bin/serve` resolves odu via Nix and runs `odu mcp` in the cwd. See the repo README for the tools/resources and override knobs.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the odu-mcp skill

What this skill tells your AI

The instructions your AI receives, as published by juspay/kolu in .agents/skills/odu-mcp/SKILL.md and read by ahel’s review.

The agent face of odu — an MCP stdio server that re-exposes a live CI run as agent tools (run, node_rerun, node_cancel, lane_cancel, wait_for_settle, cancel, lease, release) and subscribable resources (surface://streams/nodes, surface://collections/logs/{id}), so Claude Code / Codex / opencode / Gemini CLI drive CI with structured calls instead of scraping terminal output.

lease / release are the agent-held venue layer: hold a free box across discrete tool calls without re-queuing between runs. lease returns immediately (held or waiting); re-call or inventory to observe the line. run reuses held hosts and does not release them on exit.

wait_for_settle defaults to fail-fast: it returns the instant the first node goes red (fail_fast_tripped: true, settled: false), so the agent drills into the failure without blocking on the slow lanes — its failed[] is only what's red so far, and only passed: true (a fully settled run) is a trustworthy green. A verdict about an observed run is stamped with that run's identity — sha7 always, seq whenever the coordinator reserved an ordinal — so it's clear which run it describes (seq is null only when none was reserved: a wait that saw no frame, or the rare case the coordinator couldn't reserve one); and unposted[] carries full owed GitHub status rows ({context, lastError, attempts}) not yet confirmed (reporting debt never blocks settle — the test verdict stays the truth). Called with no run live it fails loud (an error mirroring odu status, not an empty settled: false), and an optional expected_sha (prefix-matched against the run's sha7) refuses loud when the live run's commit doesn't match. A run that is still PROVISIONING — run returns as soon as the coordinator serves its socket, which is now before it claims a machine — is a live run: wait_for_settle blocks on it, the nodes resource shows _ci-setup@<platform> running, and its log resource carries the runner closure's copying path … progress. A claim that never succeeds arrives as a red _ci-setup@<platform> verdict rather than as a run-time error. If the coordinator's socket closes before it publishes a terminal frame, the verdict comes from the run's finalized record on disk — never green for a run torn down mid-flight. The nodes resource carries the same unposted. MCP run tees coordinator stdout/stderr to .ci/<sha7>/runs/<seq>.log.

A settled node's surface://collections/logs/{id} is the last 64KB of its output and now reliably ENDS at the recipe's final line: a run that settles on its own holds its lanes open until every node has finished streaming, because a node's status and its output travel on different streams and the status one arrives first — so the recipe summary the agent came for used to be the part that never made it. Read .ci/<sha7>/<platform>/<node>.log for the whole thing. A lane that stops streaming with output still owed stamps [odu] log truncated: … into the log, so a drill-in never reads a cut log as a complete one.

cancel stops the live run and waits until it's torn down; node_cancel stops one node (ci::fmt@plat) and lane_cancel drops a whole platform while the rest of the run settles (status cancelled, not errored/failed). run's supersede cancels a run already live here before starting (the "stop this, run the fixed commit" move), linger keeps the coordinator serving past settle so a node can be rerun afterwards, and no_wait fails immediately when every host in a venue pool is busy (default: wait in line). Together they let the agent loop call off or replace a run instead of stranding it or hitting "a run is already in progress".

bin/serve is self-contained — it resolves odu via nix run and serves over stdio in the consumer's repo (dialing .ci/odu.sock). Set ODU_FLAKE to override the odu flake-ref (default github:juspay/odu); a repo that re-exports odu can point it at its own pinned output with ODU_FLAKE=.#odu.

Full docs in the repo README.

This skill primitive exists for APM's deployment convention — it lands bin/serve at .agents/skills/odu-mcp/bin/serve in the consumer's working tree (APM's skills-convergence path), which keeps the launcher available even before apm install runs on a fresh clone. The package is mechanically a "skill" in APM's primitive vocabulary; semantically it's a tool launcher.

Signals

GitHub stars
78
Forks
12
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
odu-mcp
Source
github.com/juspay/kolu