Skip to main content
ados plugin lint is a local, advisory analyzer. It unpacks a packed archive and checks every entry against a fixed rule set. The registry runs its own, narrower scan at submission, and every submission is reviewed before it is published (see Catalog and registry).

Quickstart

Output:
JSON form for CI:
Exit code 0 means pass. Exit code 1 means at least one finding at severity error or critical. The other exit codes are on the Plugin CLI reference.

What it checks

Findings are keyed by rule id, with a severity and the source location.

Python rules

GCS bundle rules

Manifest and archive rules

info findings are advisory. warn findings show in the report but still pass. error and critical findings fail. Risk ratings come from the capability catalog on Permissions.

Score

Each finding deducts points, with a floor of 0: The score is for your own tracking. The verdict, not the score, sets the exit code.

Network imports and permissions

If your plugin uses requests, httpx, aiohttp, urllib3 or urllib.request, the linter warns unless the manifest declares network.outbound. The host enforces the capability at runtime either way.

False positives

The rules are plain pattern matches. A finding can fire on a comment or a data file. If a finding is wrong for your case, open an issue on the agent repo with the archive and the finding.

Manifest-versus-code check (monorepo)

Inside the ADOSExtensions monorepo, each extension’s GCS package has a lint:manifest script that checks the manifest against the code it describes:
It runs node scripts/lint-manifest.mjs ../manifest.yaml and exits 1 with one FAIL line per disagreement:
  1. A telemetry.subscribe.<topic> permission with no matching ctx.telemetry.subscribe("<topic>") call, or a subscribe call with no matching permission.
  2. A host-surface permission with no call site, on either half. On the agent half this includes every hardware.* permission.
  3. A contributes slot with no implementation.
  4. A version that disagrees across manifest.yaml, the extension package.json, gcs/package.json, the definePlugin({ version }) literal, and the agent half’s pyproject.toml or Cargo.toml.
  5. A permission id that is neither in the capability catalog nor scoped to the plugin as plugin.<leaf>.<...>, where <leaf> is the last segment of the manifest id.
  6. A documentation_url on the docs site whose page does not exist in a sibling Documentation checkout. The check is skipped with a note when no checkout is present; ADOS_DOCS_ROOT overrides the path.
  7. An agent config read of a key that is in neither config-schema.json, a manifest config_key:, nor an agent write of that key.
node scripts/lint-manifest.mjs --self-test runs every case under scripts/lint-fixtures/. The repo’s extensions.yml workflow runs the manifest lint for each extension, together with a manifest schema check against the agent’s schema and the extension’s tests.

Run before every release

Run the same steps in your release workflow before the GitHub Release upload, and let a failing lint block the release.

Next steps

Local install

Pack, sign and install the archive.

Signing keys

Generate and enrol your publisher key.

Permissions

Capability risk levels.
Last modified on October 11, 2026