Skip to content

feat(cli): add inventory subcommand to enumerate KB-known AI artifacts#51

Merged
jonathansantilli merged 1 commit intomainfrom
feat/inventory-command
Apr 21, 2026
Merged

feat(cli): add inventory subcommand to enumerate KB-known AI artifacts#51
jonathansantilli merged 1 commit intomainfrom
feat/inventory-command

Conversation

@jonathansantilli
Copy link
Copy Markdown
Owner

Summary

New codegate-ai inventory subcommand that walks every tool entry in the knowledge base, resolves config_paths and skill_paths against \$HOME / workspace root(s), and emits the result as either a human table or machine-readable JSON.

Why

Downstream tooling (IDE extensions, CI agents, dashboards) has been maintaining its own hard-coded lists of "places to look for AI skills / configs" because the KB wasn't queryable. Every time the KB adds a new tool or a new path (like this week's Anthropic Skills entry in #49), those downstream lists silently go stale.

This exposes the KB as structured data so every consumer can read it instead of duplicating it.

Usage

```
codegate inventory [options]

--scope <user|project|all> scope filter (default: all)
--kind <skills|configs|all> artifact kind filter (default: all)
--only-existing filter to paths that exist on disk
--workspace project-scope root (repeatable; defaults to cwd)
--format <text|json> output format (default: text)
```

Example output (JSON)

```json
{
"kb_version": "1.0.0",
"tools": [{ "name": "claude-code", "version_range": ">=1.0.0" }, …],
"items": [
{
"tool": "claude-code",
"kind": "skill",
"type": "anthropic_skill",
"scope": "user",
"pattern": ".claude/skills/*/SKILL.md",
"path": "/Users/alice/.claude/skills/foo/SKILL.md",
"exists": true,
"risk_surface": ["prompt_injection", "unicode_backdoor", "command_exec", "mcp_config"],
"resolved_against": "/Users/alice"
},

]
}
```

Consumer use cases

Consumer Filter
IDE extension listing installed skills `--kind skills --scope user --only-existing --format json`
Dashboard "host inventory" view full dump, render table
Compliance/auditor `--scope all` dump documenting what CodeGate watches
"Does this file fall under any KB entry?" tooling match `path` against results
Plugin/SDK authors read `tools[]` to discover supported ecosystems

Implementation notes

  • Reuses `loadKnowledgeBase()` from `layer1-discovery/knowledge-base`; no duplicate KB parsing.
  • Wildcard expansion (`*`, `**`, `?`) is inlined in the command file rather than reaching into `scan.ts`'s private helpers — keeps the command self-contained and avoids widening the scanner's export surface.
  • Refuses to follow symlinks during wildcard expansion (parity with the existing scanner).
  • Deterministic ordering (tool → kind → scope → path) so output is stable across runs.
  • Depth- and count-limited walks (`MAX_WILDCARD_DEPTH = 8`, `MAX_WILDCARD_MATCHES = 2000`) to keep it bounded on large homedirs.

Tests

  • `tests/commands/inventory-command.test.ts` — 8 unit tests covering filters, scope resolution, `--only-existing`, wildcard expansion against a seeded temp `$HOME`, empty-workspace edge case, ordering.
  • `tests/cli/inventory-command.test.ts` — 3 integration tests via `createCli()` + `parseAsync()`: JSON output, `--only-existing --kind skills` end-to-end, text-format rendering.

Test plan

  • `npm run typecheck`
  • `npm test` — 694/694 passing (11 new)
  • `npm run lint`
  • `npx prettier --check` on touched files
  • `npm run build` + manual smoke: `node dist/cli.js inventory --format json --scope user --kind skills` returns structured output
  • `node dist/cli.js inventory --help` renders correctly

Follow-up (separate PRs)

  • Mobb's tracer_ext VS Code extension will switch from a hard-coded `SKILL_ROOTS` constant to calling this subcommand.
  • The mobbdev CLI's new `scan-my-skills` wrapper will do the same.
  • Mintlify docs page.

`codegate inventory` walks every tool entry in the knowledge base, resolves
each `config_paths` and `skill_paths` pattern against `$HOME` (user scope)
or the workspace root(s) (project scope), and emits the result as either a
human table or machine-readable JSON.

Motivation: downstream tooling (IDE extensions, CI agents, dashboards) was
maintaining its own hard-coded lists of "places to look for AI skills"
because the KB wasn't queryable. Exposing it as a first-class subcommand
makes that parallel list unnecessary and keeps every consumer in sync when
the KB adds a new tool or layout.

### Usage

```
codegate inventory [options]

  --scope <user|project|all>     scope filter (default: all)
  --kind <skills|configs|all>    artifact kind filter (default: all)
  --only-existing                filter to paths that exist on disk
  --workspace <path>             project-scope root (repeatable; defaults to cwd)
  --format <text|json>           output format (default: text)
```

Example consumer call:

```
codegate inventory --kind skills --scope user --only-existing --format json
```

Returns one entry per resolved skill file across every KB-registered tool
(`.claude/skills/*/SKILL.md`, `.codex/skills/**/*.md`, `.opencode/skills/`,
`.cline/skills/`, `.gemini/skills/`, `.roo/skills/`, etc.), with `tool`,
`type`, `scope`, `path`, `exists`, and `risk_surface` on each item.

### JSON output shape

```json
{
  "kb_version": "1.0.0",
  "tools": [{"name": "claude-code", "version_range": ">=1.0.0"}, ...],
  "items": [
    {
      "tool": "claude-code",
      "kind": "skill",
      "type": "anthropic_skill",
      "scope": "user",
      "pattern": ".claude/skills/*/SKILL.md",
      "path": "/Users/alice/.claude/skills/foo/SKILL.md",
      "exists": true,
      "risk_surface": ["prompt_injection", "unicode_backdoor",
                       "command_exec", "mcp_config"],
      "resolved_against": "/Users/alice"
    },
    ...
  ]
}
```

### Implementation notes

- Reuses `loadKnowledgeBase()` from `layer1-discovery/knowledge-base`; no
  duplication of KB parsing.
- Wildcard expansion (`*`, `**`, `?`) implemented inline in the command
  file rather than reaching into `scan.ts`'s private helpers — keeps the
  command self-contained and avoids widening `scan.ts`'s export surface.
- Refuses to follow symlinks during wildcard expansion (parity with the
  existing scanner).
- Deterministic ordering (tool → kind → scope → path) so output is stable
  across runs on the same machine.
- Depth- and count-limited walks (`MAX_WILDCARD_DEPTH = 8`,
  `MAX_WILDCARD_MATCHES = 2000`) to keep it bounded on large homedirs.

### Tests

- `tests/commands/inventory-command.test.ts` — 8 unit tests covering
  filters, scope resolution, `--only-existing`, wildcard expansion against
  a seeded temp `$HOME`, empty-workspace edge case, ordering.
- `tests/cli/inventory-command.test.ts` — 3 integration tests via
  `createCli()` + `parseAsync()`: JSON output, `--only-existing --kind
  skills` end-to-end, text-format rendering.

Full test suite: 694/694 pass; typecheck clean; prettier applied.
@jonathansantilli jonathansantilli merged commit 620b112 into main Apr 21, 2026
16 checks passed
@jonathansantilli jonathansantilli deleted the feat/inventory-command branch April 21, 2026 14:42
github-actions Bot pushed a commit that referenced this pull request Apr 21, 2026
# [0.14.0](v0.13.0...v0.14.0) (2026-04-21)

### Features

* **cli:** add `inventory` subcommand to enumerate KB-known AI artifacts ([#51](#51)) ([620b112](620b112))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant