Skip to content

Remove the AI Docs MCP server's frozen image tools; restore dfc mappings - #4099

Merged
matthewhelmke merged 6 commits into
mainfrom
matthewhelmke/docs-138-remove-image-tools
Sep 30, 2026
Merged

matthewhelmke merged 6 commits into
mainfrom
matthewhelmke/docs-138-remove-image-tools

Conversation

@matthewhelmke

@matthewhelmke matthewhelmke commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

The AI Docs MCP server's image tools served year-old data. ServiceNow's AI tool got back image references that don't exist, such as cgr.dev/chainguard/victoriametrics (ZD 11898), and that still reproduced on the live server today. This PR removes those tools and tells connecting clients to use cg-oci instead, which reads the registry live and was documented in #4053. It also adds find_image_equivalent, which answers "what Chainguard image replaces X?" from the Dockerfile Converter mappings with a reference the reader can actually pull. In a test with a real AI tool, correct answers went from 19 of 24 to 24 of 24. Unpullable cgr.dev/chainguard/... references went from 20 of 24 answers to none.

Changes

Remove the image tools and frozen sources (DOCS-138, DOCS-139, DOCS-140)

  • Removes get_image_docs, list_images, and check_image_freshness, along with the registry client and image parsing behind them. All three depended on an images-private README snapshot that was uploaded by hand on 2025-08-12. The automated export never succeeded.
  • Adds MCP instructions, sent at initialize, that point clients to cg-oci, cg-apk, and cg-versions.
  • Stops compiling image READMEs and courses into the bundle. Courses already contributed no content, because the 2025-08-12 tarball didn't match the compiler's expected layout.
  • Drops the workflow's GCS download step. The only other thing it downloaded, the edu export, was extracted and never read. GCP auth stays for Artifact Registry, Cloud Run, and the bundle upload.
  • Renames generate_image_catalog.py to generate_package_catalog.py and ships its output as package-mappings.json. The build still ships image-catalog.json with the same content, so existing CATALOG_PATH settings keep working.
  • The bundle drops from about 14.9 MB to 4.5 MB.

Compile the dfc mappings into the bundle again (fixes DOCS-174)

  • The compiler reads the committed data/package-mappings.yaml, which the nightly autodocs-platform job copies from dfc. The unmaintained GCS dfc object is no longer used.
  • The section uses the compiler's page signature, so search results link to the Package and image name mappings page. A missing file now prints a warning instead of passing silently.

Search: match "image" in queries to "Container" in titles

  • With the image READMEs gone, "python image" stopped finding "Getting started with the Python Chainguard Container." A title-only synonym brings it back.
  • Known limit: a page whose body contains the literal phrase, such as "nginx image," still collects the existing exact-phrase bonus and can outrank the matching guide.

Add find_image_equivalent, and point clients at the pullable reference form

This came out of review testing and was folded in from #4101. I ran headless Claude Code against a local server, with only the AI Docs tools available, on 24 upstream images whose Chainguard name differs from the upstream one:

Search only With find_image_equivalent
Correct image 19 / 24 24 / 24
Tool calls per question 1 to 4 1
Answers giving cgr.dev/chainguard/<image> 20 0
Answers giving cgr.dev/<your-organization>/<image> 0 24

Each of the five search misses was a confident wrong answer:

  • In two runs, the model skipped the server because the first instructions said it had "no container image data."
  • In two runs, the matching line fell outside the returned snippet.
  • In one run, the model misread a correct snippet and invented details.

All 21 cgr.dev/chainguard/<target> references the model printed are refused to anonymous callers at the token endpoint.

  • find_image_equivalent(image) follows dfc's own matching order, from pkg/dfc/dfc.go:

    1. The reference with and without its tag.
    2. The last path segment alone.
    3. The name with any Docker Hub host removed, with and without library/.
    4. Prefix patterns such as nodejs*.

    It returns the image name, a cgr.dev/<your-organization>/... reference with any tag the mapping pins, the matched key, and a pointer to cg-oci for checking entitlement.

  • generate_package_catalog.py writes dfc's 397 image mappings under a new image_mappings key, so they can't be confused with the old catalog's image list.

  • The server instructions and the bundle's DFC section say the mappings are available, name the tool, and give the reference form cgr.dev/<your-organization>/<image>.

  • The unit-test job installs PyYAML, because the new tests read their ground truth from the YAML file.

