Skip to content

Hide packages from search by default - #746

Merged
kentcdodds merged 2 commits into
mainfrom
hidden-packages
Jul 13, 2026
Merged

kentcdodds merged 2 commits into
mainfrom
hidden-packages

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add a user-scoped hidden property and package_set_hidden management capability
  • exclude hidden packages and search-scope retrievers by default, with explicit public/meta search opt-ins
  • preserve package runtime, context retrievers, direct lookup, list/get, and re-save behavior
  • document the visibility contract and cover migration, ownership, search, retriever, and projection behavior

Test plan

  • npm run test (843 tests passed)
  • npm run typecheck
  • staged-file oxfmt --check
  • initial full validation: lint, E2E, and MCP lanes passed
  • CI npm run validate (local all-files format scan also sees unrelated untracked orchestration config)
System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ 18f67ce3 · Head: c026c366

Classification: extends — this PR changes saved-package storage and ranked-search contracts without adding a new system primitive.

Primitives touched

Primitive Group Impact
mcp-server surfaces extends — search opt-in flags and package visibility capability
capability-registry assistant extends — registers package_set_hidden and returns visibility state
saved-packages assistant extends — user-scoped hidden property preserved across saves
d1-app-db storage extends — additive saved_packages.hidden column
vectorize-search storage extends — ranked candidates exclude hidden package rows by default

System map

Package visibility flows from MCP search and management capabilities through saved-package metadata into D1-backed, user-scoped ranked search.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	mcpServer["mcp-server<br/>MCP endpoint (/mcp)"]:::extended
	capabilityRegistry["capability-registry<br/>Capability registry"]:::extended
	savedPackages["saved-packages<br/>Saved packages"]:::extended
	d1AppDb["d1-app-db<br/>D1 app database"]:::extended
	vectorizeSearch["vectorize-search<br/>Vectorize search"]:::extended
	mcpServer -->|"includeHiddenPackages / include_hidden"| capabilityRegistry
	capabilityRegistry -->|"package_set_hidden + list/get state"| savedPackages
	savedPackages -->|"hidden column, WHERE id + user_id"| d1AppDb
	savedPackages -->|"visible rows become ranked candidates"| vectorizeSearch
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Before / after

Before: every saved package participates in ranked search.
After:  hidden packages stay usable and manageable but require an explicit search opt-in.

Invariants

  • per-user-isolation: visibility reads and writes remain scoped by userId; search continues filtering package state by the authenticated user.
  • compact-mcp-surface: management is a domain capability behind search/execute, not a new top-level MCP tool.

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Added a way to hide or unhide saved packages.
    • Hidden packages are excluded from ranked search by default, but remain accessible via direct known-id lookup and package listing.
    • Added includeHiddenPackages support to search (including meta search), and exposed hidden status in returned package details.
  • Documentation
    • Updated package, search, and data-storage docs to describe hidden behavior and visibility exceptions.
  • Database / MCP
    • Added a user-scoped hidden flag to saved packages and a capability to set it.
  • Tests
    • Updated/added coverage for hidden flag behavior in search, formatting, and capability flows.

Add a user-scoped visibility control so saved packages can be removed from discovery without disabling their runtime or management surfaces.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Saved package hiding

