fairlead 0.14.0

Guardrails and a guided path for coding agents: rules enforced as the agent works, tests scoped to what a change can reach, capped project memory, and KPIs.
fairlead-0.14.0 is not a library.

A fairlead is the fitting on a boat that keeps a line running true, so it doesn't chafe, tangle or pull off course. Fairlead does that for an agent working in your repository. It is one Rust binary with no project-specific logic: everything about your repository lives in your own fairlead.toml.

Why Fairlead

Join a good team and you don't start from zero. Someone tells you which module never to touch without running the migration check first, which test lies on Windows, and which "quick fix" broke production last spring. That knowledge is why a new engineer is useful in week two instead of month six.

A coding agent gets none of it. It opens your repository cold every time, reads the same code again, makes the mistake your team already paid for, and finds out in CI that it was an old lesson nobody told it. Fairlead gives every repository its own memory, so your agent starts where your team left off instead of trying things like a stranger.

  • A memory for every repository. The hard lessons from past work live with the code, per module, where the agent meets them before it acts. A lesson is kept short, reviewed on a date, and turned into a check when it can be, so the memory stays true instead of growing into noise. Since 0.2.0: owner rules record which tests guard which code, and a quarantined test applies only while the evidence holds and until its date. Since 0.7.0: a [[quarantine]] entry records a test that lies on one platform, such as a CRLF checkout or a path with a space. There, the plan lists it as not provable here, and done excuses only the failure it expects.
  • Set up once, never start cold. The agent's first job is to learn the repository: its modules, test runners, rules, and the commands that prove a change is right. That goes into one checked config, so every session starts where the last one left off. Since 0.1.1: fairlead config check validates every layer, and show --origin says where each value came from.
  • The right tool, not the nearest one. The agent asks what applies to the files in front of it and gets the rule, the command and the next step for exactly those files. Since 0.2.0: fairlead plan names the tests and checks a change can reach, and test --explain says why each one is in or out. Since 0.13.0: plan --head REV plans a past commit without checking it out.
  • Plans the change, not just the tests. Before an edit, the agent sees what it's about to touch, everything that depends on it, the rules and lessons recorded there, and what has to pass before it's done. Afterwards, what actually changed is checked against that brief. Since 0.6.0: fairlead brief <paths> answers that before the first edit, fairlead done is the gate a change passes before it's finished, fairlead receipt compares what changed with the brief, and fairlead next names the one step left. Since 0.13.0: a brief says when it carries paths from earlier briefs of the session, and brief --fresh starts the set over.
  • The right skills for the code in front of it. A frontend change shouldn't come with database advice. Fairlead picks the skills that apply to what a change reaches, just as it picks tests, and checks the agent used them. Since 0.8.0: [[skills.routes]] scopes each skill, the brief lists the ones a change reaches, skills sync writes them where each agent loads them, and skills report measures whether the agent used them.
  • Measured, not guessed. Good and bad are numbers: whether the plan would have caught real CI failures, rework, escaped defects, tokens and cost. Since 0.2.0: fairlead replay re-plans real failures from a repository's CI history, and the benchmarks measure that recall every week. Since 0.6.0: ci run --judge names each failing test on the default branch that the merged change's plan left out. Since 0.13.0: when the config being replayed differs from the base branch's, replay run reports the recall of both side by side and names each failure that moved between hit and miss.
  • Fast because it remembers. No rereading the codebase to rediscover what was learned last week. The graph, the plan and the lessons are already there. Since 0.2.0: the import graph is built without installing dependencies and cached between runs.
  • It learns where it's blind. When a change reaches no test, Fairlead says so and points at the rule that's missing, so the team's knowledge grows exactly where it was thin. Since 0.3.0: fairlead plan lists every file no test depends on, and replay suggests the owner rule or check path that would have caught a miss.
  • Stopped before the mistake, not after. Your rules run as the agent works, catching a wrong move in seconds instead of minutes later in CI. Since 0.4.0: [guard.*] rules run in a Claude Code hook before each edit and in a git commit hook, and fairlead guard check runs them on the tree. Since 0.7.0: the same hooks for Codex and Gemini CLI, with fairlead hooks install --codex or --gemini.

