feat(core): support multi-backend caplet files#177
Conversation
|
Caution Review failedAn error occurred during the review process. Please try again later. 📝 WalkthroughWalkthroughIntroduces multi-backend Caplet Markdown files that declare plural backend maps (e.g., ChangesMulti-Backend Caplet Files Feature
New Official Caplet Definitions
Virtual Catalog Search Lifecycle Fix
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Preview DeployedLanding: https://pr-177.preview.caplets.dev Built from commit 893d2a8 |
|
| Filename | Overview |
|---|---|
| packages/core/src/caplet-files-bundle.ts | Core schema and expansion logic for multi-backend caplet files. Well-structured with cross-family uniqueness validation in superRefine, correct dual-underscore child runtime ID derivation, and idiomatic shared-field inheritance/merging. The implicit MCP fallback in configBackend/addConfig is functionally correct but relies on an undocumented invariant. |
| packages/core/src/cli/install.ts | Adds child-install guidance, risk aggregation across plural backend families, and catalog child population for installed lock entries. Auth scope and runtime-feature deduplication handled correctly with Set. Logic for loading metadata for community-installed suites is functionally sound with a best-effort silent fallback. |
| packages/core/src/catalog/caplet-markdown.ts | Extends catalog helpers to detect plural backend maps. catalogWorkflowSummaryFromFrontmatter correctly gates on catalogHasPluralBackendMap, fixing previously reported mislabeling for community caplets. |
| scripts/generate-catalog-index.ts | Adds groupedCatalogCaplets to collapse child entries into a single parent catalog entry. Grouping key is correct, list is sorted deterministically, and parent metadata is sourced from frontmatter for suite entries. |
| apps/catalog/src/scripts/virtual-results.ts | Adds a destroyed flag guarding virtualizer callbacks after teardown, preventing async DOM mutations after catalog search is closed. |
| Dockerfile | Switches to pnpm deploy output for a portable /deploy directory, bakes telemetry tokens via build args using JSON.stringify, and fixes health check path to /v1/healthz. |
| packages/core/src/caplet-source/parse.ts | Propagates parentId and childId from loaded metadata into ParsedCapletSourceCaplet. Gracefully falls back to caplet.server when metadata is absent. |
| packages/core/src/catalog/types.ts | Adds CatalogEntryChild type and optional children field to CatalogEntryInput and CatalogEntry. Clean additive change. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["CAPLET.md\n(plural backend syntax)"] --> B["capletFileSchema.superRefine\n• cross-family child ID uniqueness\n• singular vs plural mutual exclusion\n• auth scope restriction"]
B --> C["capletToExpandedServerConfigs"]
C --> D["addExpandedChildren per backend family"]
D --> E["splitChildBackendConfig"]
E --> F["mergeSharedCapletFields"]
F --> G["validateExpandedBackendConfig"]
G --> H["normalizeExpandedBackendConfig"]
H --> I["ExpandedCapletFileConfig"]
I --> J["buildCapletFileLoadResultFromEntries\naddConfig(parent__child, config)"]
J --> K["CapletFileLoadResult\n{config, paths, metadata}"]
K --> L1["installCaplets\nrisk aggregation"]
K --> L2["parseCapletSource\nparentId + childId"]
K --> L3["catalogChildrenForInstalledLockEntry"]
L2 --> O["generateOfficialCatalogEntries\ngroupedCatalogCaplets"]
O --> P["CatalogEntry\nworkflow=Capability suite\nchildren=[CatalogEntryChild, ...]"]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["CAPLET.md\n(plural backend syntax)"] --> B["capletFileSchema.superRefine\n• cross-family child ID uniqueness\n• singular vs plural mutual exclusion\n• auth scope restriction"]
B --> C["capletToExpandedServerConfigs"]
C --> D["addExpandedChildren per backend family"]
D --> E["splitChildBackendConfig"]
E --> F["mergeSharedCapletFields"]
F --> G["validateExpandedBackendConfig"]
G --> H["normalizeExpandedBackendConfig"]
H --> I["ExpandedCapletFileConfig"]
I --> J["buildCapletFileLoadResultFromEntries\naddConfig(parent__child, config)"]
J --> K["CapletFileLoadResult\n{config, paths, metadata}"]
K --> L1["installCaplets\nrisk aggregation"]
K --> L2["parseCapletSource\nparentId + childId"]
K --> L3["catalogChildrenForInstalledLockEntry"]
L2 --> O["generateOfficialCatalogEntries\ngroupedCatalogCaplets"]
O --> P["CatalogEntry\nworkflow=Capability suite\nchildren=[CatalogEntryChild, ...]"]
Reviews (4): Last reviewed commit: "fix(core): validate plural child id coll..." | Re-trigger Greptile
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/docs/src/content/docs/reference/caplet-files.mdx`:
- Line 232: The auth field descriptions in the backend config tables are
copy-paste leftovers and still mention the wrong generic endpoint types. Update
the `auth` row text in the affected sections for `openapiEndpoints`,
`googleDiscoveryApis`, `graphqlEndpoints`, and `httpApis` so each uses the
matching backend-specific singular description; keep the change localized to the
table entries in the docs content.
- Around line 375-378: The cliTools docs are missing the plural child-field
table and the reserved actions guidance, which can cause incorrect authoring of
plural backend configs. Update the cliTools section to document the plural shape
as a child-ID map and add a note that actions is reserved as a child ID, not a
valid child identifier. Include the per-child fields (actions, disabled,
projectBinding, runtime) plus the capability metadata fields (name, description,
tags, exposure, shadowing, useWhen, avoidWhen, setup) so readers can distinguish
plural cliTools from the singular form.
In `@packages/core/src/caplet-files-bundle.ts`:
- Around line 1097-1123: Keep expanded-child runtime ID validation inside the
warning-mode boundary in caplet-files-bundle’s expanded-child handling. The
current child loop in the config expansion path validates childRuntimeId before
the try/catch, which can abort best-effort loading for an oversized
parent__child ID instead of warning and skipping just that child. Move the
validateCapletId check for childRuntimeId into the same warning-handled section
as addConfig, matching the singular addConfig path’s warning-mode behavior for
conflicting IDs.
- Around line 755-761: The plural backend map schema in
capletPluralBackendMapSchema enforces non-empty objects at runtime via refine,
but patchCapletJsonSchema is not mirroring that constraint for the plural map
properties. Update the JSON Schema patching logic to add minProperties for
mcpServers, openapiEndpoints, googleDiscoveryApis, graphqlEndpoints, httpApis,
and capletSets so the generated schema matches the runtime validation behavior.
In `@packages/core/src/cli/install.ts`:
- Around line 968-970: The capletAuth helper is picking the first auth block
from capletAuthBlocks(), which can let a top-level or first-child type: "none"
hide a later required OAuth/API-key backend. Update capletAuth to prefer a
required auth block when present and only fall back to none if no required block
exists, using capletAuthBlocks and derivedSafety(auth) as the key call sites to
preserve the intended auth selection.
- Around line 651-653: The guidance message in the install flow only reports
runtime child Caplet IDs and drops any unmatched missing IDs. Update the logic
around the `missingIds` handling in `install.ts` so the returned error message
includes both the `matches` child entries and any truly missing IDs that were
not matched, using the same install guidance path that builds the Caplet install
error. Keep the child-specific text for `match.id -> match.parentId`, but append
the non-child IDs so users see every problematic ID.
In `@packages/core/test/config.test.ts`:
- Around line 3289-3299: findUnionCliActionsSchema currently only looks for
actions under variant.properties.actions, so it misses plural cliTools variants
when cliTools is nested inside anyOf/oneOf. Update the fallback in
findUnionCliActionsSchema to mirror the direct schemaPath handling for cliTools
by checking the plural branch shape (additionalProperties.properties.actions) as
well as the existing singular branch, using the existing schemaPath helper and
the findUnionCliActionsSchema symbol to locate the logic.
In `@scripts/generate-catalog-index.ts`:
- Line 93: The suite tag assignment in generate-catalog-index.ts currently drops
inherited tags when frontmatter.tags is missing. Update the logic around the
tags field in the catalog entry निर्माण so suite entries fall back to the parsed
caplet.config.tags when catalogStringArrayFromFrontmatter(frontmatter.tags) is
undefined or empty, while preserving the existing behavior for non-suite
entries.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 6f8367d4-bb2d-48fa-b07b-05102a639d46
📒 Files selected for processing (36)
.changeset/multi-backend-caplet-files.mdCONCEPTS.mdapps/catalog/src/data/official-catalog.jsonapps/catalog/src/scripts/virtual-results.tsapps/docs/src/content/docs/reference/caplet-files.mdxapps/landing/public/caplet.schema.jsoncaplets/aws/CAPLET.mdcaplets/azure/CAPLET.mdcaplets/cloudflare/CAPLET.mdcaplets/datadog/CAPLET.mdcaplets/google-workspace/CAPLET.mdcaplets/mongodb/CAPLET.mdcaplets/neon/CAPLET.mdcaplets/notion/CAPLET.mdcaplets/pagerduty/CAPLET.mdcaplets/stripe/CAPLET.mdcaplets/supabase/CAPLET.mdcaplets/terraform/CAPLET.mdcaplets/vercel/CAPLET.mddocs/plans/2026-06-29-001-feat-multi-backend-caplet-files-plan.mdpackages/core/src/caplet-files-bundle.tspackages/core/src/caplet-source/parse.tspackages/core/src/catalog/caplet-markdown.tspackages/core/src/catalog/entry.tspackages/core/src/catalog/types.tspackages/core/src/cli/install.tspackages/core/test/caplet-files.test.tspackages/core/test/caplet-source.test.tspackages/core/test/catalog-model.test.tspackages/core/test/catalog-official-index.test.tspackages/core/test/cli.test.tspackages/core/test/config.test.tsschemas/caplet.schema.jsonscripts/generate-catalog-index.tsscripts/generate-docs-reference.tsskills/writing-caplets/SKILL.md
Summary
Caplet files can now represent a full capability suite from one
CAPLET.mdinstead of forcing each backend into a separate catalog entry. Plural backend maps such asmcpServers,googleDiscoveryApis,openapiEndpoints,graphqlEndpoints,httpApis,cliTools, andcapletSetsexpand into typed child Caplets while preserving a grouped parent entry for catalog and install flows.This also turns the public catalog into a broader first-run surface: AWS, Azure, Cloudflare, Datadog, Google Workspace, MongoDB, Neon, Notion, PagerDuty, Stripe, Supabase, Terraform, and Vercel now have starter Caplets, with Google Workspace demonstrating the multi-backend suite shape across Gmail, Drive, Docs, Sheets, Slides, and Tasks.
parent__child, protects direct child installs with parent-install guidance, and keeps backend validation strict.pnpm deployoutput, persists global config under/data/config, and points health checks at/v1/healthz.Validation
pnpm exec vitest run apps/catalog/test/virtual-results.test.tspnpm --filter @caplets/core exec vitest run test/code-mode-session.test.ts test/code-mode-sessions.test.ts test/downstream.test.tsCI=true pnpm --filter @caplets/core exec vitest run test/telemetry-release.test.ts test/serve-options.test.ts test/server-options.test.tsdocker build --build-arg CAPLETS_POSTHOG_TOKEN=phc_docker_test --build-arg CAPLETS_RUNTIME_SENTRY_DSN=https://public@example.ingest.sentry.io/123 --build-arg CAPLETS_SENTRY_RELEASE=caplets-runtime@docker-test --build-arg CAPLETS_SENTRY_ENVIRONMENT=test -t caplets:docker-drift-check .node dist/index.js --version,import('@caplets/core'), runtime env inspection, and live/v1/healthzcheck with persisted/data/config/caplets/config.jsonpnpm verifypnpm verifysuccessfullySummary by CodeRabbit
New Features
Bug Fixes
Tests