TL;DR: faf-cli's drift check is now a function you import, not a command you scrape. computeDrift() joins the public API next to scoreFafYaml, findFafFile, and generateProjectHtml. faf drift --json is the CLI mirror. Plus faf export --llms for an llms.txt view.

In Plain English

Old state. faf drift printed a table — is your CLAUDE.md ahead of your project.faf? Any other tool that wanted the answer had to run the CLI and parse text.

Fix. The comparison moved into a pure function, computeDrift(fafPath), exported from the package. And faf drift --json for scripts and CI.

New state. An editor extension reads your score, tier, and drift in-process — import { computeDrift } from 'faf-cli'. No subprocess, no text-scraping.

npm install -g faf-cli@7.11.0 faf drift --json

Try it without installing: bunx faf-cli@7.11.0 drift --json (or npx --yes faf-cli@7.11.0). Pin the version in scripts — @latest drifts.

faf-cli is a library now, not only a CLI

faf-cli has quietly exported its engine for a while — scoreFafYaml, findFafFile, generateProjectHtml. The scoring is a Rust → WASM kernel; you compose it, you never reimplement it. 7.11.0 adds drift to that surface.

import { computeDrift, scoreFafYaml, findFafFile } from 'faf-cli'; const report = computeDrift('/path/to/project.faf');

computeDrift(fafPath, dir?) takes an explicit path — it never reads process.cwd(). It compares the modification time of project.faf against the four files your AI actually reads (CLAUDE.md, AGENTS.md, .cursorrules, GEMINI.md) and returns a plain object: per-file status, raw mtimes, deltas, and the counts.

The extension is live

Update — September 8. The reason for the edition name: FAF — Project Context is on the VS Code Marketplace and Open VSX (Cursor / VSCodium / Windsurf). Score, tier, and drift in the status bar and a sidebar; the context card rendered in a webview — all of it computeDrift, scoreFafYaml, and generateProjectHtml called in process, no shell-out.

code --install-extension faf.faf-context

faf drift --json

The same report, on the command line, self-describing:

{ "faf_version": "3.0", "project": "my-app", "source": "/abs/project.faf", "targets": [ { "file": "CLAUDE.md", "status": "newer", "delta_ms": 12043 }, { "file": "AGENTS.md", "status": "in-sync", "delta_ms": 0 } ], "drifted": 1, "in_sync": 1, "missing": 2 }

Raw *_ms numbers — no Date.now() in the payload, so the shape is stable and the consumer formats its own "5d ago". A newer target means someone edited the context file and the .faf hasn't caught up; run faf sync. With no project.faf, --json returns { error, hint } and exits 2 — a --json consumer never has to parse a stderr string. Bare faf drift output is unchanged.

faf export --llms

A new export target: faf export --llms writes llms.txt in the llmstxt.org shape, from the authored six W's in your project.faf. Opt-in, like --grok — not on bare faf export or --all. A view, not a format.

Also in 7.11.0

faf hooks --install and faf diff --install now wire the canonical faf-cli bin, not the faf alias — so the pre-commit hook and the git diff driver can't be shadowed by another faf on your PATH.

Try it

Install (global):

npm install -g faf-cli@7.11.0 # short name, same bits: npm install -g faf@7.11.0

Try (no install):

bunx faf-cli@7.11.0 auto bunx faf-cli@7.11.0 score

More: docs.faf.one/drift · v7.11.0 release · repo.

Technical details

  • Version: 7.11.0 (September 7, 2026)
  • New export: computeDrift + DriftReport / DriftTarget types, from faf-cli
  • CLI: faf drift --json · faf export --llms
  • Packages: dual-published — faf-cli and faf, same version
  • Tests: 1402/1402
  • Score: ✪ Trophy 100%