Works with

  • Any test runner. Vitest, Jest, Playwright, node --test, Bun, pytest, go test, PHPUnit and Pest: a runner is one command in your config, so Fairlead never needs a plugin for your stack.
  • Monorepos, precisely. pnpm, npm, yarn and bun workspaces. A pnpm lockfile change runs only the packages whose dependencies actually changed. Since 0.8.0: in a bun project, a dependency's version bump runs only the tests of the files that import it, and nothing when nothing does. Since 0.13.0: a plan.run_all entry can name the kinds of change that run everything, so a new migration goes through the graph and an edited one runs everything. Since 0.14.0: a named import from a barrel depends on the file that declares the name, so a change behind a package's index.ts selects only the tests that import what it declares.
  • No install needed to read your code. The import graph comes from source alone, with tsconfig paths, go.mod and composer's autoload resolved and parsed files cached, so a plan takes a fraction of a second.
  • Your CI, not a new one. A GitHub Action and ci plan --format github for Actions, and a JSON plan with a published schema for any other CI.
  • Proven on real projects. Recall is replayed from the CI history of Effect, pnpm and vitest every week, and published.
  • Private by default. The CLI sends nothing you didn't ask for: no telemetry, and it never phones home.
  • One binary, everywhere. Linux (glibc or musl, as on Alpine), macOS and Windows, installed with a shell script, PowerShell or npm.

What it reads, and what replay has proven. A language counts as proven when replaying a public project's CI history judges at least 10 failures, at high recall:

