Skip to content

feat(registry): migrate registry entries from Markdown to JSON#80

Merged
amondnet merged 17 commits into
mainfrom
amondnet/phantom-station
Apr 14, 2026
Merged

feat(registry): migrate registry entries from Markdown to JSON#80
amondnet merged 17 commits into
mainfrom
amondnet/phantom-station

Conversation

@amondnet

@amondnet amondnet commented Apr 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Convert 50 registry entries from Markdown (YAML frontmatter) to plain JSON files
  • Switch Nuxt Content collection from type: 'page' to type: 'data'
  • Add JSON Schema generation (zod-to-json-schema) for IDE autocomplete
  • Remove dead Vue code (ecosystem, strategies, ContentRenderer)
  • Fix pathstem queries for data collection compatibility

Closes #78

Context

The registry serves as a CLI-routing lookup table only — the markdown body in each entry was never consumed by any client. JSON eliminates YAML indentation pitfalls, enables IDE validation via JSON Schema, and lowers the community contribution barrier.

This is Phase 1 of the Telemetry-Driven Registry initiative.

Test plan

  • bun run --cwd packages/schema test — 53 tests pass
  • bun run --cwd apps/registry build — Cloudflare Pages build succeeds
  • bun run --cwd apps/registry test — unit tests pass
  • E2E: start dev server, verify /api/registry/facebook/react returns correct response
  • E2E: verify /api/registry/npm/react alias lookup works
  • Visual: verify index page renders all 50 entries

Verification Checklist

Automated Tests

  • bun run --cwd apps/registry build succeeds with JSON entries
  • E2E: GET /api/registry/facebook/react returns identical response
  • E2E: GET /api/registry/npm/react alias lookup works
  • E2E: monorepo entry returns 409 on direct path
  • JSON Schema validates all 50 entries without errors
  • Unit: packages/schema tests pass

Acceptance Criteria

  • AC-1: All 50 entries exist as .json with identical data
  • AC-2: Build succeeds
  • AC-3/4: API responses unchanged
  • AC-5: No .md files in content/registry/
  • AC-6: JSON Schema validates all entries
  • AC-7: E2E tests pass

Summary by cubic

Migrates the registry from Markdown to JSON to simplify contributions, enable IDE validation, and prepare for telemetry-driven auto-registration. Also fixes Cloudflare Pages builds by moving wrangler.jsonc to the repo root so the workspace builds in order. Addresses #78.

  • Migration
    • Converted 50 entries to JSON; switched Nuxt Content to type: 'data' with registry/**/*.json
    • Generated JSON Schema from registryEntrySchema via zod-to-json-schema; added a default export condition for CJS/JITI; removed the branch+tag exclusivity rule
    • Cleaned Vue pages; removed ContentRenderer and dead fields; replaced path usage with stem for links and queries
    • Quick start shows first package alias (ecosystem:name) when present; otherwise falls back to entry.repo
    • Normalized aliases/paths: fixed @openai/codex, @nuxt/ui (kept legacy nuxt-ui), restored spring-security with both Maven coordinates; corrected llama_index docs path
    • Moved wrangler.jsonc to repo root and set pages_build_output_dir to apps/registry/dist so Cloudflare Pages runs the root build (turbo build) and emits the @pleaseai/ask-schema dist before the registry app builds

Written for commit 423c222. Summary will update on new commits.

@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Apr 12, 2026
@codecov

codecov Bot commented Apr 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@dosubot dosubot Bot added type/feature New feature type:refactor Code refactoring without behavior change labels Apr 12, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15 issues found across 122 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed. cubic prioritises the most important files to review.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/registry/content/registry/openai/codex.json">

<violation number="1" location="apps/registry/content/registry/openai/codex.json:19">
P1: Use the real npm package name in the alias. `@openai/codex` is the published package, so the current alias breaks npm-based registry lookups for Codex.</violation>
</file>

<file name="packages/schema/registry-entry.schema.json">

<violation number="1" location="packages/schema/registry-entry.schema.json:112">
P2: Disallow `branch` and `tag` together in the GitHub source schema. Without that exclusion, the generated JSON Schema validates entries that `registryEntrySchema` rejects.</violation>
</file>

<file name="scripts/migrate-registry-to-json.test.ts">

<violation number="1" location="scripts/migrate-registry-to-json.test.ts:1">
P2: Place this test in the configured Vitest `test/` tree (or expand the include glob), otherwise it will never run.</violation>
</file>

<file name=".please/docs/ideas/telemetry-driven-registry.md">

<violation number="1" location=".please/docs/ideas/telemetry-driven-registry.md:55">
P2: This overstates version resolution as lockfile-only; GitHub entries in ASK resolve their version from the inline `@ref`, not from project lockfiles.