Layer / File(s) Summary
Persist hidden state and preserve it
packages/worker/migrations/*, packages/worker/src/package-registry/*, related test schemas and fixtures
Adds the saved_packages.hidden column, repository persistence and mapping, projection preservation, and migration coverage.
Expose package hiding and summaries
packages/worker/src/mcp/capabilities/packages/*
Adds package_set_hidden, registers it in the packages domain, initializes new records as visible, and returns hidden in package summaries and details.
Filter hidden packages during search
packages/worker/src/mcp/tools/search.ts, packages/worker/src/package-retrievers/service.ts, packages/worker/src/mcp/capabilities/meta/search.ts, search tests
Adds includeHiddenPackages, filters hidden packages in search scope, and leaves context-scope retrievers enabled.
Propagate hidden status in formatted output
packages/worker/src/mcp/tools/search-format.ts, related tests
Adds hidden to package search contracts and structured and markdown formatter output.
Document hidden-package semantics
docs/contributing/*, docs/use/*
Documents hiding, search inclusion flags, known-id access, and the package hiding capability.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant setPackageHiddenCapability
  participant updateSavedPackage
  participant APP_DB
  Caller->>setPackageHiddenCapability: package_id, hidden
  setPackageHiddenCapability->>updateSavedPackage: update for authenticated user
  updateSavedPackage->>APP_DB: write hidden state
  APP_DB-->>updateSavedPackage: changed row count
  updateSavedPackage-->>setPackageHiddenCapability: update result
  setPackageHiddenCapability-->>Caller: ok, package_id, hidden
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main behavior change: hidden packages are excluded from search by default.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hidden-packages

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-746.kody-a99.workers.dev

Worker: kody-pr-746
D1: kody-pr-746-db
KV: kody-pr-746-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
packages/worker/src/package-registry/repo.ts (1)

145-146: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Column list duplicated across five queries.

Each of getSavedPackageById, getSavedPackageByKodyId, getSavedPackageByName, listSavedPackagesByUserId, and listSavedPackagesPage repeats the identical SELECT id, user_id, name, ..., hidden, created_at, updated_at column list. Extracting a shared constant reduces the risk of a future column addition/rename being missed in one of the five call sites.

♻️ Suggested refactor
+const SAVED_PACKAGE_COLUMNS = `id, user_id, name, kody_id, description, tags_json, search_text,
+				source_id, has_app, hidden, created_at, updated_at`
+
 export async function getSavedPackageById(...) {
 	const row = await db
 		.prepare(
-			`SELECT id, user_id, name, kody_id, description, tags_json, search_text,
-				source_id, has_app, hidden, created_at, updated_at
+			`SELECT ${SAVED_PACKAGE_COLUMNS}
 			FROM saved_packages
 			WHERE id = ? AND user_id = ?`,
 		)

Apply similarly to the other four queries.

Also applies to: 164-165, 183-184, 201-202, 224-225

🤖 Prompt for 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.

In `@packages/worker/src/package-registry/repo.ts` around lines 145 - 146, Extract
the duplicated package column projection into one shared constant in repo.ts,
then reuse it in getSavedPackageById, getSavedPackageByKodyId,
getSavedPackageByName, listSavedPackagesByUserId, and listSavedPackagesPage.
Preserve the existing column order and query behavior while replacing each
repeated SELECT list.
packages/worker/src/mcp/capabilities/meta/search-include-hidden.node.test.ts (1)

89-121: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Split into two separate test() cases.

Both the default (includeHiddenPackages: false) and opt-in (include_hidden: true) scenarios are asserted inside one test() with manual resetMocks() calls in between. Splitting into two named tests would improve isolation and make failures easier to diagnose.

♻️ Suggested split
-test('meta search remaps include_hidden through to package rows and search-scope retrievers', async () => {
-	resetMocks()
-	const ctx = createCtx()
-
-	await searchCapability.handler({ query: 'notes' }, ctx)
-
-	expect(mockModule.loadSearchRowsAndRegistry).toHaveBeenCalledWith(
-		expect.objectContaining({
-			includeHiddenPackages: false,
-		}),
-	)
-	expect(mockModule.runPackageRetrievers).toHaveBeenCalledWith(
-		expect.objectContaining({
-			scope: 'search',
-			includeHiddenPackages: false,
-		}),
-	)
-
-	resetMocks()
-	await searchCapability.handler({ query: 'notes', include_hidden: true }, ctx)
-
-	expect(mockModule.loadSearchRowsAndRegistry).toHaveBeenCalledWith(
-		expect.objectContaining({
-			includeHiddenPackages: true,
-		}),
-	)
-	expect(mockModule.runPackageRetrievers).toHaveBeenCalledWith(
-		expect.objectContaining({
-			scope: 'search',
-			includeHiddenPackages: true,
-		}),
-	)
-})
+test('meta search defaults include_hidden to false', async () => {
+	resetMocks()
+	const ctx = createCtx()
+	await searchCapability.handler({ query: 'notes' }, ctx)
+	expect(mockModule.loadSearchRowsAndRegistry).toHaveBeenCalledWith(
+		expect.objectContaining({ includeHiddenPackages: false }),
+	)
+	expect(mockModule.runPackageRetrievers).toHaveBeenCalledWith(
+		expect.objectContaining({ scope: 'search', includeHiddenPackages: false }),
+	)
+})
+
+test('meta search remaps include_hidden: true through to package rows and search-scope retrievers', async () => {
+	resetMocks()
+	const ctx = createCtx()
+	await searchCapability.handler({ query: 'notes', include_hidden: true }, ctx)
+	expect(mockModule.loadSearchRowsAndRegistry).toHaveBeenCalledWith(
+		expect.objectContaining({ includeHiddenPackages: true }),
+	)
+	expect(mockModule.runPackageRetrievers).toHaveBeenCalledWith(
+		expect.objectContaining({ scope: 'search', includeHiddenPackages: true }),
+	)
+})
🤖 Prompt for 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.

In `@packages/worker/src/mcp/capabilities/meta/search-include-hidden.node.test.ts`
around lines 89 - 121, Split the combined test for searchCapability.handler into
two independently named test cases: one covering the default include_hidden
behavior and one covering the explicit true opt-in. Move each scenario’s setup
and assertions into its respective test, removing the manual resetMocks()
between scenarios while preserving the existing expectations.
packages/worker/src/mcp/tools/search-format.ts (1)

948-962: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Markdown summary omits hidden status.

hasApp gets a - Has app: yes/no line in the package markdown summary (line 960), but there's no equivalent line for hidden, even though the structured output for this same detail (line 1054) now includes it. Since a hidden package is still directly reachable via entity lookup, surfacing this in the human-readable text too would avoid the markdown and structured outputs diverging.

♻️ Suggested addition
 			`- Has app: ${detail.record.hasApp ? 'yes' : 'no'}`,
+			`- Hidden from search: ${detail.record.hidden ? 'yes' : 'no'}`,
 			...(detail.hostedUrl ? [`- Hosted URL: \`${detail.hostedUrl}\``] : []),
🤖 Prompt for 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.

In `@packages/worker/src/mcp/tools/search-format.ts` around lines 948 - 962,
Update the package markdown summary construction in the lines array to include a
Hidden status line derived from detail.record.hidden, matching the yes/no
formatting used by the existing Has app line and the structured detail output.
packages/worker/src/mcp/capabilities/meta/search.ts (1)

110-129: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

include_hidden breaks casing convention used by sibling fields and the public tool.

conversationId and memoryContext in this same inputSchema are camelCase, but the new field is include_hidden (snake_case). The public search tool (tools/search.ts) exposes the equivalent flag as includeHiddenPackages — and this capability's description explicitly states it mirrors "the same discovery surface as the public MCP search tool." Mixed casing on the identical concept increases the chance of integration mistakes for callers switching between the two surfaces.

✏️ Suggested rename for consistency
-			include_hidden: z
+			includeHiddenPackages: z
 				.boolean()
 				.optional()
 				.describe(
 					'Include hidden packages in search results (hidden packages are excluded by default).',
 				),

and update the handler's arg type/usage accordingly (args.includeHiddenPackages).

Also applies to: 138-138

🤖 Prompt for 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.

In `@packages/worker/src/mcp/capabilities/meta/search.ts` around lines 110 - 129,
Rename the inputSchema field include_hidden to includeHiddenPackages in the
capability search definition, matching the public search tool and sibling
camelCase fields. Update the handler’s argument type and all usages to read
args.includeHiddenPackages while preserving the existing optional behavior and
description.
🤖 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.

Nitpick comments:
In
`@packages/worker/src/mcp/capabilities/meta/search-include-hidden.node.test.ts`:
- Around line 89-121: Split the combined test for searchCapability.handler into
two independently named test cases: one covering the default include_hidden
behavior and one covering the explicit true opt-in. Move each scenario’s setup
and assertions into its respective test, removing the manual resetMocks()
between scenarios while preserving the existing expectations.

In `@packages/worker/src/mcp/capabilities/meta/search.ts`:
- Around line 110-129: Rename the inputSchema field include_hidden to
includeHiddenPackages in the capability search definition, matching the public
search tool and sibling camelCase fields. Update the handler’s argument type and
all usages to read args.includeHiddenPackages while preserving the existing
optional behavior and description.

In `@packages/worker/src/mcp/tools/search-format.ts`:
- Around line 948-962: Update the package markdown summary construction in the
lines array to include a Hidden status line derived from detail.record.hidden,
matching the yes/no formatting used by the existing Has app line and the
structured detail output.

In `@packages/worker/src/package-registry/repo.ts`:
- Around line 145-146: Extract the duplicated package column projection into one
shared constant in repo.ts, then reuse it in getSavedPackageById,
getSavedPackageByKodyId, getSavedPackageByName, listSavedPackagesByUserId, and
listSavedPackagesPage. Preserve the existing column order and query behavior
while replacing each repeated SELECT list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cd726bbb-c181-434d-9e54-7a53c3ad1551

📥 Commits

Reviewing files that changed from the base of the PR and between 18f67ce and 6bc121e.

📒 Files selected for processing (53)
  • docs/contributing/architecture/data-storage.md
  • docs/contributing/packages-and-manifests.md
  • docs/use/packages.md
  • docs/use/search.md
  • packages/worker/migrations/0058-saved-packages-hidden.sql
  • packages/worker/src/app/handlers/account-package-invocation-tokens.node.test.ts
  • packages/worker/src/app/handlers/account-secrets.node.test.ts
  • packages/worker/src/app/handlers/package-app.node.test.ts
  • packages/worker/src/community/community-flow-test-schema.ts
  • packages/worker/src/community/community-service.node.test.ts
  • packages/worker/src/email/inbound.workers.test.ts
  • packages/worker/src/email/system-email-subscriptions.workers.test.ts
  • packages/worker/src/mcp/capabilities/meta/search-include-hidden.node.test.ts
  • packages/worker/src/mcp/capabilities/meta/search.ts
  • packages/worker/src/mcp/capabilities/openapi-provider/operation-request.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/create-stub-package.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/create-stub-package.ts
  • packages/worker/src/mcp/capabilities/packages/domain.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.ts
  • packages/worker/src/mcp/capabilities/packages/list-package-subscriptions.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/list-packages.ts
  • packages/worker/src/mcp/capabilities/packages/save-package-entitlements.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/save-package-private-visibility.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/save-package.ts
  • packages/worker/src/mcp/capabilities/packages/set-package-hidden.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/set-package-hidden.ts
  • packages/worker/src/mcp/capabilities/packages/shared.ts
  • packages/worker/src/mcp/capabilities/repo/repo-list-sessions.node.test.ts
  • packages/worker/src/mcp/capabilities/repo/repo-open-session.node.test.ts
  • packages/worker/src/mcp/capabilities/repo/repo-workflow.node.test.ts
  • packages/worker/src/mcp/capabilities/services/service-start.node.test.ts
  • packages/worker/src/mcp/capabilities/services/services-domain.node.test.ts
  • packages/worker/src/mcp/fetch-gateway.node.test.ts
  • packages/worker/src/mcp/tools/search-format.node.test.ts
  • packages/worker/src/mcp/tools/search-format.ts
  • packages/worker/src/mcp/tools/search-handler.node.test.ts
  • packages/worker/src/mcp/tools/search-hidden-packages.node.test.ts
  • packages/worker/src/mcp/tools/search.node.test.ts
  • packages/worker/src/mcp/tools/search.ts
  • packages/worker/src/package-invocations/service.node.test.ts
  • packages/worker/src/package-registry/package-reindex.node.test.ts
  • packages/worker/src/package-registry/repo.ts
  • packages/worker/src/package-registry/saved-packages-hidden-migration.node.test.ts
  • packages/worker/src/package-registry/service.node.test.ts
  • packages/worker/src/package-registry/service.ts
  • packages/worker/src/package-registry/types.ts
  • packages/worker/src/package-retrievers/manifest-cache.node.test.ts
  • packages/worker/src/package-retrievers/service.ts
  • packages/worker/src/package-runtime/module-graph.node.test.ts
  • packages/worker/src/package-runtime/module-graph.workers.test.ts
  • packages/worker/src/package-runtime/published-bundle-artifacts.node.test.ts
  • packages/worker/src/repo/published-bundle-artifacts-repo.workers.test.ts

Use one include-hidden contract across search surfaces and expose visibility in human-readable package details.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kentcdodds
kentcdodds merged commit b7b1a86 into main Jul 13, 2026
5 checks passed
@kentcdodds
kentcdodds deleted the hidden-packages branch July 13, 2026 22:35
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