---
title: "Unified search across orgs, catalog, collections, releases, and chunks"
method: GET
path: "/search"
tags: ["Search"]
---

# Unified search across orgs, catalog, collections, releases, and chunks

`GET /search`

Returns orgs, catalog entries (products + standalone sources folded together), curated collections, release hits, and — on hybrid/semantic modes — CHANGELOG.md chunk hits in a single response.

Entity sections (orgs/catalog) match at word boundaries — including camelCase transitions ("ai" matches OpenAI but not Em·ai·l) — and never via a domain TLD ("ai" does not match coderabbit.ai). Hits order by match quality: exact name/slug, then name prefix, then name word, then slug/domain/URL, then org category.

`mode` selects the release-retrieval strategy: `lexical` (FTS5), `semantic` (vector-only), or `hybrid` (RRF fusion of FTS5 + vector; default). The handler echoes back the mode actually used, including `degraded: true` when a hybrid request fell back to lexical because Vectorize is unavailable.

`?domain=` narrows the entire result set to one org (matched against `organizations.domain` and `domain_aliases.domain`). Invalid hostnames return 400; unknown hostnames return an empty envelope with `domainStatus: "not_found"` (distinct from "matched but no hits").

`?category=` and `?collection=` scope orgs, catalog, and release hits to an org set — a fixed category slug (unknown → 400) or a curated collection's members (unknown → empty envelope with `collectionStatus: "not_found"`). Both compose with every other filter.

When the query parses as a GitHub coordinate (`org/repo` or `github:org/repo`) and no orgs/catalog matched, the handler runs an on-demand lookup and embeds the result on `lookup`. Coordinate-shaped queries are not suppressed by tangential release/chunk hits.

Collections surface via two paths: a direct match on the collection's name/description (lexical in every mode, plus a vector match in hybrid/semantic mode — vector hits below the relevance floor are dropped so off-topic queries return no collections) and a member rollup that includes every collection containing one of the matched orgs. Each row carries a `via` discriminator (`"direct"` vs `"member"`); `matchedOrgSlugs` on member rows names the result-set orgs that triggered the rollup so a UI can render an "includes X" hint.

Content negotiation: `Accept: text/markdown` returns a Markdown-rendered version of the same payload.

## Query parameters

- `q` string, required
- `limit` integer
- `offset` integer
- `mode` 'lexical' | 'semantic' | 'hybrid'
- `domain` string
- `product` string
- `category` 'ai' | 'cloud' | 'commerce' | 'crm' | 'database' | 'design' | 'developer-tools' | 'devops' | 'finance' | 'framework' | 'infrastructure' | 'observability' | 'productivity' | 'security'
- `collection` string
- `include_coverage` boolean
- `include_content` boolean
- `include_empty` boolean
- `kind` 'platform' | 'sdk' | 'mobile' | 'desktop' | 'docs' | 'integration' | 'tool'
- `since` string
- `until` string

## Response `200`

Unified search response. JSON by default; Markdown when `Accept: text/markdown` is sent.