Also

  • compile_docs.py gets a formatting-only black commit first; its AST is unchanged. Without it, the pre-commit hook would reformat the whole file inside the real change.
  • quick-start-guide.md gets its existing lint errors fixed. It now passes through the same cleaning step as every page, so its markdownlint directive stays out of the bundle.
  • Fixes the image reference in extract.sh's usage line (cgr.dev/chainguard/ai-docs doesn't exist).

The docs pages follow in #4100, merged right after this one.

Testing

  • pytest scripts/test_mcp_server.py scripts/test_mcp_transport.py scripts/test_compile_docs.py: 45 passed.
    • The new tests check the exact tool set, the instructions, the DFC section against the committed YAML, the synonym, and find_image_equivalent.
    • The image lookup tests take ground truth from data/package-mappings.yaml, parsed separately. They cover all 394 exact mappings, plus tags, digests, Docker Hub hosts, prefix patterns, pinned tags, and registry ports.
    • The synonym, DFC, prefix, Docker Hub, and digest tests each fail when their change is reverted.
  • Compiled a real bundle and catalog locally: 4.47 MB, 626 pages, no image markers, 683 package mappings, and both catalog filenames byte-identical.
  • Ran the server over HTTP against those files:
    • tools/list returns the documentation tools, and initialize carries the instructions. This run predates the find_image_equivalent commit, which the 24-run test and CI's smoke-test and unit-test jobs cover.
    • find_package_equivalent("build-essential") returns build-base.
    • A dfc search returns the new section and its page URL.
    • Calling list_images returns Unknown tool.
  • Built the container with the real artifacts. smoke-test-mcp.sh passes, verify passes, and extract writes both catalog files with valid checksums.

After merge