(Based on your team's feedback about ASK version resolution.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/registry/app/pages/index.vue">

<violation number="1" location="apps/registry/app/pages/index.vue:73">
P2: Render the `ask add` example from a package alias, not from `entry.repo`. Using `owner/repo` here points npm/pypi/etc entries at the GitHub flow instead of the curated ecosystem spec.</violation>
</file>

<file name="apps/registry/content/registry/mastra-ai/mastra.json">

<violation number="1" location="apps/registry/content/registry/mastra-ai/mastra.json:26">
P1: The npm source for `@mastra/core` points to `dist/docs`, but that directory is not present in the published package.</violation>

<violation number="2" location="apps/registry/content/registry/mastra-ai/mastra.json:47">
P1: The npm source for `@mastra/memory` points to `dist/docs`, but that directory is not present in the published package.</violation>
</file>

<file name="apps/registry/content/registry/nuxt/ui.json">

<violation number="1" location="apps/registry/content/registry/nuxt/ui.json:16">
P1: Use the scoped npm package name `@nuxt/ui` here. Alias lookups are exact, so registering this package as `nuxt-ui` makes `/api/registry/npm/%40nuxt%2Fui` miss the Nuxt UI entry.</violation>
</file>

<file name="apps/registry/content/registry/spring-projects/spring-security.json">

<violation number="1" location="apps/registry/content/registry/spring-projects/spring-security.json:20">
P2: Use a real Maven coordinate for this alias. `spring-security` is not a valid Spring Maven package name, so coordinate-based lookups will miss this entry.</violation>
</file>

<file name=".please/docs/tracks/active/telemetry-driven-registry-20260413/spec.md">

<violation number="1" location=".please/docs/tracks/active/telemetry-driven-registry-20260413/spec.md:26">
P3: FR-6 points to a non-existent skill path; use the real `.claude/skills/ask-registry/` location so the migration work updates the correct files.</violation>

<violation number="2" location=".please/docs/tracks/active/telemetry-driven-registry-20260413/spec.md:54">
P2: This assumption is inaccurate: the JSON `data` collection requires different query fields (`stem` in this repo), so saying it behaves identically to `page` will mislead follow-up work.</violation>
</file>

<file name="apps/registry/content/registry/jerryjliu/llama_index.json">

<violation number="1" location="apps/registry/content/registry/jerryjliu/llama_index.json:27">
P1: This GitHub source path does not exist in `jerryjliu/llama_index`, so docs ingestion for this registry entry will fail.</violation>
</file>

<file name="apps/registry/app/pages/registry/[...slug].vue">

<violation number="1" location="apps/registry/app/pages/registry/[...slug].vue:48">
P2: Use a package alias for the Quick Start command instead of the bare repo. Rendering `entry.repo` makes npm-backed entries add a GitHub spec such as `facebook/react`, which bypasses the lockfile-based npm resolution users previously got from `npm:react`.</violation>
</file>

<file name="apps/registry/content/registry/microsoft/agent-framework.json">

<violation number="1" location="apps/registry/content/registry/microsoft/agent-framework.json:14">
P1: Use the real NuGet package ID here; `agent-framework` will not match `Microsoft.Agents.AI` lookups.</violation>
</file>

<file name="apps/registry/content/registry/vercel/ai.json">

<violation number="1" location="apps/registry/content/registry/vercel/ai.json:27">
P1: The npm docs path is wrong for `ai`; the published package ships docs under `docs/`, not `dist/docs`. Pointing at a non-existent directory will break npm-source docs resolution for this entry.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant Dev as Contributor (IDE)
    participant Schema as Schema Package
    participant Files as content/registry/*.json
    participant Nuxt as Nuxt Content (v3)
    participant API as Registry API
    participant Web as Web UI (Nuxt Page)
    participant CLI as CLI Client

    Note over Schema,Files: NEW: Schema Generation & Validation
    Schema->>Schema: zod-to-json-schema
    Schema-->>Files: NEW: Publish registry.schema.json
    Dev->>Files: Create/Update JSON entry
    Files->>Dev: NEW: IDE autocomplete & validation

    Note over Nuxt,Files: CHANGED: Content Collection Model
    Nuxt->>Files: CHANGED: Load collection (type: 'data')
    Note right of Nuxt: Migration from type: 'page' (.md)<br/>to type: 'data' (.json)

    Note over CLI,API: Runtime API Flow (Unchanged Output)
    CLI->>API: GET /api/registry/:owner/:repo
    API->>Nuxt: queryCollection('registry')
    Nuxt-->>API: Return JSON data
    API-->>CLI: 200 OK (Identical Schema)

    Note over Web,Nuxt: CHANGED: Web Navigation & Rendering
    Web->>Nuxt: CHANGED: query by 'stem' (formerly 'path')
    Nuxt-->>Web: Return Data Entry
    Web->>Web: CHANGED: Direct data render (No ContentRenderer)
    Note right of Web: Removed Vue components<br/>for Markdown body rendering
Loading

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/registry/content/registry/openai/codex.json Outdated
Comment thread apps/registry/content/registry/mastra-ai/mastra.json
Comment thread apps/registry/content/registry/mastra-ai/mastra.json
Comment thread apps/registry/content/registry/nuxt/ui.json Outdated
Comment thread apps/registry/content/registry/jerryjliu/llama_index.json Outdated
Comment thread apps/registry/app/pages/index.vue Outdated
Comment thread apps/registry/content/registry/spring-projects/spring-security.json
Comment thread .please/docs/tracks/completed/telemetry-driven-registry-20260413/spec.md Outdated
Comment thread apps/registry/app/pages/registry/[...slug].vue Outdated
Comment thread .please/docs/tracks/completed/telemetry-driven-registry-20260413/spec.md Outdated
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Apr 12, 2026

Copy link
Copy Markdown

Deploying ask-registry with  Cloudflare Pages  Cloudflare Pages

Latest commit: 423c222
Status: ✅  Deploy successful!
Preview URL: https://70a9e733.ask-registry.pages.dev
Branch Preview URL: https://amondnet-phantom-station.ask-registry.pages.dev

View logs

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 4 files (changes from recent commits).

Requires human review: Auto-approval blocked by 15 unresolved issues from previous reviews.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 13 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/registry/content/registry/spring-projects/spring-security.json">

<violation number="1" location="apps/registry/content/registry/spring-projects/spring-security.json:16">
P1: Preserve the existing `spring-security` package identity here and add the Maven coordinate as an extra alias; otherwise this entry changes `package.name` in the API response and breaks existing `/api/registry/maven/spring-security` lookups.</violation>
</file>

<file name="apps/registry/content/registry/nuxt/ui.json">

<violation number="1" location="apps/registry/content/registry/nuxt/ui.json:20">
P2: Keep the legacy `nuxt-ui` alias here. Setting the only alias to the same value as `package.name` removes the old lookup key and can break existing alias-based resolution.</violation>
</file>

<file name="apps/registry/content/registry/vercel/ai.json">

<violation number="1" location="apps/registry/content/registry/vercel/ai.json:27">
P1: Keep the `ai` npm source at `dist/docs`; `docs` does not match this package's documented curated npm docs path and can break npm-based doc resolution.</violation>
</file>

<file name="apps/registry/app/pages/index.vue">

<violation number="1" location="apps/registry/app/pages/index.vue:72">
P2: Don't advertise the first package alias as the entry's install command. For monorepo entries, this silently picks one package (for example `@mastra/core`) even though the card represents the whole repo.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/registry/content/registry/spring-projects/spring-security.json Outdated
Comment thread apps/registry/content/registry/vercel/ai.json
Comment thread apps/registry/content/registry/nuxt/ui.json
Comment thread apps/registry/app/pages/index.vue

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/registry/app/pages/registry/[...slug].vue">

<violation number="1" location="apps/registry/app/pages/registry/[...slug].vue:47">
P2: This guards the curated alias behind `packages.length === 1`, so multi-package entries now fall back to `entry.repo` even when `entry.packages[0].aliases[0]` exists. Render the first alias whenever it exists, and only fall back to `entry.repo` when no alias is available.

(Based on your team's feedback about rendering Quick Start commands from the curated ecosystem alias.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/registry/app/pages/index.vue">

<violation number="1" location="apps/registry/app/pages/index.vue:72">
P2: This `length === 1` guard drops the curated `ecosystem:name` quick-start for any entry with multiple packages. Use the first alias whenever it exists, and fall back to `entry.repo` only when no alias is available.

(Based on your team's feedback about rendering Quick Start commands from the curated ecosystem alias.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/registry/app/pages/registry/[...slug].vue Outdated
Comment thread apps/registry/app/pages/index.vue Outdated
@amondnet amondnet self-assigned this Apr 13, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/registry/app/pages/index.vue">

<violation number="1" location="apps/registry/app/pages/index.vue:72">
P2: Only use the package alias for single-package entries; this now picks the first package alias for multi-package entries and can show the wrong quick-start command.

(Based on your team's feedback about rendering repo for multi-package entries.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread apps/registry/app/pages/index.vue

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/registry/wrangler.jsonc">

<violation number="1" location="apps/registry/wrangler.jsonc:39">
P2: `vars.SKIP_DEPENDENCY_INSTALL` is a runtime Pages Function binding, so it will not skip dependency installation during the Cloudflare Pages build.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread wrangler.jsonc
amondnet added 16 commits April 14, 2026 10:30
Registry JSON migration track: convert registry entries from Markdown
with YAML frontmatter to plain JSON files in Nuxt Content v3.

Includes ideation document, spec, plan, and GitHub Issue #78.
- T002: add zod-to-json-schema dependency and registryEntryJsonSchema export
- add generate script that writes registry-entry.schema.json to package root
- re-export from packages/schema/src/index.ts
- Tests: passed

[/please:implement]
- T001: one-shot script extracts YAML frontmatter from registry .md files and writes .json
- Tests: passed (9/9)

[/please:implement]
Run the migration script to extract YAML frontmatter from each .md file
and write it as a plain .json file, discarding the unused markdown body.
- content.config.ts: type 'page' → 'data', source **/*.md → **/*.json
- Detail page: remove ContentRenderer, dead ecosystem/strategies fields
- Index page: remove dead ecosystem badge
- Both pages: use entry.repo for quick-start command
Data collections in Nuxt Content v3 do not have a `path` field.
Replace all `entry.path` and `.where('path', ...)` with `stem`-based
equivalents. Also fix console.log → consola in generate script.
- Move track active/ → completed/
- Add retrospective to plan.md
- Update CLAUDE.md with Nuxt Content data collection gotchas
- Fix openai/codex.json alias to use @openai/codex (official package name)
- Fix nuxt/ui.json package name and alias to use @nuxt/ui (scoped name)
- Fix jerryjliu/llama_index.json github path from docs/docs to docs
- Fix microsoft/agent-framework.json alias to use Microsoft.Agents.AI (real NuGet ID)
- Fix vercel/ai.json npm source path from dist/docs to docs (ai package ships docs/)
- Fix spring-projects/spring-security.json Maven alias to proper coordinate
- Add not constraint to JSON Schema to disallow branch+tag together in github source
- Expand vitest include glob to pick up scripts/*.test.ts (migration tests were unreachable)
- Fix telemetry-driven-registry.md: clarify GitHub entries use inline @ref for version
- Fix spec.md assumption: data collection uses stem not path
- Fix spec.md FR-6: use correct .claude/skills/ask-registry/ skill path
- Fix index.vue and [...slug].vue: render ask add from package alias not entry.repo
- spring-security: restore package name to spring-security, add both
  maven:spring-security and maven:org.springframework.security:spring-security-core
  aliases to preserve backward-compat lookups while adding proper Maven coordinate
- nuxt/ui: add legacy nuxt-ui alias alongside @nuxt/ui to avoid breaking
  existing /api/registry/npm/nuxt-ui lookups
- index.vue, [...slug].vue: only show ecosystem:name for single-package entries;
  fall back to entry.repo for monorepo entries (multiple packages) to avoid
  misleadingly advertising only the first package as the install command
Remove packages.length === 1 guard so multi-package entries also render
the curated ecosystem:name quick-start command when a first alias exists.
Cloudflare Pages builds use Node.js jiti (CJS require) to load
content.config.ts, which fails when the exports map only has an
"import" condition. Add "default" fallback so both CJS and ESM
consumers can resolve the package.

Also removes stale "not: required [branch, tag]" constraint from
the generated JSON Schema (regenerated from source).
@amondnet
amondnet force-pushed the amondnet/phantom-station branch from 9c4ac59 to 3990a8b Compare April 14, 2026 01:31

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Requires human review: This is a significant data migration and refactor of core registry logic (Markdown to JSON) which requires human verification of data integrity and routing changes.

Cloudflare Pages was running with Root directory = apps/registry, so
`bun run build` invoked Nuxt directly and skipped turbo's workspace
build graph. The schema package (`@pleaseai/ask-schema`) never had its
`dist/` emitted, and Nuxt's content.config.ts failed to resolve it.

Relocate wrangler.jsonc to the repo root and point
`pages_build_output_dir` at `apps/registry/dist` so the Cloudflare
project can set Root directory = repo root. The root build command
(`bun install && bun run build` → `turbo build`) then builds the
schema workspace dep before the registry app.

Adjust `preview:cf` to reference the relocated config file so local
`wrangler pages dev` continues to work from apps/registry.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 2 files (changes from recent commits).

Requires human review: Significant data migration and architectural change in registry storage and querying logic warrants human review to ensure API compatibility.

@amondnet
amondnet merged commit dcb4941 into main Apr 14, 2026
5 checks passed
@amondnet
amondnet deleted the amondnet/phantom-station branch April 14, 2026 04:03
@github-actions github-actions Bot mentioned this pull request Apr 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files. type/feature New feature type:refactor Code refactoring without behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(registry): migrate registry entries from Markdown to JSON

1 participant