Language Since Replay evidence
JavaScript, TypeScript 0.2.0 Effect, pnpm and vitest, replayed weekly (benchmarks)
Python 0.5.0 poetry: 99.2% of 122 failures
PHP 0.5.0 pterodactyl/panel and invoiceninja: 100% of 27 failures
Go 0.5.0 Reads, not yet proven: opentelemetry-go has too few failures to judge
Vue, Svelte, Astro components 0.5.0 Reads, not yet proven: no replay yet
Java, Kotlin (Maven, Gradle) 0.7.0 Reads, not yet proven: okhttp at 92.6%, most misses look flaky (#184)

An external provider feeds the graph for any other language, and a coverage map adds what imports can't show. Framework packs and folders of several repositories are on the way (#47).

What it does

This README documents Fairlead 0.14.0. Each command, by what it's for:

  • The test plan: plan, test --explain, the import graph (graph) and coverage maps (coverage import). Since 0.13.0: graph hubs lists the files that link the most changes to the most tests and the barrier that would cut the top one, and a changed barrier file selects its importers' tests.
  • Plans in CI: ci plan (by stage, with --since-green), ci run (with --results, --judge, --only and --except), ci report, ci workflow, which writes a staged workflow, and the GitHub Action. Since 0.13.0: ci plan --shards N splits a plan across a matrix of N jobs, balanced by past durations, and ci run --shard K/N runs one job's share.
  • Rules as the agent works: guard check, the hooks hooks install adds, and doctor.
  • The change loop: brief before an edit, or context for the brief with the lessons, skills, README and history to read; done before it's finished, then receipt and next; resume picks up where the last session on a branch stopped.
  • Project memory: learn writes a lesson, import lessons turns a lessons document the team already keeps into one lesson per heading, and lessons lists, reviews and checks them. The brief offers the ones a change reaches.
  • Skills: [[skills.routes]] scopes each SKILL.md, and the brief lists the skills a change reaches. import rules turns path-scoped rule files into skills and routes, and refreshes a skill when its rule changes, and skills sync writes each skill where Claude Code, Codex and Cursor load it.
  • Finding things: find searches lessons, skills, docs headings and declared names, nearest the brief first.
  • Agents over MCP: mcp serves the plan, the brief, the receipt and the other read-only commands as tools.
  • What agents read first: agents sync keeps the loop, the always-on lessons and the skill index in a marked block in AGENTS.md and CLAUDE.md.
  • Measuring: insights, what the event log and CI's reports say about the setup and the config changes they back; tokens, the tokens and cost of each agent session; replay, the benchmarks, skills eval, which scores skill routing on the repository's history, and skills report, the hit rate of what routing offers against what agents load. Since 0.14.0: test bench times bun test serial, --parallel and --parallel --no-isolate on the repository's tests, flags order-dependent ones, and recommends the fastest mode for doctor --score and insights --suggest.
  • Getting started: init writes a first config from what the repository shows, and init --blueprint adds a starting point for a kind of project: config, starter skills and the CI workflow. Since 0.14.0: on Bun 1.4.4 or later, init runs bun test in parallel (--parallel --no-isolate) and offers bun fmt --check on the changed files as a check.
  • The config: config check, show and schema.
  • Upgrading: migrate, which brings the hooks, the config's version floor and the version pins to the release you installed. Since 0.7.0.

The quick start shows the first few, and the book covers each one.

Status

Pre-alpha. The latest release, v0.14.0, measures and uses Bun 1.4.4: init writes the parallel test runner and offers a per-change bun fmt check, and fairlead test bench times Bun's test modes on your own tests and says which to use. A named import through a barrel now depends on the file that declares the name, so a change behind a package's index.ts selects only the tests that use it. Fairlead installs with Composer too, and releases are ready to publish to crates.io and a Homebrew tap. What each earlier release added is in the changelog, and what upgrading to it asks of you is in the upgrade guide. Recall on real CI failures, with every miss and its cause, is in the changelog and on the benchmarks page. Hooks ship for Claude Code, Codex and Gemini CLI. The roadmap has milestones K0 to K6, each an issue with its exit criteria.

Install

# macOS and Linux
curl -fsSL https://github.com/mahkassem/fairlead/releases/latest/download/fairlead-installer.sh | sh

# Windows (PowerShell)
powershell -c "irm https://github.com/mahkassem/fairlead/releases/latest/download/fairlead-installer.ps1 | iex"

# In a JavaScript or TypeScript project, as a dev dependency
bun add -d fairlead   # or: npm i -D fairlead

# In a PHP project, as a dev dependency
composer require --dev mahkassem/fairlead

Since 0.14.0: with Homebrew, brew install mahkassem/tap/fairlead, or from crates.io, cargo install --locked fairlead.

Then fairlead doctor says which binary, platform and config it would use.

Since 0.13.0: static musl builds for x86_64 and aarch64 Linux, which the installers pick on a musl system such as an Alpine container image. On a platform with no build, the npm package still installs, and fairlead says how to build it from source (Install).

Since 0.14.0: the Composer package, for a PHP project without Node. A small PHP launcher downloads the release build for the platform on its first run, checks its sha256 before unpacking it, and caches it in vendor/ (Install).

Quick start

fairlead init                                # a first fairlead.toml, from what the repository shows
fairlead config check                        # validate fairlead.toml
fairlead plan --base main                    # the tests and checks this branch can affect
fairlead test --explain src/a.test.ts        # why that test is in the plan, or isn't
fairlead graph why src/a.test.ts src/util.ts # how one file depends on another
fairlead brief src/util.ts                   # before an edit: what it reaches and what must pass
fairlead done                                # the gate a change passes before it's finished

Documentation

The site is mahkassem.github.io/fairlead, and the book covers install, configuration, the import graph, the test plan, plans in CI, guard rules and hooks, the brief, the done gate, the receipt, replay and the benchmarks. Its source is in docs/.

The README, the site and the book describe the latest release, and each says which one. For an earlier release, read them at its tag, such as v0.5.1. A release can't be cut while any of them lags it: scripts/docs_check.py runs before the release builds.

Brand

The logo, its colors and how to use them are in assets/brand.

License

Licensed under either of

at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.