The scripts/** push trigger redeploys the hosted server. The served download at /downloads/chainguard-complete-docs.md shrinks at the next nightly publish. Until then, the real-bundle tests run against the old committed bundle, which still passes.

Refs DOCS-138, DOCS-139, DOCS-140
Fixes DOCS-174

🤖 Generated with Claude Code


Created in collaboration with Claude Code running Opus 5.5 on 2026-09-30.

matthewhelmke and others added 4 commits September 30, 2026 08:06
The pre-commit black hook reformats any Python file it sees, and this
file predates the hook. Formatting it on its own keeps the next commits'
diffs to the lines that change behavior. The parsed AST is identical
before and after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server's image data came from a README snapshot of images-private
that was uploaded by hand on 2025-08-12 and never refreshed. The
automated export never succeeded, so list_images returned names that
are not real repositories, and get_image_docs returned year-old text.
The cg-oci MCP server now provides live image data, documented in
edu#4053.

- Remove get_image_docs, list_images, and check_image_freshness, plus
  the registry client and image-section parsing behind them.
- Send MCP instructions at initialize that point clients to cg-oci,
  cg-apk, and cg-versions for image and package facts.
- Stop compiling images-private READMEs and courses into the bundle.
  Courses already contributed no content: the 2025-08-12 tarball no
  longer matched the compiler's expected layout.
- Drop the workflow's GCS download step. Its only other download, the
  edu export, was extracted and never read.
- Rename generate_image_catalog.py to generate_package_catalog.py and
  ship its output as package-mappings.json. The build also ships the
  same file as image-catalog.json, so existing CATALOG_PATH settings
  keep working.
- Fix the package catalog's availability check, which looked for the
  removed images key.

The bundle shrinks from about 14.9 MB to 4.5 MB.

Refs DOCS-138, DOCS-139, DOCS-140

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The workflow downloaded gs://academy-all-docs/dfc/docs-export.tar.gz,
but nothing maintains that object, and the compiler found no mappings
file inside it. The bundle silently shipped without its DFC section.

The mappings are already in the repository. The nightly
autodocs-platform workflow copies dfc's builtin-mappings.yaml into
data/package-mappings.yaml, and the package catalog already reads it.
The compiler now reads the same file.

The section uses the compiler's page signature, so the MCP server
indexes it like any other page and links search results to the
Package and image name mappings page. A missing file now prints a
warning instead of passing silently.

test_compile_docs.py compiles a real bundle and checks that the section
matches the committed YAML byte for byte.

Fixes DOCS-174

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
People and AI tools ask about a Python image, but since the Containers
rename (edu#3926) the guides are titled "Getting started with the Python
Chainguard Container". With the image READMEs gone from the bundle,
"python image" no longer found that guide.

A query stem now earns the title weight through a synonym as well, so
"image" also matches "container" in a title. Body matching stays
literal, so the synonym cannot inflate a page's score from its text.

The new test fails with the synonym removed.

Refs DOCS-138

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@matthewhelmke
matthewhelmke requested review from a team as code owners September 30, 2026 13:10
@vercel

vercel Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
chainguard-docs-preview Ready Ready Preview Sep 30, 2026 2:14pm UTC

Request Review

@netlify

netlify Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for ornate-narwhal-088216 ready!

Name Link
🔨 Latest commit 0137e7d
🔍 Latest deploy log https://app.netlify.com/projects/ornate-narwhal-088216/deploys/6abd18ec82af7c0008e9c3dd
😎 Deploy Preview https://deploy-preview-4099--ornate-narwhal-088216.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

…e form

A headless Claude Code test, 24 runs against a local server, found two
problems with the instructions this branch added:

- "It has no container image data" read as "don't ask about images."
  In two runs the model skipped the dfc image mappings the server does
  carry, cited the instructions, and guessed a wrong image name.
- 20 of 24 answers told the reader to pull cgr.dev/chainguard/<image>.
  All 21 targets probed are refused to anonymous callers: most images
  are served only from an entitled organization's own namespace.

The instructions now say the documentation includes the dfc mappings
and where search finds them, reserve "no" for live image data, and give
the reference form cgr.dev/<your-organization>/<image>. The bundle's
DFC section says the same, since search results read that text too.

Tests check the instructions' reference form and that they name the
DFC section by the compiler's own title constant.

Refs DOCS-138

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A headless Claude Code test found that search usually surfaces dfc's
image mappings but hands them off unreliably: the matching line can
fall outside the returned snippet, and in one run the model misread a
correct snippet and invented details. A lookup returns one labeled
answer instead.

find_image_equivalent follows dfc's own matching order (pkg/dfc/dfc.go):
the reference with and without its tag, the last path segment, the
name with any Docker Hub host and library/ removed, then prefix
patterns such as nodejs*. It returns the Chainguard image name and a
pull reference of the form cgr.dev/<your-organization>/<image>, and
never presents the public cgr.dev/chainguard namespace as the place to
pull it.

generate_package_catalog.py now writes dfc's image mappings to
package-mappings.json under image_mappings, a new key, so it cannot be
mistaken for the image list the old catalog carried under images.

Tests take their ground truth from data/package-mappings.yaml, parsed
separately, and cover every exact mapping plus tags, digests, Docker
Hub hosts, prefix patterns, pinned tags, and registry ports. The prefix,
Docker Hub, and digest tests each fail with their rule removed. The
unit-test job now installs PyYAML for them.

Refs DOCS-138

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@matthewhelmke
matthewhelmke merged commit 286d599 into main Sep 30, 2026
24 checks passed
@matthewhelmke
matthewhelmke deleted the matthewhelmke/docs-138-remove-image-tools branch September 30, 2026 14:18
matthewhelmke added a commit that referenced this pull request Sep 30, 2026
…e-tool replacements (#4100)

The AI Docs page now documents the four tools the server keeps. It also
includes a table that sends anyone who relied on the removed image tools
to the live replacements from #4053. Developer Resources, which covered
the same product and had drifted, is merged in.

**Merge after #4099.** This page describes the server as #4099 leaves
it, including the `find_image_equivalent` tool, which was folded into
#4099 from #4101.

## Changes

**`/platform/mcp-servers/ai-docs/`**, retitled "AI Docs: Chainguard
documentation for AI tools"

- Documents five tools, including `find_image_equivalent`.
- A new "Image references" section explains that most Chainguard images
are pulled from `cgr.dev/<your-organization>/<image>`, and that the
public `cgr.dev/chainguard` namespace serves only a free subset.
- A new "Container image data" section has a table mapping each task to
its former AI Docs tool and its replacement:
- `get_image_docs`: the Chainguard Containers Directory, or `get_config`
and `get_apko_config` on `cg-oci`
  - `list_images`: `list_repos` on `cg-oci`
- `check_image_freshness`: `list_tags` and `get_manifest` on `cg-oci`,
or `registry_tags_list` on `cg-api`
- `find_package_equivalent`: unchanged, with `cg-apk` for package
versions
- A dated note records the removal. We can delete the note and the
"Former AI Docs tool" column once migrators have moved on.
- "Image catalog" becomes "Package catalog" and covers
`package-mappings.json` and its earlier name, `image-catalog.json`. The
standalone and Claude Desktop examples use the new name.
- The `check_image_freshness` example becomes a dfc image-mapping
example.
- A new "Use the documentation without a server" section holds the
offline content from Developer Resources: a direct link to the download,
which that page never had, plus container `verify` and `extract`,
`cosign verify`, and how to load the bundle into an AI tool. It notes
that the bundle is larger than most tools can hold in one conversation.
- Adds a troubleshooting entry for an AI tool that can't find image
details.

**`/developer-resources/`**
- Deleted and turned into an alias of the AI Docs page. The page
repeated the AI Docs tool list and Claude Desktop configuration, and its
copies had drifted: it still claimed Alpine support.
- Its roughly 50 example prompts are dropped. The per-tool prompts and
the bundle's own usage guide cover the same ground.
- The sidebar's **AI Docs Bundle** link now points to
`#use-the-documentation-without-a-server`.

**Other pages**
- **MCP servers overview:** no longer says AI Docs searches image
READMEs, and points to `cg-oci` for image data.
- **AI documentation security:** lists the two remaining sources (edu
pages and the dfc mappings), drops the provisional dfc note, and says a
clone is all the compiler needs.
- **Directory name:** the AI Docs page now uses "Chainguard Containers
Directory" instead of "Images Directory."

## Testing

- `hugo --gc --minify` builds clean. `/developer-resources/` redirects
to `/platform/mcp-servers/ai-docs/`.
- Every link and fragment in the article body of the three changed pages
resolves against the build, including the sidebar link.
- The migration table and note render correctly; there's no literal
shortcode text.
- `check-related-pages` found no page that needs this change. The Kiro
and Cursor pages still say "Chainguard Images directory." That belongs
to a sitewide naming sweep, so this PR leaves them alone.

Refs DOCS-138, DOCS-174

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
Created in collaboration with Claude Code running Opus 5.5 on
2026-09-30.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
matthewhelmke added a commit that referenced this pull request Sep 30, 2026
Cleanup after #4099, which made the AI docs bundle compile from this
repository alone. None of these changes alters what the build does.

## Changes

- **Drop the `httpx` pin** from `scripts/mcp-requirements.txt`. The pin
served the registry client that #4099 removed, and nothing imports
`httpx` now. `mcp` 2.2 depends on `httpx2`, a separate package, so the
pin only installed an unused library.
- **Delete `.github/workflows/templates/`.** Its three files were
blueprints for the images-private and courses exports to GCS, which
nothing reads anymore. Actions never ran them.
- **Rewrite `docs/automated-docs-setup.md`.** The guide still described
four sources, those templates, GCS downloads, and a local test that
needed placeholder sibling directories. It now covers the two sources,
the `scripts/` trigger, the package catalog, and a local test that runs
from a plain checkout.

## Deliberately not changed

The edu export's GCS upload and the compile workflow's `compiled/`
upload stay as they are. Neither has a known reader, but nobody can
check the bucket's access logs. DOCS-218, due 2026-10-28, revisits both,
once the 2026-09-30 MCP changes have settled and if ownership or readers
become known.

## Testing

- In a fresh virtual environment built from the new requirements,
`httpx` isn't installed, and `pytest scripts/test_mcp_server.py
scripts/test_mcp_transport.py scripts/test_compile_docs.py` passes (45
tests).
- Ran every command in the rewritten guide as written. The compile logs
`DFC mappings added`, and the catalog builds with 683 package mappings
and 397 image mappings.
- `grep` finds no remaining reference to `.github/workflows/templates/`.

Refs DOCS-138, DOCS-218

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
Created in collaboration with Claude Code running Opus 5.5 on
2026-09-30.

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 0137e7dc Deployed Sep 30, 2026 by vercel[bot]
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.

2 participants