Standalone source of truth for AI coding tool capability data, plus the monitoring pipeline that keeps it accurate.
Capmon tracks which content types (rules, skills, agents, commands, MCP, hooks) each AI coding tool provider supports natively, watches the providers' upstream documentation for drift, and heals its own data when sources move. Capability dispositions and vocabularies conform to ACIF v0.1; capmon conforms to ACIF, never the reverse.
All capability data lives under docs/ in this repo:
docs/provider-sources/— per-provider source manifests: the upstream documentation URLs monitored for each content type.docs/provider-formats/— per-provider format docs: how each provider represents each content type, with canonical-key mappings.docs/provider-capabilities/— the authoritative capability baseline per provider, plus generated by-content-type views and the compatibility matrix.docs/spec/canonical-keys.yaml— the canonical capability keys, each with aspec_refto its owning ACIF section.
Downstream consumers pull this data; they do not push to it.
fetch → extract → recognize/derive → diff → report / heal
- fetch — pulls ~150 upstream sources (raw GitHub files, HTTP pages, JS-rendered pages via chromedp) into a hash cache.
- extract — per-format extractors (HTML, Markdown, Go, Rust, TypeScript, JSON, JSON Schema, YAML, TOML) turn sources into comparable field sets.
- recognize/derive — per-provider recognizers map extracted fields onto the canonical capability model.
- diff/report — compares against the committed state under
docs/and opens PRs/issues on this repo for drift (the healing layer). - check — content-hash drift detection across all providers
(
capmon check --all).
The CLI runs from the repo root (the --formats-dir/--sources-dir/
--canonical-keys defaults assume the working directory is the repo root):
go build -o capmon ./cmd/capmon
./capmon run # full pipeline
./capmon run --stage fetch-extract
./capmon run --stage report
./capmon check --all
./capmon verify # validate provider-capabilities YAML
./capmon generate # regenerate by-content-type viewscmd/provider-monitor is the sister tool that watches provider source URLs
for rename/deprecation/URL drift; it finds docs/provider-sources/ from the
working directory, or point it elsewhere with CAPMON_ROOT or --dir.
The /v1/ contract tree is published to GitHub Pages at
https://openscribbler.github.io/capmon/. It is a live view of current
data, not an archive — the URL major (/v1/) versions the contract
(document shapes, paths, field semantics), never the data.
GET /index.json(unversioned root) → readlatestand themajorsarray; follow the live major'sindex(v1/index.json).GET /v1/index.json→ comparedata_revisionagainst your last-known value. It is a hash over provider data only and changes only when data changes, so "did anything change?" is one field compare. If unchanged, you already have the current data.- On a change, use the per-file
sha256values underproviders[]andfiles{}to fetch only the documents that changed. - Fetch each
capabilities/<slug>.json(and any pivots you need).
The sha256 values in index.json are change and corruption detection,
not authenticity: they share an origin and a fate with the files they
hash. Authenticity comes from build-provenance attestation bound to the
publishing workflow's identity.
Integrity-sensitive consumers — anything that acts automatically on the
data — MUST verify the attestation over v1/index.json, then each
file's sha256 against it, and MUST fail closed: any mismatch aborts
the fetch and triggers nothing downstream.
gh attestation verify v1-index.json --repo OpenScribbler/capmonv1/index.jsoncarriesgenerated_at,cadence: "daily", andmax_staleness_hours. Ifgenerated_atis older thanmax_staleness_hours, treat the feed as stale and keep your last-known-good copy. The feed is best-effort with no SLA.- Poll at most daily, and use HTTP conditional GET (
If-None-Match/If-Modified-Since— Pages serves ETags and returns304). - Deploys are not atomic at the CDN edge. On an
index.json-vs-file hash mismatch, re-fetch after the propagation window (minutes) before treating it as an integrity failure.
supportedabsent means unknown — never treat it as false."supported": trueis verified/inferred support (seeconfidence);"supported": falseis affirmatively not supported.- Treat every enum-valued field (
confidence,status,conversion, …) as open: an unrecognized value is "unknown/other", never an error. - Ignore unknown fields, unknown canonical keys, and unknown files — producers may add any of these within a major.
Field and canonical-key semantics are specified in
v1/spec/field-semantics.md; the JSON Schemas live under v1/schemas/.
.github/workflows/pipeline.yml runs the full pipeline daily against the
data in this repo. Heal PRs and drift issues are opened here using the
workflow's own GITHUB_TOKEN. A scheduled keepalive re-enables the workflow
through the Actions API so GitHub's 60-day-inactivity rule never disables the
schedule — no scheduled job holds contents write on main (ADR 0005).
.github/workflows/publish.yml exports the /v1/ tree, attests it, and
deploys it to GitHub Pages on any push to main under docs/. A daily cron
re-runs the fail-closed gate and always deploys, so the re-stamped
generated_at keeps the published index a truthful liveness heartbeat
(ADR 0012); data_revision remains the change-detection signal.
.github/workflows/ci.yml builds, vets, and tests on every push and PR.
Drift-guard tests compare the recognizers and format docs against the data
under docs/ in the same checkout.
Apache-2.0.