- object
  - `query` string, required
  - `domain` string
  - `domainStatus` 'matched' | 'not_found'
  - `category` string
  - `categoryStatus` 'matched'
  - `collection` string
  - `collectionStatus` 'matched' | 'not_found'
  - `orgs` object[], required
    - `slug` string, required
    - `name` string, required
    - `domain` string, nullable, required
    - `avatarUrl` string, nullable, required
    - `category` string, nullable, required
    - `status` 'stub' | 'tracked'
    - `aliasDomains` string[]
  - `catalog` object[], required
    - `slug` string, required
    - `name` string, required
    - `orgSlug` string, nullable, required
    - `orgName` string, nullable, required
    - `orgAvatarUrl` string, nullable
    - `category` string, nullable, required
    - `entryType` 'product' | 'source', required
    - `kind` 'platform' | 'sdk' | 'mobile' | 'desktop' | 'docs' | 'integration' | 'tool', nullable
    - `sourceSlug` string
    - `sourceType` 'github' | 'scrape' | 'feed' | 'agent' | 'appstore' | 'video'
  - `sources` object[], required
    - `slug` string, required
    - `name` string, required
    - `type` 'github' | 'scrape' | 'feed' | 'agent' | 'appstore' | 'video', required
    - `orgSlug` string, nullable, required
    - `orgName` string, nullable, required
    - `productSlug` string, nullable, required
    - `stars` integer, nullable
  - `releases` object[], required
    - `id` string, required
    - `sourceSlug` string, required
    - `sourceName` string, required
    - `sourceType` string
    - `appStore` object, nullable
      - `platform` 'ios' | 'macos', required
      - `iconUrl` string, nullable, required
    - `video` object, nullable
      - `provider` 'youtube' | 'vimeo' | 'wistia', required
    - `orgSlug` string, nullable, required
    - `orgName` string, nullable
    - `productSlug` string, nullable
    - `version` string, nullable, required
    - `title` string, required
    - `summary` string, required
    - `titleGenerated` string, nullable
    - `titleShort` string, nullable
    - `importance` integer, nullable
    - `content` string
    - `media` object[]
      - `type` 'image' | 'video' | 'gif', required
      - `url` string, required
      - `alt` string
      - `r2Key` string
      - `r2Url` string
      - `linkUrl` string
    - `publishedAt` string, nullable, required
    - `score` number
    - `type` 'feature' | 'rollup'
    - `coverageCount` integer
  - `collections` object[]
    - `slug` string, required
    - `name` string, required
    - `description` string, nullable, required
    - `memberCount` integer, required
    - `via` 'direct' | 'member', required
    - `score` number
    - `matchedOrgSlugs` string[]
    - `previewMembers` union[]
      - union
        - object
          - `slug` string, required
          - `name` string, required
          - `domain` string, nullable, required
          - `avatarUrl` string, nullable, required
          - `githubHandle` string, nullable, required
          - `description` string, nullable, required
          - `kind` 'org', required
        - object
          - `slug` string, required
          - `name` string, required
          - `description` string, nullable, required
          - `org` object, required
            - `slug` string, required
            - `name` string, required
            - `domain` string, nullable, required
            - `avatarUrl` string, nullable, required
            - `githubHandle` string, nullable, required
          - `kind` 'product', required
  - `chunks` object[]
    - `sourceSlug` string, required
    - `sourceName` string, required
    - `orgSlug` string, nullable, required
    - `orgName` string, nullable
    - `filePath` string, required
    - `offset` integer, required
    - `length` integer, required
    - `heading` string, nullable, required
    - `snippet` string, required
    - `score` number, required
  - `mode` 'lexical' | 'semantic' | 'hybrid'
  - `degraded` boolean
  - `degradedReason` string
  - `lookup` object, nullable
    - `status` 'indexed' | 'existing' | 'empty' | 'not_found' | 'deferred', required
    - `source` object
      - `id` string, required
      - `slug` string, required
      - `name` string, required
      - `url` string, required
      - `discovery` 'curated' | 'agent' | 'on_demand', required
      - `stars` integer, nullable
    - `releases` object[]
      - `id` string, required
      - `version` string, nullable, required
      - `title` string, required
      - `publishedAt` string, nullable, required
      - `thumbnail` object, nullable
        - `url` string, required
        - `alt` string
    - `relatedOrg` object, nullable, required
      - `org` object, required
        - `id` string, required
        - `slug` string, required
        - `name` string, required
      - `sources` object[], required
        - `id` string, required
        - `slug` string, required
        - `name` string, required
        - `url` string, required

## Other responses

- `400` — Missing `q`, invalid `domain` hostname, unknown `kind` or `category` value, or unparseable `since`/`until`

---

[API](https://skmtc.net/releases/apis/releases-api.md) · [All operations](https://skmtc.net/releases/apis/releases-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/releases/releases-api/revisions/168e32061f53/schema)
