Skip to content

Applicability

bob tour grades an item parked when nobody uses it. That conflates a bad item with an inapplicable one: drupal-security goes unused because no Drupal is being shipped, not because it is a poor skill. bob tour --applicability (engine scripts/bobu/applicability.js, #2900, part of Bob University #2898) grades applicability first, so an item that fits no project in the portfolio reads as a portfolio decision, not a quality one.

Terminal window
bob tour --applicability # the human table
bob tour --applicability --json # one bob-applicability/1 document
bob tour --applicability --bucket not-applicable-anywhere # one bucket
bob tour --applicability --no-infer # declared profiles only

It is read-only: nothing is written and there are no network calls. It is deterministic: the document has no timestamps and every list is sorted, so unchanged inputs give byte-identical output.

Bucket Meaning
not-applicable-anywhere The item is scoped, and no active portfolio project matches it. This is the cheapest bucket to clear.
applicable-unused Matches at least one project, and no fleet usage event exists for it.
applicable-used Matches at least one project, and it was used on some project on some fleet machine.
unscoped Not graded. applies_to.stacks includes any (unscoped_reason: any), or the metadata is missing (missing) or implausible (implausible). The last two carry metadata_fix: true.

Items covered: every registry/skills/*/SKILL.md, registry/commands/*.md, registry/agents/*.md and registry/runbooks/*.md, including those with no applies_to at all. An item with no applies_to is a finding, not a skip.

The rule is the orchestrator’s (recommend.js explainInclude), reduced to the two applicability facets. A project matches an item when:

  • one of the item’s applies_to.stacks is in the project’s stack, and
  • the item’s applies_to.project_types include any or the project’s type.

A project whose type is unknown cannot be excluded on type. It matches on stack alone, and the match records type: "unknown". A project with no stack matches no stack-scoped item, because applicability is never claimed without evidence. default, opt_in and recommended_for do not affect applicability. They govern what gets recommended, not what applies, and are reported as-is.

There is one profile per project manifest (provisions/<project>.json), read through the operator resolver. _*.json globals and ports.json are skipped. A project with _meta.active: false is left out and named in excluded.

Field Source, in order
stack _meta.stack when non-empty (declared), else infer-profile.js on the project’s _meta.path when that checkout exists on this machine (inferred), else [] (unknown)
project_type _meta.project_type (declared), else inferred as above, else null (unknown)

--no-infer skips inference. Profiles then come from declarations only, and the result is the same on every machine.

An item with any flag lands in unscoped with metadata_fix: true and is not graded:

Flag When
missing-applies-to No applies_to block.
missing-stacks / missing-project-types The block lacks one of the two lists.
any-with-named-stacks any sits next to named stacks, so the names mean nothing.
any-on-stack-specific:<stacks> stacks: [any], but the item’s name or description names a stack from the registry’s own vocabulary (the stacks scoped items declare, minus generic ones like node, shell, typescript). An agent’s <example> blocks are ignored.
unknown-project-type:<types> A project_types value outside the orchestrator’s set (web-app, api, backend, cms, research, cli, library, mixed, any).

Usage is the fleet-wide join scripts/evidence/fleet-usage.js (#2899), matched by item name. usage_base records what the split rests on: events, machines_reporting, missing (fleet machines with no usable snapshot), and sufficient (true when no machine is missing). While a machine is missing, applicable-unused is not yet proof of non-use. The table says so.

{
"schema": "bob-applicability/1",
"buckets": ["not-applicable-anywhere", "applicable-unused", "applicable-used", "unscoped"],
"counts": { "not-applicable-anywhere": 2, "applicable-unused": 22, "applicable-used": 1, "unscoped": 94, "metadata_fix": 38 },
"usage_base": { "events": 60, "machines_reporting": 1, "missing": ["macbook-air"], "sufficient": false },
"profiles": [{ "project": "example-cms", "stack": ["drupal", "javascript", "php"], "stack_source": "declared", "project_type": null, "project_type_source": "unknown" }],
"excluded": [{ "project": "old", "reason": "inactive (_meta.active: false)" }],
"items": [{
"name": "drupal-security", "type": "skill", "bucket": "applicable-unused",
"applies_to": { "stacks": ["drupal", "php"], "project_types": ["cms", "web-app"] },
"default": false, "opt_in": false, "metadata_fix": false, "flags": [], "unscoped_reason": null,
"projects": [{ "project": "example-cms", "stacks": ["drupal", "php"], "type": "unknown" }],
"usage": { "events": 0, "projects": [], "machines": [] }
}],
"error": null
}

--bucket filters items only. counts always cover every item. On failure, error is {code, message}: usage for a bad flag, input for an unreadable usage or profiles file. An unreadable manifest is not an error: that project is left out and named in excluded.

Code Meaning
0 Graded.
2 Usage error (unknown flag, unknown bucket) or unreadable input.
Variable Effect
BOB_SOURCE The registry to grade.
BOB_OPERATOR The operator repo whose provisions/ are the portfolio.
BOB_APPLICABILITY_USAGE A bob-fleet-usage/1 file read instead of the snapshots (fixtures).
BOB_APPLICABILITY_PROFILES A JSON array of {project, stack, project_type} read instead of the manifests (fixtures).