From aeb711a9088013041dc427e38e4b325a3367e489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Fri, 4 Sep 2026 10:13:44 +0200 Subject: [PATCH 01/26] Add prompt template. --- .../documentation/agentic-tools/_index.md | 21 ++ .../agentic-tools/prompt-templates/_index.md | 16 ++ .../review-collection-configuration.md | 110 ++++++++ .../translate-pinecone-workload.md | 115 ++++++++ .../{ => agentic-tools}/skills.md | 4 +- .../qdrant-2024/assets/css/_components.scss | 1 + .../css/components/_prompt-template.scss | 252 ++++++++++++++++++ .../qdrant-2024/assets/js/prompt-template.js | 114 ++++++++ .../qdrant-2024/layouts/partials/js.html | 7 + .../layouts/shortcodes/prompt-template.html | 52 ++++ 10 files changed, 691 insertions(+), 1 deletion(-) create mode 100644 qdrant-landing/content/documentation/agentic-tools/_index.md create mode 100644 qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md create mode 100644 qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md create mode 100644 qdrant-landing/content/documentation/agentic-tools/prompt-templates/translate-pinecone-workload.md rename qdrant-landing/content/documentation/{ => agentic-tools}/skills.md (99%) create mode 100644 qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss create mode 100644 qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js create mode 100644 qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html diff --git a/qdrant-landing/content/documentation/agentic-tools/_index.md b/qdrant-landing/content/documentation/agentic-tools/_index.md new file mode 100644 index 000000000..900a83e3d --- /dev/null +++ b/qdrant-landing/content/documentation/agentic-tools/_index.md @@ -0,0 +1,21 @@ +--- +title: "Agentic Tools" +short_description: "Tools that help AI coding assistants work with Qdrant: agent skills for diagnosis and tuning, and prompt templates for design, migration, evaluation, and review." +description: "Qdrant agentic tools for AI coding assistants. Agent skills give your agent solutions architect knowledge on demand. Prompt templates give you task-shaped prompts for designing collections, migrating from other engines, evaluating search quality, and reviewing configurations." +weight: 303 +partition: develop +--- + +# Agentic Tools + +Most people now reach Qdrant through an AI coding assistant rather than through the documentation directly. Agentic tools are built for that path: they give your agent the context and the judgment it needs to configure vector search correctly, instead of leaving it to infer both from API reference. + +There are two, and they answer different questions. + +## Agent Skills + +[Agent skills](/documentation/agentic-tools/skills/) encode solutions architect knowledge as structured files your agent loads on demand. They're organized around symptoms, so they answer "why is this happening, and what should I check first?" Reach for skills when something is already running and behaving unexpectedly: slow search, growing memory, a stuck optimizer, poor relevance. + +## Prompt Template Library + +The [prompt template library](/documentation/agentic-tools/prompt-templates/) is a set of task-shaped prompts you fill in and hand to your agent. They answer "how do I get a correct result for my specific case?" Reach for templates when you're designing something new, moving from another engine, measuring whether search actually works, or reviewing a configuration before it ships. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md new file mode 100644 index 000000000..091423c44 --- /dev/null +++ b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md @@ -0,0 +1,16 @@ +--- +title: "Prompt Template Library" +short_description: "Task-shaped prompts for designing, migrating, evaluating, and reviewing Qdrant deployments. Fill in the variables, hand the result to your coding agent." +description: "A curated library of Qdrant prompt templates. Each template takes your collection configuration and workload as input and produces a structured result: a launch review, a migration plan, an evaluation harness, or a payload index audit." +weight: 20 +partition: develop +--- + +# Prompt Template Library + +Vector search is unusual in that a wrong configuration returns plausible results instead of an error, so the hard questions are rarely about syntax. Each template here takes your real configuration and workload as input, tells your agent what to check and what shape to answer in, and points at the [agent skills](/documentation/agentic-tools/skills/) that own the underlying reasoning. Fill in the variables, copy the prompt, and hand it to your coding assistant. + +## Templates + +- [Review a Collection Configuration Before Launch](/documentation/agentic-tools/prompt-templates/review-collection-configuration/) produces a go or no-go checklist over indexing, quantization, replication, and filter readiness for a collection about to take production traffic. +- [Translate a Pinecone Workload to Qdrant](/documentation/agentic-tools/prompt-templates/translate-pinecone-workload/) maps an index definition, namespaces, metadata filters, and hybrid weighting onto Qdrant equivalents, and calls out where the two engines genuinely differ. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md new file mode 100644 index 000000000..5c6d69b8b --- /dev/null +++ b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md @@ -0,0 +1,110 @@ +--- +title: "Review a Collection Configuration Before Launch" +short_description: "Hand your agent a collection configuration and workload profile, and get a go or no-go checklist covering indexing, quantization, replication, and filter readiness." +description: "A Qdrant prompt template for pre-launch collection review. Produces a prioritized checklist of blockers and recommendations across payload indexing, quantization, replication, sharding, and search parameters, based on your actual configuration." +weight: 10 +partition: develop +category: review-and-audit +output_contract: checklist +tags: + - review + - production-readiness + - payload-index +template_version: 1 +variables: + - name: COLLECTION_CONFIG + required: true + description: "The full configuration of the collection you're about to launch." + source: "curl -s $QDRANT_URL/collections/COLLECTION | jq .result" + placeholder: "vectors: {size: 1024, distance: Cosine}, optimizers_config: {...}" + - name: WORKLOAD_PROFILE + required: true + description: "Point count, expected QPS, latency target, and the filters your queries actually use." + placeholder: "12M points, ~300 QPS peak, p95 target 100 ms, filters on tenant_id and created_at" + - name: DEPLOYMENT_TARGET + required: false + description: "Node count, RAM and disk per node, and whether this is Qdrant Cloud, Hybrid Cloud, or self-hosted." + placeholder: "3 nodes, 32 GB RAM each, self-hosted on Kubernetes" + - name: LAUNCH_CONSTRAINTS + required: false + description: "Anything that limits your options, such as a fixed memory budget or a no-downtime requirement." + placeholder: "cannot exceed 32 GB per node; no downtime during cutover" +draws_on: + skills: + - qdrant-performance-optimization/search-speed-optimization + - qdrant-performance-optimization/memory-usage-optimization + - qdrant-sizing + - qdrant-multitenancy + docs: + - /documentation/production-checklist/ + - /documentation/manage-data/indexing/ + - /documentation/manage-data/quantization/ +--- + +# Review a Collection Configuration Before Launch + +A collection that works in staging can fail in production for reasons that never surface in a test suite: a filter field with no payload index, a replication factor of 1 on a cluster you expect to survive a node loss, or a quantization setting that quietly costs you recall. This template hands your agent the actual configuration and the workload it is about to take, and asks for a prioritized verdict rather than general advice. + +Use it once the configuration is settled but before real traffic arrives. For a collection that's already live and misbehaving, the [agent skills](/documentation/agentic-tools/skills/) are the better starting point, because they're organized around symptoms. + +## The Template + +Fill in the variables, then copy the prompt into your coding assistant. + +{{< prompt-template >}} +You are reviewing a Qdrant collection configuration before it takes production traffic. Report findings only. Do not explain how Qdrant works. + +Collection configuration: +{{COLLECTION_CONFIG}} + +Workload profile: +{{WORKLOAD_PROFILE}} + +Deployment target: +{{DEPLOYMENT_TARGET}} + +Launch constraints: +{{LAUNCH_CONSTRAINTS}} + +Check each of the following against the configuration and workload above. For each one, decide whether it's a blocker, a recommendation, or already correct. + +1. Payload indexes. Every field used in a filter needs an index whose type matches how it's filtered. Flag filter fields with no index, and flag indexes on fields too low in cardinality to be selective. If the workload is multitenant, check whether is_tenant is set on the partitioning field. +2. Vector index parameters. Check m and ef_construct against the point count and latency target. For a multitenant collection, check whether m is set to 0 with payload_m set instead, so the global index isn't built. +3. Quantization. Decide whether the memory budget requires it. If quantization is already configured, check that rescore and oversampling are set consistently with the recall the workload needs, and say what recall loss to expect. +4. Memory and disk. Estimate resident memory for vectors, payload indexes, and the vector index, then compare against the deployment target. State the assumptions behind the estimate. +5. Replication and sharding. Check the replication factor against the stated failure tolerance, and the shard count against node count and expected growth. Flag a shard count that can't be changed later without a full reindex. +6. Optimizer and write path. Check indexing_threshold, memmap_threshold, and default_segment_number against the ingestion pattern, and say whether the initial bulk load should use different settings from steady state. +7. Consistency and durability. Check write_consistency_factor and the on-disk settings against the durability the workload requires. + +Then look for anything that's wrong but not on this list. + +Output a table with columns: Area, Severity, Finding, Action. Use severity values Blocker, Recommended, or OK. Sort blockers first. Omit rows that are OK unless there are no blockers at all. + +After the table, output the exact API or client calls needed to resolve every blocker, in the order they should be applied. Note which of them require a collection recreation rather than an update. + +End with one line: ship or do not ship. +{{< /prompt-template >}} + +## What Good Output Looks Like + +The table should be short and specific, with severities you can act on and no restatement of the configuration you supplied. + +```text +| Area | Severity | Finding | Action | +|----------------|-------------|--------------------------------------|---------------------------| +| Payload index | Blocker | tenant_id filtered, no index | create keyword index | +| Sharding | Blocker | 1 shard, 12M points, growth expected | recreate with 4 shards | +| Vector index | Recommended | m=16 global on multitenant set | m=0, payload_m=16 | + +Blocker resolution, in order: + 1. client.create_payload_index(..., field_schema=models.KeywordIndexParams( + type="keyword", is_tenant=True)) # update, no downtime + 2. Shard count change requires recreation. # plan a cutover + +Do not ship. +``` + +## Related + +- [Production Checklist](/documentation/production-checklist/) covers the same ground as prose you read yourself. +- The `qdrant-sizing` and `qdrant-performance-optimization` [agent skills](/documentation/agentic-tools/skills/) own the reasoning behind the memory and latency findings. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/translate-pinecone-workload.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/translate-pinecone-workload.md new file mode 100644 index 000000000..2a6e7f5ff --- /dev/null +++ b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/translate-pinecone-workload.md @@ -0,0 +1,115 @@ +--- +title: "Translate a Pinecone Workload to Qdrant" +short_description: "Map a Pinecone index definition, namespaces, metadata filters, and hybrid weighting onto Qdrant equivalents, including the places where the two engines genuinely differ." +description: "A Qdrant prompt template for Pinecone migration. Translates index definitions, namespace tenancy, metadata filters, and alpha-weighted hybrid search into Qdrant collection configuration and query shapes, and flags the semantic differences to verify after cutover." +weight: 20 +partition: develop +category: migration +output_contract: report +tags: + - migration + - pinecone + - multitenancy +template_version: 1 +variables: + - name: PINECONE_INDEX + required: true + description: "Your index definition: dimension, metric, pod or serverless type, replicas, and namespace count." + placeholder: "dim 1536, cosine, p1.x2 with 3 replicas, 240 namespaces" + - name: PINECONE_QUERIES + required: true + description: "Representative queries, including topK, namespace usage, metadata filters, and any hybrid alpha weighting." + placeholder: "topK=20, namespace per customer, filter {tier: {$in: [gold, platinum]}}, alpha=0.7" + - name: SCALE + required: false + description: "Vector count, peak QPS, latency target, and memory budget." + placeholder: "18M vectors, ~450 QPS peak, p95 under 80 ms" + - name: EMBEDDING_MODEL + required: false + description: "The model producing your vectors, and whether you plan to keep it through the migration." + placeholder: "text-embedding-3-small, keeping it for now" +draws_on: + skills: + - qdrant-multitenancy + - qdrant-search-quality/search-strategies/hybrid-search/combining-searches + - qdrant-sizing + docs: + - /documentation/migrate-to-qdrant/pinecone/ + - /documentation/manage-data/multitenancy/ + - /documentation/search/hybrid-queries/ +--- + +# Translate a Pinecone Workload to Qdrant + +A field-by-field port from Pinecone to Qdrant usually compiles and usually returns worse results, because three of Pinecone's core concepts have no direct equivalent. Namespaces are physical partitions, where Qdrant's answer is normally payload-based tenancy in a single collection. Metadata filters are applied differently, so result ordering can shift even when the filter is logically identical. And alpha-weighted hybrid search is a single blended score, where Qdrant uses prefetch plus a fusion step that ignores your weighting entirely. + +This template makes your agent resolve all three explicitly instead of guessing. + +## The Template + +Fill in the variables, then copy the prompt into your coding assistant. + +{{< prompt-template >}} +You are translating a Pinecone workload to Qdrant. Assume the reader knows both systems. Do not re-explain either API. + +Pinecone index definition: +{{PINECONE_INDEX}} + +Representative Pinecone queries: +{{PINECONE_QUERIES}} + +Scale and constraints: +{{SCALE}} + +Embedding model: +{{EMBEDDING_MODEL}} + +Produce the translation. Resolve each of the following rather than glossing over it. + +1. Namespaces. Pinecone namespaces are physical partitions. The usual Qdrant equivalent is one collection with payload-based tenancy and is_tenant set on the partitioning field, not one collection per namespace. Choose a model based on the namespace count and how skewed the data is across them, and state why. If the count is high or growth is unbounded, say what breaks in the alternative. +2. Metadata filters. Map the operators used above onto Qdrant filter clauses. Then note where ordering may shift: Qdrant applies filters during index traversal, so the candidate set differs from Pinecone's, and a filtered query can return a different ranking even when the filter is logically identical. +3. Hybrid search. If any query uses alpha weighting, give the Qdrant query shape as prefetch branches plus a fusion step. Say whether RRF or DBSF matches the intent, and state plainly that neither preserves the alpha weighting, so relevance has to be re-tuned against a ground-truth set after cutover. +4. Sizing. Translate pod or serverless capacity and replica count into RAM, disk, and node count for Qdrant. State every assumption you use, and flag where quantization would be needed to fit a stated memory budget. +5. Index parameters. Choose m, ef_construct, and any quantization settings from the scale and latency target. If you chose payload-based tenancy, set m to 0 and use payload_m. + +Output exactly four sections. + +Collection definition: the create_collection call, with payload index calls. +Query translations: a side-by-side mapping of each representative query to its Qdrant equivalent. +Semantic differences to verify after cutover: numbered, each with the specific check that would catch it. +Open questions: what you needed and did not have, and how each answer would change the design. +{{< /prompt-template >}} + +## What Good Output Looks Like + +The four sections should be concrete, and the differences section should read as a test plan rather than a caveat list. + +```text +## Collection definition + create_collection("prod", vectors_config={...}, + hnsw_config=models.HnswConfigDiff(m=0, payload_m=16)) + create_payload_index("prod", "tenant_id", + models.KeywordIndexParams(type="keyword", is_tenant=True)) + +## Query translations + Pinecone Qdrant + namespace="acme" -> filter must key=tenant_id match acme + filter {"tier": {"$in": -> key=tier match any [gold, platinum] + ["gold","platinum"]}} + alpha=0.7 hybrid -> prefetch dense + sparse, fusion=RRF + +## Semantic differences to verify after cutover + 1. Filtered ranking may differ. Check: run 200 production queries against + both, compare top-10 overlap. Under 0.9 means re-tune, not a bug. + 2. alpha=0.7 has no fusion equivalent. RRF is rank-based and discards the + weighting. Check: measure nDCG@10 on a ground-truth set before cutover. + +## Open questions + 1. Largest namespace as a share of total. Above roughly 20% the single + collection model needs a dedicated shard key. +``` + +## Related + +- [Migrate From Pinecone](/documentation/migrate-to-qdrant/pinecone/) covers the data transfer mechanics this template leaves out. +- [Hybrid Queries](/documentation/search/hybrid-queries/) documents the prefetch and fusion syntax the output uses. diff --git a/qdrant-landing/content/documentation/skills.md b/qdrant-landing/content/documentation/agentic-tools/skills.md similarity index 99% rename from qdrant-landing/content/documentation/skills.md rename to qdrant-landing/content/documentation/agentic-tools/skills.md index 2006f31b4..86aec2f99 100644 --- a/qdrant-landing/content/documentation/skills.md +++ b/qdrant-landing/content/documentation/agentic-tools/skills.md @@ -2,7 +2,9 @@ title: "Agent Skills" short_description: Qdrant agent skills encode solutions architect knowledge for AI coding assistants, helping them diagnose vector search problems, recommend the right configuration, and navigate to the exact documentation without installation. description: Qdrant agent skills help AI coding assistants diagnose and tune vector search in production. Pass a skill URL from skills.qdrant.tech to your agent to get targeted guidance on scaling, search quality, performance, monitoring, and more. -weight: 303 +weight: 10 +aliases: + - /documentation/skills/ partition: develop --- diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss b/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss index 6e1a8ed23..0071c0f5e 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss @@ -11,3 +11,4 @@ @import 'components/accordion'; @import 'components/course-card'; @import 'components/date'; +@import 'components/prompt-template'; diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss new file mode 100644 index 000000000..975463a15 --- /dev/null +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss @@ -0,0 +1,252 @@ +@use '../helpers/functions' as *; + +$pt-surface: $neutral-20; +$pt-surface-raised: $neutral-30; +$pt-border: $neutral-30; +$pt-border-strong: $neutral-40; +$pt-text: $neutral-98; +$pt-text-muted: $neutral-70; +$pt-accent: $primary-60; +$pt-ready: $secondary-teal-70; + +.prompt-template { + display: flex; + flex-direction: column; + gap: pxToRem(24); + margin: pxToRem(24) 0 pxToRem(32); + + &__vars { + background: $pt-surface; + border: 1px solid $pt-border; + border-radius: pxToRem(8); + padding: pxToRem(20); + } + + &__vars-title { + font-size: $font-size-xs; + font-weight: 600; + letter-spacing: 0.07em; + text-transform: uppercase; + color: $pt-text-muted; + margin: 0 0 pxToRem(16); + } + + &__field + &__field { + margin-top: pxToRem(20); + } + + &__label { + display: flex; + align-items: baseline; + gap: pxToRem(8); + margin-bottom: pxToRem(4); + + code { + font-family: $font-family-code; + font-size: $font-size-s; + color: $pt-text; + background: none; + padding: 0; + } + } + + &__flag { + font-size: pxToRem(11); + letter-spacing: 0.04em; + color: $pt-text-muted; + + &--req { + color: $pt-accent; + font-weight: 600; + } + } + + &__field--filled &__label code { + color: $pt-ready; + } + + &__hint { + font-size: $font-size-s; + color: $pt-text-muted; + margin: 0 0 pxToRem(8); + line-height: 1.45; + + code { + font-family: $font-family-code; + font-size: pxToRem(12); + background: $pt-surface-raised; + border-radius: pxToRem(3); + padding: pxToRem(1) pxToRem(5); + color: $pt-text-muted; + } + } + + &__input { + width: 100%; + font-family: $font-family-code; + font-size: $font-size-s; + line-height: 1.5; + color: $pt-text; + background: $neutral-10; + border: 1px solid $pt-border-strong; + border-radius: pxToRem(6); + padding: pxToRem(9) pxToRem(11); + resize: vertical; + + &:focus { + outline: 2px solid $pt-accent; + outline-offset: -1px; + border-color: $pt-accent; + } + } + + &__status { + font-size: $font-size-s; + color: $pt-text-muted; + margin: pxToRem(16) 0 0; + padding-top: pxToRem(12); + border-top: 1px solid $pt-border; + + &--ready { + color: $pt-ready; + } + } + + &__output { + border: 1px solid $pt-border; + border-radius: pxToRem(8); + overflow: hidden; + } + + &__bar { + display: flex; + align-items: center; + justify-content: space-between; + gap: pxToRem(12); + padding: pxToRem(10) pxToRem(16); + background: $pt-surface-raised; + border-bottom: 1px solid $pt-border; + } + + &__bar-title { + font-size: $font-size-xs; + font-weight: 600; + letter-spacing: 0.07em; + text-transform: uppercase; + color: $pt-text-muted; + } + + &__copy { + font-family: $font-family-base; + font-size: $font-size-s; + font-weight: 500; + color: $pt-text; + background: none; + border: 1px solid $pt-border-strong; + border-radius: pxToRem(6); + padding: pxToRem(5) pxToRem(14); + cursor: pointer; + + &:hover { + border-color: $pt-text-muted; + } + + &--done { + color: $pt-ready; + border-color: $pt-ready; + } + } + + &__body { + font-family: $font-family-code; + font-size: $font-size-s; + line-height: 1.65; + white-space: pre-wrap; + word-break: break-word; + background: $pt-surface; + color: $pt-text; + margin: 0; + padding: pxToRem(16); + max-height: pxToRem(560); + overflow: auto; + } + + &__ph { + color: $pt-accent; + font-weight: 500; + border: 1px dashed $pt-accent; + border-radius: pxToRem(3); + padding: 0 pxToRem(3); + } + + [data-theme='light'] & { + &__vars, + &__body { + background: $neutral-98; + } + + &__vars, + &__output { + border-color: $neutral-94; + } + + &__bar { + background: $neutral-94; + border-bottom-color: $neutral-90; + } + + &__status { + border-top-color: $neutral-94; + } + + &__input { + background: $neutral-100; + border-color: $neutral-90; + color: $neutral-10; + } + + &__label code, + &__body, + &__copy { + color: $neutral-10; + } + + &__hint, + &__vars-title, + &__bar-title, + &__flag, + &__status { + color: $neutral-50; + } + + &__hint code { + background: $neutral-94; + color: $neutral-50; + } + + &__flag--req, + &__ph { + color: $primary-40; + } + + &__ph { + border-color: $primary-40; + } + + &__status--ready, + &__copy--done { + color: $secondary-teal-30; + } + + &__copy--done { + border-color: $secondary-teal-30; + } + } +} + +// Written out rather than nested: inside a compound `&__a &__b` selector, +// `[data-theme='light'] &` would land in the descendant position and never +// match, because the theme attribute sits on . +[data-theme='light'] .prompt-template__field--filled .prompt-template__label code { + color: $secondary-teal-30; +} diff --git a/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js b/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js new file mode 100644 index 000000000..7a0c8921d --- /dev/null +++ b/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js @@ -0,0 +1,114 @@ +/** + * Fillable prompt templates (/documentation/agentic-tools/prompt-templates/). + * + * The shortcode renders the prompt body server-side with its {{PLACEHOLDER}} + * tokens intact. This module takes that text as its source, substitutes the + * values you type, and marks whatever is still unresolved. Nothing is fetched, + * and nothing is stored. + */ +(function () { + const PLACEHOLDER = /\{\{\s*([A-Z0-9_]+)\s*\}\}/g; + + const escapeHtml = (value) => + value.replace(/&/g, '&').replace(//g, '>'); + + class PromptTemplate { + constructor(root) { + this.root = root; + this.output = root.querySelector('[data-pt-output]'); + + if (!this.output) return; + + // The server-rendered body is the source of truth, read once before any + // substitution happens. + this.source = this.output.textContent; + this.inputs = Array.from(root.querySelectorAll('[data-pt-var]')); + this.status = root.querySelector('[data-pt-status]'); + this.copyBtn = root.querySelector('[data-pt-copy]'); + + this.inputs.forEach((input) => { + input.addEventListener('input', () => this.render()); + }); + + if (this.copyBtn) { + this.copyBtn.addEventListener('click', () => this.copy()); + } + + this.render(); + } + + values() { + return this.inputs.reduce((acc, input) => { + acc[input.dataset.ptVar] = input.value.trim(); + return acc; + }, {}); + } + + resolve() { + const values = this.values(); + return this.source.replace(PLACEHOLDER, (token, name) => values[name] || token); + } + + missingRequired() { + const values = this.values(); + return this.inputs + .filter((input) => input.dataset.ptRequired === 'true' && !values[input.dataset.ptVar]) + .map((input) => input.dataset.ptVar); + } + + render() { + this.output.innerHTML = escapeHtml(this.resolve()).replace( + PLACEHOLDER, + '$&', + ); + + this.inputs.forEach((input) => { + const field = this.root.querySelector(`[data-pt-field="${input.dataset.ptVar}"]`); + if (field) field.classList.toggle('prompt-template__field--filled', !!input.value.trim()); + }); + + if (!this.status) return; + + const missing = this.missingRequired(); + + if (missing.length === 0) { + this.status.textContent = 'All required variables resolved.'; + this.status.classList.add('prompt-template__status--ready'); + } else { + this.status.textContent = `Still unresolved: ${missing.join(', ')}`; + this.status.classList.remove('prompt-template__status--ready'); + } + } + + copy() { + const label = this.copyBtn.textContent; + + navigator.clipboard.writeText(this.resolve()).then( + () => { + this.copyBtn.textContent = 'Copied'; + this.copyBtn.classList.add('prompt-template__copy--done'); + + setTimeout(() => { + this.copyBtn.textContent = label; + this.copyBtn.classList.remove('prompt-template__copy--done'); + }, 1600); + }, + () => { + this.copyBtn.textContent = 'Press Ctrl+C'; + }, + ); + } + } + + const init = () => { + document.querySelectorAll('[data-prompt-template]').forEach((root) => { + new PromptTemplate(root); + }); + }; + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); diff --git a/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html b/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html index 4edb8fdf1..7b88ece46 100644 --- a/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html +++ b/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html @@ -117,6 +117,13 @@ {{ end }} +{{/* Prompt templates live under /documentation/, so .Section is "documentation" + here and cannot isolate them. Match on the path instead. */}} +{{ if in .RelPermalink "/documentation/agentic-tools/prompt-templates/" }} + {{ $promptTemplateJs := resources.Get "js/prompt-template.js" | js.Build | minify | resources.Fingerprint "sha512" }} + +{{ end }} + {{ if in (slice "customers" "demo") .Section }} {{ $catalogFiltersJs := resources.Get "js/catalog-filters.js" | js.Build | minify | resources.Fingerprint "sha512" }} diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html new file mode 100644 index 000000000..3406670bc --- /dev/null +++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html @@ -0,0 +1,52 @@ +{{- /* + Renders a fillable prompt template. The prompt body is this shortcode's Inner + content; the variables come from the page's `variables` front matter. + + The body is rendered server-side with its {{PLACEHOLDER}} tokens intact, so the + page is complete and copyable without JavaScript. prompt-template.js reads that + text as its source and substitutes values as you type. + + `without-copy-code` keeps copy-code.js from injecting a second copy button. +*/ -}} +{{- $vars := .Page.Params.variables -}} +
+ {{- with $vars }} +
+

Variables

+ {{- range . }} +
+ +

+ {{ .description }} + {{- with .source }}
{{ . }}{{ end }} +

+ +
+ {{- end }} +

+
+ {{- end }} + +
+
+ Prompt + +
+
{{ .Inner | htmlEscape | safeHTML }}
+
+
From 60cebb450ff460a9819cc08c90c1debdf988cd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Tue, 8 Sep 2026 15:20:56 +0200 Subject: [PATCH 02/26] Add prompts. --- .../documentation/agentic-tools/_index.md | 50 ++++++- .../agentic-tools/prompt-templates/_index.md | 6 +- .../design-collection-schema.md | 129 ++++++++++++++++++ .../review-collection-configuration.md | 2 +- .../translate-pinecone-workload.md | 115 ---------------- 5 files changed, 179 insertions(+), 123 deletions(-) create mode 100644 qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md delete mode 100644 qdrant-landing/content/documentation/agentic-tools/prompt-templates/translate-pinecone-workload.md diff --git a/qdrant-landing/content/documentation/agentic-tools/_index.md b/qdrant-landing/content/documentation/agentic-tools/_index.md index 900a83e3d..449a5098b 100644 --- a/qdrant-landing/content/documentation/agentic-tools/_index.md +++ b/qdrant-landing/content/documentation/agentic-tools/_index.md @@ -8,14 +8,56 @@ partition: develop # Agentic Tools -Most people now reach Qdrant through an AI coding assistant rather than through the documentation directly. Agentic tools are built for that path: they give your agent the context and the judgment it needs to configure vector search correctly, instead of leaving it to infer both from API reference. +Qdrant provides tools and resources that help AI agents work with Qdrant more effectively. +Use them to give your agent task-specific guidance, troubleshoot existing deployments, design and evaluate search systems, and apply Qdrant best practices to your specific use case. -There are two, and they answer different questions. +## Start Building + +If you're new to Qdrant, paste this into your coding assistant. +It stands up a local instance, installs the client with local embeddings, adds the [Qdrant Advisor](/documentation/agentic-tools/skills/#the-qdrant-advisor) skill, and then builds against your own use case. + +```text +Help me get started building on Qdrant. + +1. Start Qdrant locally with Docker. No signup and no API key needed: + docker run -p 6333:6333 -p 6334:6334 \ + -v "$(pwd)/qdrant_storage:/qdrant/storage:z" \ + qdrant/qdrant + Confirm it's running at http://localhost:6333/dashboard + +2. Install the client with local embeddings, so I don't need an + embedding provider key either: + pip install "qdrant-client[fastembed]" + +3. Install the Qdrant Advisor agent skill: + npx skills add qdrant/skills/meta/qdrant-advisor + +4. Then ask me what I'm building and what I'll search over before you + write any code. Once you know, build the integration against my + local instance, and get the collection right the first time: + - Derive the vector size from the model with + client.get_embedding_size(model_name). Never hardcode a dimension. + - Choose the distance metric the model was trained for, and say + which one you picked and why. + - Create a payload index for every field I'll filter on, before I + load data rather than after. + Then load a small sample, run a real query, and show me the results. +``` + +Nothing in those four steps needs an account. +Qdrant runs in Docker and [FastEmbed](/documentation/fastembed/fastembed-quickstart/) generates embeddings on your machine, so you can go from nothing to a working search query without signing up for anything. + +Step 4 does the work that matters. +A wrong collection configuration rarely fails loudly in vector search: a mismatched distance metric or a missing payload index returns plausible results and quietly costs you relevance, so it's worth making your agent commit to those choices out loud before it writes code. ## Agent Skills -[Agent skills](/documentation/agentic-tools/skills/) encode solutions architect knowledge as structured files your agent loads on demand. They're organized around symptoms, so they answer "why is this happening, and what should I check first?" Reach for skills when something is already running and behaving unexpectedly: slow search, growing memory, a stuck optimizer, poor relevance. +[Agent skills](/documentation/agentic-tools/skills/) encode solutions architect knowledge as structured files your agent loads on demand. +They're organized around symptoms, so they answer "why is this happening, and what should I check first?" +Reach for skills when something is already running and behaving unexpectedly: slow search, growing memory, a stuck optimizer, poor relevance. ## Prompt Template Library -The [prompt template library](/documentation/agentic-tools/prompt-templates/) is a set of task-shaped prompts you fill in and hand to your agent. They answer "how do I get a correct result for my specific case?" Reach for templates when you're designing something new, moving from another engine, measuring whether search actually works, or reviewing a configuration before it ships. +The [prompt template library](/documentation/agentic-tools/prompt-templates/) is a set of task-shaped prompts you fill in and hand to your agent. +They answer "how do I get a correct result for my specific case?" +Reach for templates when you're designing something new, moving from another engine, measuring whether search actually works, or reviewing a configuration before it ships. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md index 091423c44..a820063a3 100644 --- a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md +++ b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md @@ -1,7 +1,7 @@ --- title: "Prompt Template Library" -short_description: "Task-shaped prompts for designing, migrating, evaluating, and reviewing Qdrant deployments. Fill in the variables, hand the result to your coding agent." -description: "A curated library of Qdrant prompt templates. Each template takes your collection configuration and workload as input and produces a structured result: a launch review, a migration plan, an evaluation harness, or a payload index audit." +short_description: "Task-shaped prompts for designing, evaluating, and reviewing Qdrant collections. Fill in the variables, hand the result to your coding agent." +description: "A curated library of Qdrant prompt templates. Each template takes your data, configuration, and workload as input and produces a structured result: a collection definition, a pre-launch review, or a payload index audit." weight: 20 partition: develop --- @@ -12,5 +12,5 @@ Vector search is unusual in that a wrong configuration returns plausible results ## Templates +- [Design a Collection Schema From a Dataset Description](/documentation/agentic-tools/prompt-templates/design-collection-schema/) turns a description of your data and the searches you need into a collection definition, with the vector configuration, distance metric, payload schema, and payload indexes chosen and justified. - [Review a Collection Configuration Before Launch](/documentation/agentic-tools/prompt-templates/review-collection-configuration/) produces a go or no-go checklist over indexing, quantization, replication, and filter readiness for a collection about to take production traffic. -- [Translate a Pinecone Workload to Qdrant](/documentation/agentic-tools/prompt-templates/translate-pinecone-workload/) maps an index definition, namespaces, metadata filters, and hybrid weighting onto Qdrant equivalents, and calls out where the two engines genuinely differ. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md new file mode 100644 index 000000000..697fb150b --- /dev/null +++ b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md @@ -0,0 +1,129 @@ +--- +title: "Design a Collection Schema From a Dataset Description" +short_description: "Describe your data and the searches you need, and get a collection definition: vector configuration, distance metric, payload schema, and the payload indexes to create before you load." +description: "A Qdrant prompt template for greenfield collection design. Turns a dataset description and a set of search requirements into a concrete collection definition, with the vector configuration, distance metric, payload schema, and payload indexes chosen and justified." +weight: 10 +partition: develop +category: authoring +output_contract: config +tags: + - collection-design + - payload-index + - vectors +template_version: 1 +variables: + - name: DATASET_DESCRIPTION + required: true + description: "What the data is, the fields each record has, and roughly how many records." + placeholder: "1.2M support articles: title, body, product, language, updated_at, author_id" + - name: SEARCH_REQUIREMENTS + required: true + description: "The searches you need to serve, including anything you must filter or sort by." + placeholder: "semantic search over body, filtered by product and language, newest first on ties" + - name: EMBEDDING_MODEL + required: false + description: "The model you plan to use, if you've chosen one. Leave blank to have one recommended." + placeholder: "sentence-transformers/all-MiniLM-L6-v2" + - name: SCALE_AND_CONSTRAINTS + required: false + description: "Expected growth, peak QPS, latency target, and memory budget." + placeholder: "growing to 5M in a year, ~200 QPS, p95 under 100 ms, 16 GB RAM" +draws_on: + skills: + - qdrant-search-quality/search-strategies + - qdrant-multitenancy + - qdrant-sizing + docs: + - /documentation/manage-data/collections/ + - /documentation/manage-data/vectors/ + - /documentation/manage-data/indexing/ +--- + +# Design a Collection Schema From a Dataset Description + +Almost every decision in a Qdrant collection is easier to make before you load data than after. Some of them, like shard count, can't be changed later at all without a full reindex. Others, like a distance metric that doesn't match how your model was trained, never raise an error: the collection accepts your vectors and returns results that look reasonable and rank badly. + +This template takes a plain description of your data and the searches you need, and asks your agent to produce a concrete collection definition with every choice justified. It's the day-zero counterpart to [Review a Collection Configuration Before Launch](/documentation/agentic-tools/prompt-templates/review-collection-configuration/), which checks a configuration you already have. + +## The Template + +Fill in the variables, then copy the prompt into your coding assistant. + +{{< prompt-template >}} +You are designing a Qdrant collection from scratch. Produce a concrete definition, not a survey of options. + +Dataset: +{{DATASET_DESCRIPTION}} + +Search requirements: +{{SEARCH_REQUIREMENTS}} + +Embedding model: +{{EMBEDDING_MODEL}} + +Scale and constraints: +{{SCALE_AND_CONSTRAINTS}} + +Decide each of the following. Where the input above doesn't tell you enough, state the assumption you're making and move on rather than stopping. + +1. What gets embedded. Name the field or combination of fields that becomes the vector, and say what stays in the payload only. If records are long enough to need chunking, say so, give a chunk size, and say what identifier links chunks back to the source record. +2. Vector configuration. Choose a single vector or named vectors. Use named vectors if the requirements call for searching more than one representation, for example a title vector and a body vector, or dense plus sparse. Derive the size from the model rather than hardcoding it, using client.get_embedding_size(model_name) where the client supports it. If no model was given, recommend one and say why it fits the data. +3. Distance metric. Qdrant supports Dot, Cosine, Euclid, and Manhattan. Pick the one the model was trained for, and say which. This choice does not fail loudly when it's wrong, so justify it explicitly rather than defaulting to Cosine. +4. Whether sparse vectors are warranted. If the requirements involve exact terms, product codes, identifiers, or rare vocabulary that a dense model will blur, add a sparse named vector and say which searches it serves. If not, say plainly that dense alone is enough. +5. Payload schema. List every dataset field you'd keep, with its type. Flag any field large enough that it should live outside Qdrant with only a reference stored, and say what the reference is. +6. Payload indexes. For every field the requirements filter or sort on, choose the index type: keyword, integer, float, bool, datetime, geo, uuid, or text. Match the type to the operation, not to the field's storage type. A date filtered by range needs a datetime index, not keyword. A field needing substring or phrase matching needs a text index, and you should say which tokenizer. +7. Tenancy. If the data has a per-customer, per-user, or per-workspace dimension, treat it as multitenant: set is_tenant on that field's index, and set m to 0 with payload_m configured so the global vector index isn't built. If it isn't multitenant, say so. +8. Point IDs. Choose unsigned integers or UUIDs, and say how you derive them from the source data so that a re-ingest updates records rather than duplicating them. If the natural key isn't usable as an ID, keep it in the payload with its own index. + +Output four sections. + +Field decisions: a table with columns Field, Role, Payload type, Index, Reason. Role is one of embedded, filter, sort, display, or reference. +Collection definition: the create_collection call followed by every create_payload_index call, in the order to run them. +Choices that can't be changed later: which of your decisions would require recreating the collection or a full reindex to undo. +Assumptions and open questions: what you assumed, and what answer from me would change the design. +{{< /prompt-template >}} + +## What Good Output Looks Like + +The field table should account for every field in your description, and the immutability section should be short and specific. + +```text +## Field decisions +| Field | Role | Payload type | Index | Reason | +|------------|-----------|--------------|-------------------|---------------------------| +| body | embedded | not stored | none | vector source, 1.4 KB avg | +| title | embedded | text | text (word) | second named vector | +| product | filter | keyword | keyword | filtered on every query | +| language | filter | keyword | keyword | 7 values, still selective | +| updated_at | sort | integer | datetime | range and tiebreak | +| author_id | display | keyword | none | never filtered | + +## Collection definition + client.create_collection( + collection_name="articles", + vectors_config={ + "body": models.VectorParams( + size=client.get_embedding_size(MODEL), distance=models.Distance.COSINE), + "title": models.VectorParams( + size=client.get_embedding_size(MODEL), distance=models.Distance.COSINE), + }, + ) + # Cosine: all-MiniLM-L6-v2 is trained with a cosine objective. + client.create_payload_index("articles", "product", field_schema="keyword") + client.create_payload_index("articles", "updated_at", field_schema="datetime") + +## Choices that can't be changed later + 1. Vector size and distance metric. Both require recreating the collection. + 2. Named vector set. Adding a third vector later needs a full re-upload. + +## Assumptions and open questions + 1. Assumed articles are single-language, so no per-language vectors. + 2. Is author_id ever filtered? If yes it needs a keyword index, which is + cheap now and a full reindex of that field later. +``` + +## Related + +- [Collections](/documentation/manage-data/collections/) documents the parameters the output uses, including the four distance metrics. +- [Indexing](/documentation/manage-data/indexing/) covers the payload index types and their tokenizers. +- [Review a Collection Configuration Before Launch](/documentation/agentic-tools/prompt-templates/review-collection-configuration/) checks the result once you've built it. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md index 5c6d69b8b..44205228d 100644 --- a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md +++ b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md @@ -2,7 +2,7 @@ title: "Review a Collection Configuration Before Launch" short_description: "Hand your agent a collection configuration and workload profile, and get a go or no-go checklist covering indexing, quantization, replication, and filter readiness." description: "A Qdrant prompt template for pre-launch collection review. Produces a prioritized checklist of blockers and recommendations across payload indexing, quantization, replication, sharding, and search parameters, based on your actual configuration." -weight: 10 +weight: 20 partition: develop category: review-and-audit output_contract: checklist diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/translate-pinecone-workload.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/translate-pinecone-workload.md deleted file mode 100644 index 2a6e7f5ff..000000000 --- a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/translate-pinecone-workload.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: "Translate a Pinecone Workload to Qdrant" -short_description: "Map a Pinecone index definition, namespaces, metadata filters, and hybrid weighting onto Qdrant equivalents, including the places where the two engines genuinely differ." -description: "A Qdrant prompt template for Pinecone migration. Translates index definitions, namespace tenancy, metadata filters, and alpha-weighted hybrid search into Qdrant collection configuration and query shapes, and flags the semantic differences to verify after cutover." -weight: 20 -partition: develop -category: migration -output_contract: report -tags: - - migration - - pinecone - - multitenancy -template_version: 1 -variables: - - name: PINECONE_INDEX - required: true - description: "Your index definition: dimension, metric, pod or serverless type, replicas, and namespace count." - placeholder: "dim 1536, cosine, p1.x2 with 3 replicas, 240 namespaces" - - name: PINECONE_QUERIES - required: true - description: "Representative queries, including topK, namespace usage, metadata filters, and any hybrid alpha weighting." - placeholder: "topK=20, namespace per customer, filter {tier: {$in: [gold, platinum]}}, alpha=0.7" - - name: SCALE - required: false - description: "Vector count, peak QPS, latency target, and memory budget." - placeholder: "18M vectors, ~450 QPS peak, p95 under 80 ms" - - name: EMBEDDING_MODEL - required: false - description: "The model producing your vectors, and whether you plan to keep it through the migration." - placeholder: "text-embedding-3-small, keeping it for now" -draws_on: - skills: - - qdrant-multitenancy - - qdrant-search-quality/search-strategies/hybrid-search/combining-searches - - qdrant-sizing - docs: - - /documentation/migrate-to-qdrant/pinecone/ - - /documentation/manage-data/multitenancy/ - - /documentation/search/hybrid-queries/ ---- - -# Translate a Pinecone Workload to Qdrant - -A field-by-field port from Pinecone to Qdrant usually compiles and usually returns worse results, because three of Pinecone's core concepts have no direct equivalent. Namespaces are physical partitions, where Qdrant's answer is normally payload-based tenancy in a single collection. Metadata filters are applied differently, so result ordering can shift even when the filter is logically identical. And alpha-weighted hybrid search is a single blended score, where Qdrant uses prefetch plus a fusion step that ignores your weighting entirely. - -This template makes your agent resolve all three explicitly instead of guessing. - -## The Template - -Fill in the variables, then copy the prompt into your coding assistant. - -{{< prompt-template >}} -You are translating a Pinecone workload to Qdrant. Assume the reader knows both systems. Do not re-explain either API. - -Pinecone index definition: -{{PINECONE_INDEX}} - -Representative Pinecone queries: -{{PINECONE_QUERIES}} - -Scale and constraints: -{{SCALE}} - -Embedding model: -{{EMBEDDING_MODEL}} - -Produce the translation. Resolve each of the following rather than glossing over it. - -1. Namespaces. Pinecone namespaces are physical partitions. The usual Qdrant equivalent is one collection with payload-based tenancy and is_tenant set on the partitioning field, not one collection per namespace. Choose a model based on the namespace count and how skewed the data is across them, and state why. If the count is high or growth is unbounded, say what breaks in the alternative. -2. Metadata filters. Map the operators used above onto Qdrant filter clauses. Then note where ordering may shift: Qdrant applies filters during index traversal, so the candidate set differs from Pinecone's, and a filtered query can return a different ranking even when the filter is logically identical. -3. Hybrid search. If any query uses alpha weighting, give the Qdrant query shape as prefetch branches plus a fusion step. Say whether RRF or DBSF matches the intent, and state plainly that neither preserves the alpha weighting, so relevance has to be re-tuned against a ground-truth set after cutover. -4. Sizing. Translate pod or serverless capacity and replica count into RAM, disk, and node count for Qdrant. State every assumption you use, and flag where quantization would be needed to fit a stated memory budget. -5. Index parameters. Choose m, ef_construct, and any quantization settings from the scale and latency target. If you chose payload-based tenancy, set m to 0 and use payload_m. - -Output exactly four sections. - -Collection definition: the create_collection call, with payload index calls. -Query translations: a side-by-side mapping of each representative query to its Qdrant equivalent. -Semantic differences to verify after cutover: numbered, each with the specific check that would catch it. -Open questions: what you needed and did not have, and how each answer would change the design. -{{< /prompt-template >}} - -## What Good Output Looks Like - -The four sections should be concrete, and the differences section should read as a test plan rather than a caveat list. - -```text -## Collection definition - create_collection("prod", vectors_config={...}, - hnsw_config=models.HnswConfigDiff(m=0, payload_m=16)) - create_payload_index("prod", "tenant_id", - models.KeywordIndexParams(type="keyword", is_tenant=True)) - -## Query translations - Pinecone Qdrant - namespace="acme" -> filter must key=tenant_id match acme - filter {"tier": {"$in": -> key=tier match any [gold, platinum] - ["gold","platinum"]}} - alpha=0.7 hybrid -> prefetch dense + sparse, fusion=RRF - -## Semantic differences to verify after cutover - 1. Filtered ranking may differ. Check: run 200 production queries against - both, compare top-10 overlap. Under 0.9 means re-tune, not a bug. - 2. alpha=0.7 has no fusion equivalent. RRF is rank-based and discards the - weighting. Check: measure nDCG@10 on a ground-truth set before cutover. - -## Open questions - 1. Largest namespace as a share of total. Above roughly 20% the single - collection model needs a dedicated shard key. -``` - -## Related - -- [Migrate From Pinecone](/documentation/migrate-to-qdrant/pinecone/) covers the data transfer mechanics this template leaves out. -- [Hybrid Queries](/documentation/search/hybrid-queries/) documents the prefetch and fusion syntax the output uses. From a537f52a44570e1859d655337047e631cbec197e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 10 Sep 2026 10:56:16 +0200 Subject: [PATCH 03/26] Address feedback. --- .../articles/bulk-uploads-in-qdrant.md | 2 +- qdrant-landing/content/blog/qdrant-1.19.x.md | 2 +- .../design-collection-schema.md | 3 +- .../review-collection-configuration.md | 1 - .../css/components/_prompt-template.scss | 7 +- .../qdrant-2024/assets/js/prompt-template.js | 66 ++++++++++++++----- .../qdrant-2024/layouts/partials/js.html | 2 +- .../layouts/shortcodes/prompt-template.html | 14 ++-- 8 files changed, 68 insertions(+), 29 deletions(-) diff --git a/qdrant-landing/content/articles/bulk-uploads-in-qdrant.md b/qdrant-landing/content/articles/bulk-uploads-in-qdrant.md index a3300ef70..b35cdb7f7 100644 --- a/qdrant-landing/content/articles/bulk-uploads-in-qdrant.md +++ b/qdrant-landing/content/articles/bulk-uploads-in-qdrant.md @@ -241,7 +241,7 @@ client.create_collection( ![Decision tree for choosing the right bulk upload strategy: dense, sparse, or hybrid vectors, with memory, quantization, and sharding options](/articles_data/bulk-uploads-in-qdrant/choosing-the-right-mix.png) -Still deciding exactly what to configure for your workload? [Qdrant's Agent Skills](https://qdrant.tech/documentation/skills/) provide hands-on, scenario-based guidance that walks you through the specific settings for your situation. +Still deciding exactly what to configure for your workload? [Qdrant's Agent Skills](https://qdrant.tech/documentation/agentic-tools/skills/) provide hands-on, scenario-based guidance that walks you through the specific settings for your situation. ## It's Not One-Size-Fits-All diff --git a/qdrant-landing/content/blog/qdrant-1.19.x.md b/qdrant-landing/content/blog/qdrant-1.19.x.md index f0940bc8b..6747bffc9 100644 --- a/qdrant-landing/content/blog/qdrant-1.19.x.md +++ b/qdrant-landing/content/blog/qdrant-1.19.x.md @@ -132,7 +132,7 @@ We recommend upgrading versions one by one. Qdrant Cloud does this automatically > If you still use the legacy `/search`, `/recommend`, or `/discover` endpoints, migrate to the [`/query` API](/documentation/search/search/#query-api) before upgrading to 1.19. -Need help with your upgrade? The [Qdrant Advisor agent skill](https://qdrant.tech/documentation/skills/) can help you navigate upgrades, troubleshoot configurations, and answer questions about your Qdrant setup, whether you're on Qdrant Cloud or self-hosting. +Need help with your upgrade? The [Qdrant Advisor agent skill](https://qdrant.tech/documentation/agentic-tools/skills/) can help you navigate upgrades, troubleshoot configurations, and answer questions about your Qdrant setup, whether you're on Qdrant Cloud or self-hosting. ## Engage diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md index 697fb150b..e5aa75206 100644 --- a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md +++ b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md @@ -3,7 +3,6 @@ title: "Design a Collection Schema From a Dataset Description" short_description: "Describe your data and the searches you need, and get a collection definition: vector configuration, distance metric, payload schema, and the payload indexes to create before you load." description: "A Qdrant prompt template for greenfield collection design. Turns a dataset description and a set of search requirements into a concrete collection definition, with the vector configuration, distance metric, payload schema, and payload indexes chosen and justified." weight: 10 -partition: develop category: authoring output_contract: config tags: @@ -95,7 +94,7 @@ The field table should account for every field in your description, and the immu | title | embedded | text | text (word) | second named vector | | product | filter | keyword | keyword | filtered on every query | | language | filter | keyword | keyword | 7 values, still selective | -| updated_at | sort | integer | datetime | range and tiebreak | +| updated_at | sort | datetime | datetime | range and tiebreak | | author_id | display | keyword | none | never filtered | ## Collection definition diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md index 44205228d..55634ec67 100644 --- a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md +++ b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md @@ -3,7 +3,6 @@ title: "Review a Collection Configuration Before Launch" short_description: "Hand your agent a collection configuration and workload profile, and get a go or no-go checklist covering indexing, quantization, replication, and filter readiness." description: "A Qdrant prompt template for pre-launch collection review. Produces a prioritized checklist of blockers and recommendations across payload indexing, quantization, replication, sharding, and search parameters, based on your actual configuration." weight: 20 -partition: develop category: review-and-audit output_contract: checklist tags: diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss index 975463a15..93cba260b 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss @@ -2,7 +2,7 @@ $pt-surface: $neutral-20; $pt-surface-raised: $neutral-30; -$pt-border: $neutral-30; +$pt-border: $neutral-40; $pt-border-strong: $neutral-40; $pt-text: $neutral-98; $pt-text-muted: $neutral-70; @@ -137,6 +137,7 @@ $pt-ready: $secondary-teal-70; } &__copy { + display: none; font-family: $font-family-base; font-size: $font-size-s; font-weight: 500; @@ -157,6 +158,10 @@ $pt-ready: $secondary-teal-70; } } + &--ready &__copy { + display: inline-block; + } + &__body { font-family: $font-family-code; font-size: $font-size-s; diff --git a/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js b/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js index 7a0c8921d..5852c8f99 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js +++ b/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js @@ -5,9 +5,19 @@ * tokens intact. This module takes that text as its source, substitutes the * values you type, and marks whatever is still unresolved. Nothing is fetched, * and nothing is stored. + * + * Blocks separated by a blank line are the unit of resolution. When every + * placeholder in a block belongs to an empty optional variable, the whole block + * is dropped rather than handed to an agent as a literal token. Template + * authors should therefore keep one variable per blank-line-separated block; a + * block mixing a filled required variable with an empty optional one is kept, + * and the optional token stays visible. */ (function () { - const PLACEHOLDER = /\{\{\s*([A-Z0-9_]+)\s*\}\}/g; + const PLACEHOLDER_SRC = '\\{\\{\\s*([A-Z0-9_]+)\\s*\\}\\}'; + + // A fresh regex per use: a shared global one carries lastIndex between calls. + const placeholders = () => new RegExp(PLACEHOLDER_SRC, 'g'); const escapeHtml = (value) => value.replace(/&/g, '&').replace(//g, '>'); @@ -25,6 +35,8 @@ this.inputs = Array.from(root.querySelectorAll('[data-pt-var]')); this.status = root.querySelector('[data-pt-status]'); this.copyBtn = root.querySelector('[data-pt-copy]'); + this.copyLabel = this.copyBtn ? this.copyBtn.textContent : 'Copy'; + this.copyTimer = null; this.inputs.forEach((input) => { input.addEventListener('input', () => this.render()); @@ -34,6 +46,8 @@ this.copyBtn.addEventListener('click', () => this.copy()); } + // Reveals the copy button, which is hidden until the behavior exists. + root.classList.add('prompt-template--ready'); this.render(); } @@ -44,9 +58,28 @@ }, {}); } + /** Optional variables left empty: their blocks come out of the prompt. */ + droppable(values) { + return new Set( + this.inputs + .filter((input) => input.dataset.ptRequired !== 'true') + .map((input) => input.dataset.ptVar) + .filter((name) => !values[name]), + ); + } + resolve() { const values = this.values(); - return this.source.replace(PLACEHOLDER, (token, name) => values[name] || token); + const droppable = this.droppable(values); + + return this.source + .split(/\n{2,}/) + .filter((block) => { + const names = Array.from(block.matchAll(placeholders()), (m) => m[1]); + return !(names.length > 0 && names.every((name) => droppable.has(name))); + }) + .join('\n\n') + .replace(placeholders(), (token, name) => values[name] || token); } missingRequired() { @@ -58,7 +91,7 @@ render() { this.output.innerHTML = escapeHtml(this.resolve()).replace( - PLACEHOLDER, + placeholders(), '$&', ); @@ -80,22 +113,21 @@ } } + flashCopyLabel(text, isError) { + clearTimeout(this.copyTimer); + this.copyBtn.textContent = text; + this.copyBtn.classList.toggle('prompt-template__copy--done', !isError); + + this.copyTimer = setTimeout(() => { + this.copyBtn.textContent = this.copyLabel; + this.copyBtn.classList.remove('prompt-template__copy--done'); + }, 1600); + } + copy() { - const label = this.copyBtn.textContent; - navigator.clipboard.writeText(this.resolve()).then( - () => { - this.copyBtn.textContent = 'Copied'; - this.copyBtn.classList.add('prompt-template__copy--done'); - - setTimeout(() => { - this.copyBtn.textContent = label; - this.copyBtn.classList.remove('prompt-template__copy--done'); - }, 1600); - }, - () => { - this.copyBtn.textContent = 'Press Ctrl+C'; - }, + () => this.flashCopyLabel('Copied', false), + () => this.flashCopyLabel('Copy failed', true), ); } } diff --git a/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html b/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html index 7b88ece46..db13251b0 100644 --- a/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html +++ b/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html @@ -119,7 +119,7 @@ {{/* Prompt templates live under /documentation/, so .Section is "documentation" here and cannot isolate them. Match on the path instead. */}} -{{ if in .RelPermalink "/documentation/agentic-tools/prompt-templates/" }} +{{ if and .IsPage (in .RelPermalink "/documentation/agentic-tools/prompt-templates/") }} {{ $promptTemplateJs := resources.Get "js/prompt-template.js" | js.Build | minify | resources.Fingerprint "sha512" }} {{ end }} diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html index 3406670bc..ac1398e29 100644 --- a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html +++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html @@ -3,13 +3,16 @@ content; the variables come from the page's `variables` front matter. The body is rendered server-side with its {{PLACEHOLDER}} tokens intact, so the - page is complete and copyable without JavaScript. prompt-template.js reads that - text as its source and substitutes values as you type. + page is complete and readable without JavaScript. prompt-template.js reads that + text as its source, substitutes values as you type, and drops blocks whose only + placeholders are empty optional variables. Keep one variable per + blank-line-separated block in the body so that dropping works cleanly. - `without-copy-code` keeps copy-code.js from injecting a second copy button. + The copy button is hidden until the script marks the panel ready, so it is not + offered as a control that does nothing. */ -}} {{- $vars := .Page.Params.variables -}} -
+
{{- with $vars }}

Variables

@@ -23,7 +26,7 @@ Optional {{- end }} -

+

{{ .description }} {{- with .source }}
{{ . }}{{ end }}

@@ -32,6 +35,7 @@ id="pt-{{ .name }}" rows="2" spellcheck="false" + aria-describedby="pt-hint-{{ .name }}" data-pt-var="{{ .name }}" data-pt-required="{{ if .required }}true{{ else }}false{{ end }}" {{ with .placeholder }}placeholder="{{ . }}"{{ end }} From 537d26ef7010b982a0c432eac62c50bcf09ab384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 10 Sep 2026 13:06:00 +0200 Subject: [PATCH 04/26] Refactoring. --- .../documentation/agentic-tools/_index.md | 10 +- .../agentic-tools/prompt-templates/_index.md | 16 -- .../design-collection-schema.md | 128 --------- .../review-collection-configuration.md | 109 -------- .../qdrant-2024/assets/css/_components.scss | 1 - .../css/components/_prompt-template.scss | 257 ------------------ .../qdrant-2024/assets/js/prompt-template.js | 146 ---------- .../qdrant-2024/layouts/partials/js.html | 7 - .../layouts/shortcodes/prompt-template.html | 56 ---- 9 files changed, 2 insertions(+), 728 deletions(-) delete mode 100644 qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md delete mode 100644 qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md delete mode 100644 qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md delete mode 100644 qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss delete mode 100644 qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js delete mode 100644 qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html diff --git a/qdrant-landing/content/documentation/agentic-tools/_index.md b/qdrant-landing/content/documentation/agentic-tools/_index.md index 449a5098b..fcc1f0362 100644 --- a/qdrant-landing/content/documentation/agentic-tools/_index.md +++ b/qdrant-landing/content/documentation/agentic-tools/_index.md @@ -1,7 +1,7 @@ --- title: "Agentic Tools" -short_description: "Tools that help AI coding assistants work with Qdrant: agent skills for diagnosis and tuning, and prompt templates for design, migration, evaluation, and review." -description: "Qdrant agentic tools for AI coding assistants. Agent skills give your agent solutions architect knowledge on demand. Prompt templates give you task-shaped prompts for designing collections, migrating from other engines, evaluating search quality, and reviewing configurations." +short_description: "Tools that help AI coding assistants work with Qdrant: a prompt to get started, and agent skills that carry solutions architect knowledge into your agent." +description: "Qdrant agentic tools for AI coding assistants. Start from a single prompt that runs Qdrant locally and installs the Qdrant Advisor, then use agent skills to diagnose and tune search, memory, scaling, and relevance in a running deployment." weight: 303 partition: develop --- @@ -55,9 +55,3 @@ A wrong collection configuration rarely fails loudly in vector search: a mismatc [Agent skills](/documentation/agentic-tools/skills/) encode solutions architect knowledge as structured files your agent loads on demand. They're organized around symptoms, so they answer "why is this happening, and what should I check first?" Reach for skills when something is already running and behaving unexpectedly: slow search, growing memory, a stuck optimizer, poor relevance. - -## Prompt Template Library - -The [prompt template library](/documentation/agentic-tools/prompt-templates/) is a set of task-shaped prompts you fill in and hand to your agent. -They answer "how do I get a correct result for my specific case?" -Reach for templates when you're designing something new, moving from another engine, measuring whether search actually works, or reviewing a configuration before it ships. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md deleted file mode 100644 index a820063a3..000000000 --- a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/_index.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: "Prompt Template Library" -short_description: "Task-shaped prompts for designing, evaluating, and reviewing Qdrant collections. Fill in the variables, hand the result to your coding agent." -description: "A curated library of Qdrant prompt templates. Each template takes your data, configuration, and workload as input and produces a structured result: a collection definition, a pre-launch review, or a payload index audit." -weight: 20 -partition: develop ---- - -# Prompt Template Library - -Vector search is unusual in that a wrong configuration returns plausible results instead of an error, so the hard questions are rarely about syntax. Each template here takes your real configuration and workload as input, tells your agent what to check and what shape to answer in, and points at the [agent skills](/documentation/agentic-tools/skills/) that own the underlying reasoning. Fill in the variables, copy the prompt, and hand it to your coding assistant. - -## Templates - -- [Design a Collection Schema From a Dataset Description](/documentation/agentic-tools/prompt-templates/design-collection-schema/) turns a description of your data and the searches you need into a collection definition, with the vector configuration, distance metric, payload schema, and payload indexes chosen and justified. -- [Review a Collection Configuration Before Launch](/documentation/agentic-tools/prompt-templates/review-collection-configuration/) produces a go or no-go checklist over indexing, quantization, replication, and filter readiness for a collection about to take production traffic. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md deleted file mode 100644 index e5aa75206..000000000 --- a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/design-collection-schema.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: "Design a Collection Schema From a Dataset Description" -short_description: "Describe your data and the searches you need, and get a collection definition: vector configuration, distance metric, payload schema, and the payload indexes to create before you load." -description: "A Qdrant prompt template for greenfield collection design. Turns a dataset description and a set of search requirements into a concrete collection definition, with the vector configuration, distance metric, payload schema, and payload indexes chosen and justified." -weight: 10 -category: authoring -output_contract: config -tags: - - collection-design - - payload-index - - vectors -template_version: 1 -variables: - - name: DATASET_DESCRIPTION - required: true - description: "What the data is, the fields each record has, and roughly how many records." - placeholder: "1.2M support articles: title, body, product, language, updated_at, author_id" - - name: SEARCH_REQUIREMENTS - required: true - description: "The searches you need to serve, including anything you must filter or sort by." - placeholder: "semantic search over body, filtered by product and language, newest first on ties" - - name: EMBEDDING_MODEL - required: false - description: "The model you plan to use, if you've chosen one. Leave blank to have one recommended." - placeholder: "sentence-transformers/all-MiniLM-L6-v2" - - name: SCALE_AND_CONSTRAINTS - required: false - description: "Expected growth, peak QPS, latency target, and memory budget." - placeholder: "growing to 5M in a year, ~200 QPS, p95 under 100 ms, 16 GB RAM" -draws_on: - skills: - - qdrant-search-quality/search-strategies - - qdrant-multitenancy - - qdrant-sizing - docs: - - /documentation/manage-data/collections/ - - /documentation/manage-data/vectors/ - - /documentation/manage-data/indexing/ ---- - -# Design a Collection Schema From a Dataset Description - -Almost every decision in a Qdrant collection is easier to make before you load data than after. Some of them, like shard count, can't be changed later at all without a full reindex. Others, like a distance metric that doesn't match how your model was trained, never raise an error: the collection accepts your vectors and returns results that look reasonable and rank badly. - -This template takes a plain description of your data and the searches you need, and asks your agent to produce a concrete collection definition with every choice justified. It's the day-zero counterpart to [Review a Collection Configuration Before Launch](/documentation/agentic-tools/prompt-templates/review-collection-configuration/), which checks a configuration you already have. - -## The Template - -Fill in the variables, then copy the prompt into your coding assistant. - -{{< prompt-template >}} -You are designing a Qdrant collection from scratch. Produce a concrete definition, not a survey of options. - -Dataset: -{{DATASET_DESCRIPTION}} - -Search requirements: -{{SEARCH_REQUIREMENTS}} - -Embedding model: -{{EMBEDDING_MODEL}} - -Scale and constraints: -{{SCALE_AND_CONSTRAINTS}} - -Decide each of the following. Where the input above doesn't tell you enough, state the assumption you're making and move on rather than stopping. - -1. What gets embedded. Name the field or combination of fields that becomes the vector, and say what stays in the payload only. If records are long enough to need chunking, say so, give a chunk size, and say what identifier links chunks back to the source record. -2. Vector configuration. Choose a single vector or named vectors. Use named vectors if the requirements call for searching more than one representation, for example a title vector and a body vector, or dense plus sparse. Derive the size from the model rather than hardcoding it, using client.get_embedding_size(model_name) where the client supports it. If no model was given, recommend one and say why it fits the data. -3. Distance metric. Qdrant supports Dot, Cosine, Euclid, and Manhattan. Pick the one the model was trained for, and say which. This choice does not fail loudly when it's wrong, so justify it explicitly rather than defaulting to Cosine. -4. Whether sparse vectors are warranted. If the requirements involve exact terms, product codes, identifiers, or rare vocabulary that a dense model will blur, add a sparse named vector and say which searches it serves. If not, say plainly that dense alone is enough. -5. Payload schema. List every dataset field you'd keep, with its type. Flag any field large enough that it should live outside Qdrant with only a reference stored, and say what the reference is. -6. Payload indexes. For every field the requirements filter or sort on, choose the index type: keyword, integer, float, bool, datetime, geo, uuid, or text. Match the type to the operation, not to the field's storage type. A date filtered by range needs a datetime index, not keyword. A field needing substring or phrase matching needs a text index, and you should say which tokenizer. -7. Tenancy. If the data has a per-customer, per-user, or per-workspace dimension, treat it as multitenant: set is_tenant on that field's index, and set m to 0 with payload_m configured so the global vector index isn't built. If it isn't multitenant, say so. -8. Point IDs. Choose unsigned integers or UUIDs, and say how you derive them from the source data so that a re-ingest updates records rather than duplicating them. If the natural key isn't usable as an ID, keep it in the payload with its own index. - -Output four sections. - -Field decisions: a table with columns Field, Role, Payload type, Index, Reason. Role is one of embedded, filter, sort, display, or reference. -Collection definition: the create_collection call followed by every create_payload_index call, in the order to run them. -Choices that can't be changed later: which of your decisions would require recreating the collection or a full reindex to undo. -Assumptions and open questions: what you assumed, and what answer from me would change the design. -{{< /prompt-template >}} - -## What Good Output Looks Like - -The field table should account for every field in your description, and the immutability section should be short and specific. - -```text -## Field decisions -| Field | Role | Payload type | Index | Reason | -|------------|-----------|--------------|-------------------|---------------------------| -| body | embedded | not stored | none | vector source, 1.4 KB avg | -| title | embedded | text | text (word) | second named vector | -| product | filter | keyword | keyword | filtered on every query | -| language | filter | keyword | keyword | 7 values, still selective | -| updated_at | sort | datetime | datetime | range and tiebreak | -| author_id | display | keyword | none | never filtered | - -## Collection definition - client.create_collection( - collection_name="articles", - vectors_config={ - "body": models.VectorParams( - size=client.get_embedding_size(MODEL), distance=models.Distance.COSINE), - "title": models.VectorParams( - size=client.get_embedding_size(MODEL), distance=models.Distance.COSINE), - }, - ) - # Cosine: all-MiniLM-L6-v2 is trained with a cosine objective. - client.create_payload_index("articles", "product", field_schema="keyword") - client.create_payload_index("articles", "updated_at", field_schema="datetime") - -## Choices that can't be changed later - 1. Vector size and distance metric. Both require recreating the collection. - 2. Named vector set. Adding a third vector later needs a full re-upload. - -## Assumptions and open questions - 1. Assumed articles are single-language, so no per-language vectors. - 2. Is author_id ever filtered? If yes it needs a keyword index, which is - cheap now and a full reindex of that field later. -``` - -## Related - -- [Collections](/documentation/manage-data/collections/) documents the parameters the output uses, including the four distance metrics. -- [Indexing](/documentation/manage-data/indexing/) covers the payload index types and their tokenizers. -- [Review a Collection Configuration Before Launch](/documentation/agentic-tools/prompt-templates/review-collection-configuration/) checks the result once you've built it. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md b/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md deleted file mode 100644 index 55634ec67..000000000 --- a/qdrant-landing/content/documentation/agentic-tools/prompt-templates/review-collection-configuration.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: "Review a Collection Configuration Before Launch" -short_description: "Hand your agent a collection configuration and workload profile, and get a go or no-go checklist covering indexing, quantization, replication, and filter readiness." -description: "A Qdrant prompt template for pre-launch collection review. Produces a prioritized checklist of blockers and recommendations across payload indexing, quantization, replication, sharding, and search parameters, based on your actual configuration." -weight: 20 -category: review-and-audit -output_contract: checklist -tags: - - review - - production-readiness - - payload-index -template_version: 1 -variables: - - name: COLLECTION_CONFIG - required: true - description: "The full configuration of the collection you're about to launch." - source: "curl -s $QDRANT_URL/collections/COLLECTION | jq .result" - placeholder: "vectors: {size: 1024, distance: Cosine}, optimizers_config: {...}" - - name: WORKLOAD_PROFILE - required: true - description: "Point count, expected QPS, latency target, and the filters your queries actually use." - placeholder: "12M points, ~300 QPS peak, p95 target 100 ms, filters on tenant_id and created_at" - - name: DEPLOYMENT_TARGET - required: false - description: "Node count, RAM and disk per node, and whether this is Qdrant Cloud, Hybrid Cloud, or self-hosted." - placeholder: "3 nodes, 32 GB RAM each, self-hosted on Kubernetes" - - name: LAUNCH_CONSTRAINTS - required: false - description: "Anything that limits your options, such as a fixed memory budget or a no-downtime requirement." - placeholder: "cannot exceed 32 GB per node; no downtime during cutover" -draws_on: - skills: - - qdrant-performance-optimization/search-speed-optimization - - qdrant-performance-optimization/memory-usage-optimization - - qdrant-sizing - - qdrant-multitenancy - docs: - - /documentation/production-checklist/ - - /documentation/manage-data/indexing/ - - /documentation/manage-data/quantization/ ---- - -# Review a Collection Configuration Before Launch - -A collection that works in staging can fail in production for reasons that never surface in a test suite: a filter field with no payload index, a replication factor of 1 on a cluster you expect to survive a node loss, or a quantization setting that quietly costs you recall. This template hands your agent the actual configuration and the workload it is about to take, and asks for a prioritized verdict rather than general advice. - -Use it once the configuration is settled but before real traffic arrives. For a collection that's already live and misbehaving, the [agent skills](/documentation/agentic-tools/skills/) are the better starting point, because they're organized around symptoms. - -## The Template - -Fill in the variables, then copy the prompt into your coding assistant. - -{{< prompt-template >}} -You are reviewing a Qdrant collection configuration before it takes production traffic. Report findings only. Do not explain how Qdrant works. - -Collection configuration: -{{COLLECTION_CONFIG}} - -Workload profile: -{{WORKLOAD_PROFILE}} - -Deployment target: -{{DEPLOYMENT_TARGET}} - -Launch constraints: -{{LAUNCH_CONSTRAINTS}} - -Check each of the following against the configuration and workload above. For each one, decide whether it's a blocker, a recommendation, or already correct. - -1. Payload indexes. Every field used in a filter needs an index whose type matches how it's filtered. Flag filter fields with no index, and flag indexes on fields too low in cardinality to be selective. If the workload is multitenant, check whether is_tenant is set on the partitioning field. -2. Vector index parameters. Check m and ef_construct against the point count and latency target. For a multitenant collection, check whether m is set to 0 with payload_m set instead, so the global index isn't built. -3. Quantization. Decide whether the memory budget requires it. If quantization is already configured, check that rescore and oversampling are set consistently with the recall the workload needs, and say what recall loss to expect. -4. Memory and disk. Estimate resident memory for vectors, payload indexes, and the vector index, then compare against the deployment target. State the assumptions behind the estimate. -5. Replication and sharding. Check the replication factor against the stated failure tolerance, and the shard count against node count and expected growth. Flag a shard count that can't be changed later without a full reindex. -6. Optimizer and write path. Check indexing_threshold, memmap_threshold, and default_segment_number against the ingestion pattern, and say whether the initial bulk load should use different settings from steady state. -7. Consistency and durability. Check write_consistency_factor and the on-disk settings against the durability the workload requires. - -Then look for anything that's wrong but not on this list. - -Output a table with columns: Area, Severity, Finding, Action. Use severity values Blocker, Recommended, or OK. Sort blockers first. Omit rows that are OK unless there are no blockers at all. - -After the table, output the exact API or client calls needed to resolve every blocker, in the order they should be applied. Note which of them require a collection recreation rather than an update. - -End with one line: ship or do not ship. -{{< /prompt-template >}} - -## What Good Output Looks Like - -The table should be short and specific, with severities you can act on and no restatement of the configuration you supplied. - -```text -| Area | Severity | Finding | Action | -|----------------|-------------|--------------------------------------|---------------------------| -| Payload index | Blocker | tenant_id filtered, no index | create keyword index | -| Sharding | Blocker | 1 shard, 12M points, growth expected | recreate with 4 shards | -| Vector index | Recommended | m=16 global on multitenant set | m=0, payload_m=16 | - -Blocker resolution, in order: - 1. client.create_payload_index(..., field_schema=models.KeywordIndexParams( - type="keyword", is_tenant=True)) # update, no downtime - 2. Shard count change requires recreation. # plan a cutover - -Do not ship. -``` - -## Related - -- [Production Checklist](/documentation/production-checklist/) covers the same ground as prose you read yourself. -- The `qdrant-sizing` and `qdrant-performance-optimization` [agent skills](/documentation/agentic-tools/skills/) own the reasoning behind the memory and latency findings. diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss b/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss index 0071c0f5e..6e1a8ed23 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss @@ -11,4 +11,3 @@ @import 'components/accordion'; @import 'components/course-card'; @import 'components/date'; -@import 'components/prompt-template'; diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss deleted file mode 100644 index 93cba260b..000000000 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt-template.scss +++ /dev/null @@ -1,257 +0,0 @@ -@use '../helpers/functions' as *; - -$pt-surface: $neutral-20; -$pt-surface-raised: $neutral-30; -$pt-border: $neutral-40; -$pt-border-strong: $neutral-40; -$pt-text: $neutral-98; -$pt-text-muted: $neutral-70; -$pt-accent: $primary-60; -$pt-ready: $secondary-teal-70; - -.prompt-template { - display: flex; - flex-direction: column; - gap: pxToRem(24); - margin: pxToRem(24) 0 pxToRem(32); - - &__vars { - background: $pt-surface; - border: 1px solid $pt-border; - border-radius: pxToRem(8); - padding: pxToRem(20); - } - - &__vars-title { - font-size: $font-size-xs; - font-weight: 600; - letter-spacing: 0.07em; - text-transform: uppercase; - color: $pt-text-muted; - margin: 0 0 pxToRem(16); - } - - &__field + &__field { - margin-top: pxToRem(20); - } - - &__label { - display: flex; - align-items: baseline; - gap: pxToRem(8); - margin-bottom: pxToRem(4); - - code { - font-family: $font-family-code; - font-size: $font-size-s; - color: $pt-text; - background: none; - padding: 0; - } - } - - &__flag { - font-size: pxToRem(11); - letter-spacing: 0.04em; - color: $pt-text-muted; - - &--req { - color: $pt-accent; - font-weight: 600; - } - } - - &__field--filled &__label code { - color: $pt-ready; - } - - &__hint { - font-size: $font-size-s; - color: $pt-text-muted; - margin: 0 0 pxToRem(8); - line-height: 1.45; - - code { - font-family: $font-family-code; - font-size: pxToRem(12); - background: $pt-surface-raised; - border-radius: pxToRem(3); - padding: pxToRem(1) pxToRem(5); - color: $pt-text-muted; - } - } - - &__input { - width: 100%; - font-family: $font-family-code; - font-size: $font-size-s; - line-height: 1.5; - color: $pt-text; - background: $neutral-10; - border: 1px solid $pt-border-strong; - border-radius: pxToRem(6); - padding: pxToRem(9) pxToRem(11); - resize: vertical; - - &:focus { - outline: 2px solid $pt-accent; - outline-offset: -1px; - border-color: $pt-accent; - } - } - - &__status { - font-size: $font-size-s; - color: $pt-text-muted; - margin: pxToRem(16) 0 0; - padding-top: pxToRem(12); - border-top: 1px solid $pt-border; - - &--ready { - color: $pt-ready; - } - } - - &__output { - border: 1px solid $pt-border; - border-radius: pxToRem(8); - overflow: hidden; - } - - &__bar { - display: flex; - align-items: center; - justify-content: space-between; - gap: pxToRem(12); - padding: pxToRem(10) pxToRem(16); - background: $pt-surface-raised; - border-bottom: 1px solid $pt-border; - } - - &__bar-title { - font-size: $font-size-xs; - font-weight: 600; - letter-spacing: 0.07em; - text-transform: uppercase; - color: $pt-text-muted; - } - - &__copy { - display: none; - font-family: $font-family-base; - font-size: $font-size-s; - font-weight: 500; - color: $pt-text; - background: none; - border: 1px solid $pt-border-strong; - border-radius: pxToRem(6); - padding: pxToRem(5) pxToRem(14); - cursor: pointer; - - &:hover { - border-color: $pt-text-muted; - } - - &--done { - color: $pt-ready; - border-color: $pt-ready; - } - } - - &--ready &__copy { - display: inline-block; - } - - &__body { - font-family: $font-family-code; - font-size: $font-size-s; - line-height: 1.65; - white-space: pre-wrap; - word-break: break-word; - background: $pt-surface; - color: $pt-text; - margin: 0; - padding: pxToRem(16); - max-height: pxToRem(560); - overflow: auto; - } - - &__ph { - color: $pt-accent; - font-weight: 500; - border: 1px dashed $pt-accent; - border-radius: pxToRem(3); - padding: 0 pxToRem(3); - } - - [data-theme='light'] & { - &__vars, - &__body { - background: $neutral-98; - } - - &__vars, - &__output { - border-color: $neutral-94; - } - - &__bar { - background: $neutral-94; - border-bottom-color: $neutral-90; - } - - &__status { - border-top-color: $neutral-94; - } - - &__input { - background: $neutral-100; - border-color: $neutral-90; - color: $neutral-10; - } - - &__label code, - &__body, - &__copy { - color: $neutral-10; - } - - &__hint, - &__vars-title, - &__bar-title, - &__flag, - &__status { - color: $neutral-50; - } - - &__hint code { - background: $neutral-94; - color: $neutral-50; - } - - &__flag--req, - &__ph { - color: $primary-40; - } - - &__ph { - border-color: $primary-40; - } - - &__status--ready, - &__copy--done { - color: $secondary-teal-30; - } - - &__copy--done { - border-color: $secondary-teal-30; - } - } -} - -// Written out rather than nested: inside a compound `&__a &__b` selector, -// `[data-theme='light'] &` would land in the descendant position and never -// match, because the theme attribute sits on . -[data-theme='light'] .prompt-template__field--filled .prompt-template__label code { - color: $secondary-teal-30; -} diff --git a/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js b/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js deleted file mode 100644 index 5852c8f99..000000000 --- a/qdrant-landing/themes/qdrant-2024/assets/js/prompt-template.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Fillable prompt templates (/documentation/agentic-tools/prompt-templates/). - * - * The shortcode renders the prompt body server-side with its {{PLACEHOLDER}} - * tokens intact. This module takes that text as its source, substitutes the - * values you type, and marks whatever is still unresolved. Nothing is fetched, - * and nothing is stored. - * - * Blocks separated by a blank line are the unit of resolution. When every - * placeholder in a block belongs to an empty optional variable, the whole block - * is dropped rather than handed to an agent as a literal token. Template - * authors should therefore keep one variable per blank-line-separated block; a - * block mixing a filled required variable with an empty optional one is kept, - * and the optional token stays visible. - */ -(function () { - const PLACEHOLDER_SRC = '\\{\\{\\s*([A-Z0-9_]+)\\s*\\}\\}'; - - // A fresh regex per use: a shared global one carries lastIndex between calls. - const placeholders = () => new RegExp(PLACEHOLDER_SRC, 'g'); - - const escapeHtml = (value) => - value.replace(/&/g, '&').replace(//g, '>'); - - class PromptTemplate { - constructor(root) { - this.root = root; - this.output = root.querySelector('[data-pt-output]'); - - if (!this.output) return; - - // The server-rendered body is the source of truth, read once before any - // substitution happens. - this.source = this.output.textContent; - this.inputs = Array.from(root.querySelectorAll('[data-pt-var]')); - this.status = root.querySelector('[data-pt-status]'); - this.copyBtn = root.querySelector('[data-pt-copy]'); - this.copyLabel = this.copyBtn ? this.copyBtn.textContent : 'Copy'; - this.copyTimer = null; - - this.inputs.forEach((input) => { - input.addEventListener('input', () => this.render()); - }); - - if (this.copyBtn) { - this.copyBtn.addEventListener('click', () => this.copy()); - } - - // Reveals the copy button, which is hidden until the behavior exists. - root.classList.add('prompt-template--ready'); - this.render(); - } - - values() { - return this.inputs.reduce((acc, input) => { - acc[input.dataset.ptVar] = input.value.trim(); - return acc; - }, {}); - } - - /** Optional variables left empty: their blocks come out of the prompt. */ - droppable(values) { - return new Set( - this.inputs - .filter((input) => input.dataset.ptRequired !== 'true') - .map((input) => input.dataset.ptVar) - .filter((name) => !values[name]), - ); - } - - resolve() { - const values = this.values(); - const droppable = this.droppable(values); - - return this.source - .split(/\n{2,}/) - .filter((block) => { - const names = Array.from(block.matchAll(placeholders()), (m) => m[1]); - return !(names.length > 0 && names.every((name) => droppable.has(name))); - }) - .join('\n\n') - .replace(placeholders(), (token, name) => values[name] || token); - } - - missingRequired() { - const values = this.values(); - return this.inputs - .filter((input) => input.dataset.ptRequired === 'true' && !values[input.dataset.ptVar]) - .map((input) => input.dataset.ptVar); - } - - render() { - this.output.innerHTML = escapeHtml(this.resolve()).replace( - placeholders(), - '$&', - ); - - this.inputs.forEach((input) => { - const field = this.root.querySelector(`[data-pt-field="${input.dataset.ptVar}"]`); - if (field) field.classList.toggle('prompt-template__field--filled', !!input.value.trim()); - }); - - if (!this.status) return; - - const missing = this.missingRequired(); - - if (missing.length === 0) { - this.status.textContent = 'All required variables resolved.'; - this.status.classList.add('prompt-template__status--ready'); - } else { - this.status.textContent = `Still unresolved: ${missing.join(', ')}`; - this.status.classList.remove('prompt-template__status--ready'); - } - } - - flashCopyLabel(text, isError) { - clearTimeout(this.copyTimer); - this.copyBtn.textContent = text; - this.copyBtn.classList.toggle('prompt-template__copy--done', !isError); - - this.copyTimer = setTimeout(() => { - this.copyBtn.textContent = this.copyLabel; - this.copyBtn.classList.remove('prompt-template__copy--done'); - }, 1600); - } - - copy() { - navigator.clipboard.writeText(this.resolve()).then( - () => this.flashCopyLabel('Copied', false), - () => this.flashCopyLabel('Copy failed', true), - ); - } - } - - const init = () => { - document.querySelectorAll('[data-prompt-template]').forEach((root) => { - new PromptTemplate(root); - }); - }; - - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', init); - } else { - init(); - } -})(); diff --git a/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html b/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html index db13251b0..4edb8fdf1 100644 --- a/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html +++ b/qdrant-landing/themes/qdrant-2024/layouts/partials/js.html @@ -117,13 +117,6 @@ {{ end }} -{{/* Prompt templates live under /documentation/, so .Section is "documentation" - here and cannot isolate them. Match on the path instead. */}} -{{ if and .IsPage (in .RelPermalink "/documentation/agentic-tools/prompt-templates/") }} - {{ $promptTemplateJs := resources.Get "js/prompt-template.js" | js.Build | minify | resources.Fingerprint "sha512" }} - -{{ end }} - {{ if in (slice "customers" "demo") .Section }} {{ $catalogFiltersJs := resources.Get "js/catalog-filters.js" | js.Build | minify | resources.Fingerprint "sha512" }} diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html deleted file mode 100644 index ac1398e29..000000000 --- a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-template.html +++ /dev/null @@ -1,56 +0,0 @@ -{{- /* - Renders a fillable prompt template. The prompt body is this shortcode's Inner - content; the variables come from the page's `variables` front matter. - - The body is rendered server-side with its {{PLACEHOLDER}} tokens intact, so the - page is complete and readable without JavaScript. prompt-template.js reads that - text as its source, substitutes values as you type, and drops blocks whose only - placeholders are empty optional variables. Keep one variable per - blank-line-separated block in the body so that dropping works cleanly. - - The copy button is hidden until the script marks the panel ready, so it is not - offered as a control that does nothing. -*/ -}} -{{- $vars := .Page.Params.variables -}} -
- {{- with $vars }} -
-

Variables

- {{- range . }} -
- -

- {{ .description }} - {{- with .source }}
{{ . }}{{ end }} -

- -
- {{- end }} -

-
- {{- end }} - -
-
- Prompt - -
-
{{ .Inner | htmlEscape | safeHTML }}
-
-
From f46e0d4770e896aedbe08e88bef265100741397e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 10 Sep 2026 15:16:24 +0200 Subject: [PATCH 05/26] Add first prompt, new CI check, and CSS. --- .../documentation/agentic-tools/_index.md | 28 +---- .../documentation/headless/prompts/_index.md | 16 +++ .../headless/prompts/set-up-monitoring.md | 11 ++ .../headless/prompts/start-building.md | 30 +++++ .../ops-monitoring/monitoring.md | 4 + .../layouts/shortcodes/prompt.markdown.md | 16 +++ .../qdrant-2024/assets/css/_components.scss | 1 + .../assets/css/components/_prompt.scss | 117 ++++++++++++++++++ .../layouts/shortcodes/prompt.html | 35 ++++++ 9 files changed, 231 insertions(+), 27 deletions(-) create mode 100644 qdrant-landing/content/documentation/headless/prompts/_index.md create mode 100644 qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md create mode 100644 qdrant-landing/content/documentation/headless/prompts/start-building.md create mode 100644 qdrant-landing/layouts/shortcodes/prompt.markdown.md create mode 100644 qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss create mode 100644 qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html diff --git a/qdrant-landing/content/documentation/agentic-tools/_index.md b/qdrant-landing/content/documentation/agentic-tools/_index.md index fcc1f0362..a745f1b9e 100644 --- a/qdrant-landing/content/documentation/agentic-tools/_index.md +++ b/qdrant-landing/content/documentation/agentic-tools/_index.md @@ -16,33 +16,7 @@ Use them to give your agent task-specific guidance, troubleshoot existing deploy If you're new to Qdrant, paste this into your coding assistant. It stands up a local instance, installs the client with local embeddings, adds the [Qdrant Advisor](/documentation/agentic-tools/skills/#the-qdrant-advisor) skill, and then builds against your own use case. -```text -Help me get started building on Qdrant. - -1. Start Qdrant locally with Docker. No signup and no API key needed: - docker run -p 6333:6333 -p 6334:6334 \ - -v "$(pwd)/qdrant_storage:/qdrant/storage:z" \ - qdrant/qdrant - Confirm it's running at http://localhost:6333/dashboard - -2. Install the client with local embeddings, so I don't need an - embedding provider key either: - pip install "qdrant-client[fastembed]" - -3. Install the Qdrant Advisor agent skill: - npx skills add qdrant/skills/meta/qdrant-advisor - -4. Then ask me what I'm building and what I'll search over before you - write any code. Once you know, build the integration against my - local instance, and get the collection right the first time: - - Derive the vector size from the model with - client.get_embedding_size(model_name). Never hardcode a dimension. - - Choose the distance metric the model was trained for, and say - which one you picked and why. - - Create a payload index for every field I'll filter on, before I - load data rather than after. - Then load a small sample, run a real query, and show me the results. -``` +{{< prompt "start-building" >}} Nothing in those four steps needs an account. Qdrant runs in Docker and [FastEmbed](/documentation/fastembed/fastembed-quickstart/) generates embeddings on your machine, so you can go from nothing to a working search query without signing up for anything. diff --git a/qdrant-landing/content/documentation/headless/prompts/_index.md b/qdrant-landing/content/documentation/headless/prompts/_index.md new file mode 100644 index 000000000..9fcf4e65a --- /dev/null +++ b/qdrant-landing/content/documentation/headless/prompts/_index.md @@ -0,0 +1,16 @@ +--- +title: "Prompts" +# The parent headless bundle cascades `list: never`, which makes this section +# unreachable via site.GetPage and leaves the prompt index empty. `list: local` +# keeps these pages out of site-wide collections while still allowing the +# section's .RegularPages to be ranged over. They are never published as URLs. +build: + list: local + render: never + publishResources: false +cascade: +- build: + list: local + render: never + publishResources: false +--- diff --git a/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md b/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md new file mode 100644 index 000000000..4d7e493a9 --- /dev/null +++ b/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md @@ -0,0 +1,11 @@ +--- +title: "Set up monitoring with an AI agent" +skill: qdrant-monitoring/setup +page: /documentation/ops-monitoring/monitoring/ +--- +Help me set up monitoring for my Qdrant deployment. Read +https://skills.qdrant.tech/qdrant-monitoring/setup/SKILL.md first, then ask me +whether I am self-hosted, on Qdrant Cloud, or on Hybrid Cloud, since the scrape +setup differs. Give me the Prometheus scrape config, the health probes worth +wiring up, and the three or four alerts that would actually have caught a real +incident. Tell me which metrics to ignore. diff --git a/qdrant-landing/content/documentation/headless/prompts/start-building.md b/qdrant-landing/content/documentation/headless/prompts/start-building.md new file mode 100644 index 000000000..496fded53 --- /dev/null +++ b/qdrant-landing/content/documentation/headless/prompts/start-building.md @@ -0,0 +1,30 @@ +--- +title: "Start building with an AI agent" +page: /documentation/agentic-tools/ +open: true +--- +Help me get started building on Qdrant. + +1. Start Qdrant locally with Docker. No signup and no API key needed: + docker run -p 6333:6333 -p 6334:6334 \ + -v "$(pwd)/qdrant_storage:/qdrant/storage:z" \ + qdrant/qdrant + Confirm it's running at http://localhost:6333/dashboard + +2. Install the client with local embeddings, so I don't need an + embedding provider key either: + pip install "qdrant-client[fastembed]" + +3. Install the Qdrant Advisor agent skill: + npx skills add qdrant/skills/meta/qdrant-advisor + +4. Then ask me what I'm building and what I'll search over before you + write any code. Once you know, build the integration against my + local instance, and get the collection right the first time: + - Derive the vector size from the model with + client.get_embedding_size(model_name). Never hardcode a dimension. + - Choose the distance metric the model was trained for, and say + which one you picked and why. + - Create a payload index for every field I'll filter on, before I + load data rather than after. + Then load a small sample, run a real query, and show me the results. diff --git a/qdrant-landing/content/documentation/ops-monitoring/monitoring.md b/qdrant-landing/content/documentation/ops-monitoring/monitoring.md index 314e77c9c..3ddbbdb84 100644 --- a/qdrant-landing/content/documentation/ops-monitoring/monitoring.md +++ b/qdrant-landing/content/documentation/ops-monitoring/monitoring.md @@ -21,6 +21,10 @@ The integration with Qdrant is easy to [configure](https://prometheus.io/docs/prometheus/latest/getting_started/#configure-prometheus-to-monitor-the-sample-targets) with Prometheus and Grafana. +If you would rather have an agent do this, the prompt below asks it to pick the right scrape setup for your deployment type and propose alerts worth having. + +{{< prompt "set-up-monitoring" >}} + ## Metrics Qdrant exposes various metrics in Prometheus/OpenMetrics format, commonly used together with Grafana for monitoring. diff --git a/qdrant-landing/layouts/shortcodes/prompt.markdown.md b/qdrant-landing/layouts/shortcodes/prompt.markdown.md new file mode 100644 index 000000000..dd56b4db0 --- /dev/null +++ b/qdrant-landing/layouts/shortcodes/prompt.markdown.md @@ -0,0 +1,16 @@ +{{- /* + Markdown output variant of the `prompt` shortcode. + + The prompt body is deliberately omitted. An index.md file is consumed by + agents, and a prompt is written in the imperative first person, so including + it risks an agent following the prompt instead of answering the question it + was actually asked. The skill pointer survives, because that is the part with + genuine value to an agent. +*/ -}} +{{- $id := .Get 0 -}} +{{- $p := site.GetPage (printf "documentation/headless/prompts/%s" $id) -}} +{{- with $p -}} + {{- with .Params.skill }} +> Related agent skill: https://skills.qdrant.tech/{{ . }}/SKILL.md +{{ end -}} +{{- end -}} diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss b/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss index 6e1a8ed23..cd2db516f 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/_components.scss @@ -11,3 +11,4 @@ @import 'components/accordion'; @import 'components/course-card'; @import 'components/date'; +@import 'components/prompt'; diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss new file mode 100644 index 000000000..5932674b2 --- /dev/null +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -0,0 +1,117 @@ +@use '../helpers/functions' as *; + +$prompt-surface: $neutral-20; +$prompt-border: $neutral-40; +$prompt-text: $neutral-98; +$prompt-text-muted: $neutral-70; +$prompt-accent: $primary-60; + +.prompt { + background: $prompt-surface; + border: 1px solid $prompt-border; + border-left: 3px solid $prompt-accent; + border-radius: pxToRem(8); + margin: pxToRem(24) 0; + overflow: hidden; + + &__summary { + display: flex; + align-items: center; + gap: pxToRem(10); + padding: pxToRem(14) pxToRem(16); + cursor: pointer; + font-size: $font-size-md; + font-weight: 600; + color: $prompt-text; + list-style: none; + + &::-webkit-details-marker { + display: none; + } + + // Disclosure caret, drawn rather than an icon file so it inherits color. + &::before { + content: ''; + flex: none; + width: pxToRem(8); + height: pxToRem(8); + border-right: 2px solid $prompt-accent; + border-bottom: 2px solid $prompt-accent; + transform: rotate(-45deg); + transition: transform 0.15s ease; + } + + &:hover { + color: $prompt-accent; + } + + &:focus-visible { + outline: 2px solid $prompt-accent; + outline-offset: -2px; + } + } + + &[open] &__summary::before { + transform: rotate(45deg); + } + + &__summary-label { + // A prompt title can be long; wrap rather than overflow. + min-width: 0; + } + + &__body { + padding: 0 pxToRem(16) pxToRem(16); + } + + // The fenced block Chroma emits inside the body. + .highlight { + margin: 0; + } + + &__skill { + font-size: $font-size-s; + color: $prompt-text-muted; + margin: pxToRem(12) 0 0; + line-height: 1.5; + + code { + font-family: $font-family-code; + font-size: pxToRem(12); + background: none; + padding: 0; + } + } + + [data-theme='light'] & { + background: $neutral-98; + border-color: $neutral-94; + border-left-color: $primary-40; + } +} + +// Written out longhand: inside a compound selector `[data-theme='light'] &` +// lands in the descendant position, where it can never match, because the +// theme attribute sits on . +[data-theme='light'] .prompt__summary { + color: $neutral-10; +} + +[data-theme='light'] .prompt__summary::before { + border-right-color: $primary-40; + border-bottom-color: $primary-40; +} + +[data-theme='light'] .prompt__summary:hover { + color: $primary-40; +} + +[data-theme='light'] .prompt__skill { + color: $neutral-50; +} + +@media (prefers-reduced-motion: reduce) { + .prompt__summary::before { + transition: none; + } +} diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html new file mode 100644 index 000000000..b2db91964 --- /dev/null +++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html @@ -0,0 +1,35 @@ +{{- /* + Renders one prompt from content/documentation/headless/prompts/.md. + + Usage: {{< prompt "set-up-monitoring" >}} + + The prompt file's body is plain text. This template wraps it in a fenced + block and runs it through markdownify so Chroma produces a real + `.highlight > pre`, which copy-code.js finds and adds a copy button to. That + is why this element needs no JavaScript of its own. + + The Markdown output format has its own variant, prompt.markdown.md, which + deliberately drops the body so an agent reading index.md is not handed an + instruction addressed to it. +*/ -}} +{{- $id := .Get 0 -}} +{{- $p := site.GetPage (printf "documentation/headless/prompts/%s" $id) -}} +{{- if not $p -}} + {{- errorf "prompt: no prompt file found for id %q (looked in content/documentation/headless/prompts/). Called from %s" $id .Page.File.Path -}} +{{- end -}} +
+ + {{ $p.Title }} + +
+ {{ printf "```text\n%s\n```" (trim $p.RawContent "\n") | markdownify }} + {{- with $p.Params.skill }} +

+ Uses the + {{ . }} + agent skill. + What are agent skills? +

+ {{- end }} +
+
From 4031c520acd21fd7231a80056b343077e8165a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 10 Sep 2026 15:17:35 +0200 Subject: [PATCH 06/26] GitHub workflow. --- .github/workflows/prompts.yml | 37 ++++++++++ automation/prompts/README.md | 71 +++++++++++++++++++ automation/prompts/check-prompts.sh | 104 ++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 .github/workflows/prompts.yml create mode 100644 automation/prompts/README.md create mode 100755 automation/prompts/check-prompts.sh diff --git a/.github/workflows/prompts.yml b/.github/workflows/prompts.yml new file mode 100644 index 000000000..901eabd25 --- /dev/null +++ b/.github/workflows/prompts.yml @@ -0,0 +1,37 @@ +name: Check documentation prompts + +on: + pull_request: + paths: + - 'qdrant-landing/content/documentation/headless/prompts/**' + - 'qdrant-landing/content/**/*.md' + - 'qdrant-landing/layouts/shortcodes/prompt.markdown.md' + - 'qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html' + - 'automation/prompts/**' + - '.github/workflows/prompts.yml' + +jobs: + check-prompts: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Hugo + uses: peaceiris/actions-hugo@v3 + with: + hugo-version: '0.160.1' + extended: true + + - name: Install Dart Sass + run: | + curl -sSL -o dart-sass.tar.gz \ + https://github.com/sass/dart-sass/releases/download/1.70.0/dart-sass-1.70.0-linux-x64.tar.gz + tar -xzf dart-sass.tar.gz + echo "$PWD/dart-sass" >> "$GITHUB_PATH" + + - name: Build site + working-directory: qdrant-landing + run: hugo --destination public + + - name: Check prompts + run: automation/prompts/check-prompts.sh diff --git a/automation/prompts/README.md b/automation/prompts/README.md new file mode 100644 index 000000000..c8bb8a730 --- /dev/null +++ b/automation/prompts/README.md @@ -0,0 +1,71 @@ +# Documentation prompts + +A prompt is a short, ready-to-paste instruction that gets a coding agent moving +on the task a documentation page is about. Prompts live in one folder, +`qdrant-landing/content/documentation/headless/prompts/`, one file each, and +pages include them by id. + +## Adding one + +1. Create `content/documentation/headless/prompts/.md`: + + ```yaml + --- + title: "Set up monitoring with an AI agent" + skill: qdrant-monitoring/setup + page: /documentation/ops-monitoring/monitoring/ + --- + Help me set up monitoring for my Qdrant deployment. Read + https://skills.qdrant.tech/qdrant-monitoring/setup/SKILL.md first, then ask + me whether I am self-hosted, on Qdrant Cloud, or on Hybrid Cloud. + ``` + + - `title` is what shows when the element is collapsed, which is the only + thing most readers will ever see of it. + - `skill` is a path under `skills.qdrant.tech`, without the `/SKILL.md` + suffix. Omit it when no skill applies. + - `page` is where the prompt is included. CI checks that page really + includes it. + - `open: true` renders the element expanded. Use it only where the prompt is + the point of the page, as on the Agentic Tools hub. + +2. Add `{{< prompt "" >}}` to that page, near the top of the section it + relates to rather than at the bottom. + +3. Run `automation/prompts/check-prompts.sh` after a build. + +## Writing one + +**A few sentences.** Enough to get someone moving, not a specification. + +**Name the skill inside the body,** with its full `SKILL.md` URL, so the agent +loads it rather than guessing. Prompts exist partly to surface skills. + +**No variables.** Never ask the reader to fill something in before pasting. If +the task needs their configuration, tell the agent to ask for it. + +**Do not restate the page.** The reader is already on it. A prompt that +re-explains the feature earns nothing. + +**Ask for what the docs cannot give.** The useful instructions are the ones +that make an agent commit to a judgment call: which setup applies to the +reader's deployment, what to check first, what to ignore. + +**Title it as an offer, not a label.** "Set up monitoring with an AI agent" +tells a reader what they get. "Prompt" does not, and the element is collapsed +by default, so the title is the whole invitation. + +## Two rules that break silently + +**Prompt bodies must never reach a built `index.md`.** Those files are consumed +by agents. A prompt is an instruction written in the imperative first person, +so an agent reading it inside a page it was told to fetch can follow the prompt +instead of answering the question it was actually asked. The shortcode's +Markdown variant drops the body and keeps the skill pointer. This is also why a +prompt is never written as a plain fenced block on the page. + +**The `page:` declaration is what the index trusts.** Prompt files cannot know +who includes them, so a stale declaration would put a wrong link in the index, +and a prompt that is never included would still be listed. + +`check-prompts.sh` guards both. diff --git a/automation/prompts/check-prompts.sh b/automation/prompts/check-prompts.sh new file mode 100755 index 000000000..726f24382 --- /dev/null +++ b/automation/prompts/check-prompts.sh @@ -0,0 +1,104 @@ +#!/usr/bin/env bash +# Guards the two rules that keep documentation prompts working. Both fail +# silently otherwise, which is why they are checked rather than reviewed. +# +# 1. No prompt body reaches a built index.md. Those files are consumed by +# agents, and a prompt is an instruction addressed to an agent, so it can +# displace the question the agent was actually asked. Writing a prompt as a +# plain fenced block instead of using the shortcode is how this breaks. +# 2. Every prompt's declared `page:` really includes it. The prompt files live +# in one folder and cannot know who includes them, so the declaration is +# what the index trusts. This also catches a prompt that is written but +# never used, which would otherwise appear in the index anyway. +# +# Usage: automation/prompts/check-prompts.sh [built-site-dir] +# Default built-site-dir is qdrant-landing/public. + +set -Eeuo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +public_dir="${1:-$repo_root/qdrant-landing/public}" +prompts_dir="$repo_root/qdrant-landing/content/documentation/headless/prompts" +content_dir="$repo_root/qdrant-landing/content" + +failures=0 + +fail() { + printf 'FAIL: %s\n' "$1" >&2 + failures=$((failures + 1)) +} + +if [[ ! -d "$prompts_dir" ]]; then + echo "No prompts directory at $prompts_dir; nothing to check." + exit 0 +fi + +if [[ ! -d "$public_dir" ]]; then + fail "built site not found at $public_dir (run hugo first, or pass the directory)" + exit 1 +fi + +shopt -s nullglob +prompt_files=("$prompts_dir"/*.md) +checked=0 + +for file in "${prompt_files[@]}"; do + id="$(basename "$file" .md)" + [[ "$id" == "_index" ]] && continue + checked=$((checked + 1)) + + # --- rule 1: the body must not appear in any built index.md --- + # Use the first non-empty body line as the probe. Front matter is delimited + # by the first two '---' lines. + probe="$(awk ' + /^---[[:space:]]*$/ { d++; next } + d >= 2 && NF { print; exit } + ' "$file")" + + if [[ -z "$probe" ]]; then + fail "$id: prompt file has no body" + continue + fi + + if hits="$(grep -rlF "$probe" --include='index.md' "$public_dir" 2>/dev/null)" && [[ -n "$hits" ]]; then + fail "$id: prompt body reached the agent-facing Markdown output:" + printf ' %s\n' $hits >&2 + printf ' Use {{< prompt "%s" >}} rather than a fenced block.\n' "$id" >&2 + fi + + # --- rule 2: the declared page must include the shortcode --- + page="$(awk -F': *' ' + /^---[[:space:]]*$/ { d++; if (d >= 2) exit; next } + d == 1 && $1 == "page" { print $2; exit } + ' "$file" | tr -d '"'"'"'')" + + if [[ -z "$page" ]]; then + fail "$id: no page: declared in front matter" + continue + fi + + # /documentation/foo/bar/ -> content/documentation/foo/bar.md or .../bar/_index.md + rel="${page#/}" + rel="${rel%/}" + src="" + for candidate in "$content_dir/$rel.md" "$content_dir/$rel/_index.md"; do + [[ -f "$candidate" ]] && { src="$candidate"; break; } + done + + if [[ -z "$src" ]]; then + fail "$id: declared page $page has no source file under content/" + continue + fi + + if ! grep -qF "prompt \"$id\"" "$src" && ! grep -qF "prompt '$id'" "$src"; then + fail "$id: declared page $page does not include it" + printf ' Expected {{< prompt "%s" >}} in %s\n' "$id" "${src#"$repo_root"/}" >&2 + fi +done + +if (( failures > 0 )); then + printf '\n%d prompt check failure(s) across %d prompt(s).\n' "$failures" "$checked" >&2 + exit 1 +fi + +printf 'Prompt checks passed: %d prompt(s).\n' "$checked" From 0d14144f68a28d7a08f4c8e6b386db692dfa696e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 10 Sep 2026 15:39:12 +0200 Subject: [PATCH 07/26] Rephrase intro sentence. --- .../content/documentation/ops-monitoring/monitoring.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qdrant-landing/content/documentation/ops-monitoring/monitoring.md b/qdrant-landing/content/documentation/ops-monitoring/monitoring.md index 3ddbbdb84..1784c4aa0 100644 --- a/qdrant-landing/content/documentation/ops-monitoring/monitoring.md +++ b/qdrant-landing/content/documentation/ops-monitoring/monitoring.md @@ -21,7 +21,7 @@ The integration with Qdrant is easy to [configure](https://prometheus.io/docs/prometheus/latest/getting_started/#configure-prometheus-to-monitor-the-sample-targets) with Prometheus and Grafana. -If you would rather have an agent do this, the prompt below asks it to pick the right scrape setup for your deployment type and propose alerts worth having. +If you would rather have an agent handle this, use the following prompt to select the appropriate configuration for your deployment type and recommend relevant alerts. {{< prompt "set-up-monitoring" >}} From 63b93c315cb91e61fe09d729ee7ba1c9f9108b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Mon, 14 Sep 2026 14:21:37 +0200 Subject: [PATCH 08/26] Add prompts. --- .../headless/prompts/design-a-collection.md | 15 +++++++++++++++ .../headless/prompts/diagnose-memory-usage.md | 13 +++++++++++++ .../documentation/manage-data/collections.md | 4 ++++ .../documentation/ops-optimization/optimize.md | 4 ++++ 4 files changed, 36 insertions(+) create mode 100644 qdrant-landing/content/documentation/headless/prompts/design-a-collection.md create mode 100644 qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md diff --git a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md new file mode 100644 index 000000000..ffccf3b2e --- /dev/null +++ b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md @@ -0,0 +1,15 @@ +--- +title: "Design a collection with an AI agent" +skill: qdrant-multitenancy +page: /documentation/manage-data/collections/ +--- +Help me design a Qdrant collection for my data. Ask me what I am searching +over, roughly how many vectors I expect, which embedding model I am using, and +what I will filter on, before you write any code. Decide first whether this +should be one collection or many, reading +https://skills.qdrant.tech/qdrant-multitenancy/SKILL.md, since that choice +drives the index layout. Then derive the vector size from the model rather than +hardcoding it, name the distance metric the model was trained for and say why +you picked it, and add a payload index for every field I will filter on. Finish +by telling me which of these I cannot change later without recreating the +collection. diff --git a/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md b/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md new file mode 100644 index 000000000..dbcf4c261 --- /dev/null +++ b/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md @@ -0,0 +1,13 @@ +--- +title: "Diagnose high memory usage with an AI agent" +skill: qdrant-performance-optimization/memory-usage-optimization +page: /documentation/ops-optimization/optimize/ +--- +My Qdrant memory usage is higher than I expected, or a node was killed for +running out of memory. Read +https://skills.qdrant.tech/qdrant-performance-optimization/memory-usage-optimization/SKILL.md +first, then ask me for my collection configuration before proposing anything. +Tell me which component is actually consuming the memory, whether that is the +vectors, the HNSW index, or the payload indexes, and give me the fixes in order +of impact. Say which ones need a reindex, and what recall I would lose if I +quantize. diff --git a/qdrant-landing/content/documentation/manage-data/collections.md b/qdrant-landing/content/documentation/manage-data/collections.md index 9fbee724a..8b9a67b69 100644 --- a/qdrant-landing/content/documentation/manage-data/collections.md +++ b/qdrant-landing/content/documentation/manage-data/collections.md @@ -29,6 +29,10 @@ Qdrant supports these most popular types of metrics: In addition to metrics and vector size, each collection uses its own set of parameters that controls collection optimization, index construction, and vacuum. These settings can be changed at any time by a corresponding request. +If you would rather have an agent design this with you, the prompt below asks it for your data and query shape first, then commits to a vector configuration and the payload indexes to create. + +{{< prompt "design-a-collection" >}} + ## Setting Up Multitenancy **How many collections should you create?** In most cases, you should only use a single collection with payload-based partitioning. This approach is called [multitenancy](https://en.wikipedia.org/wiki/Multitenancy). It is efficient for most of users, but it requires additional configuration. [Learn how to set it up](/documentation/manage-data/multitenancy/). diff --git a/qdrant-landing/content/documentation/ops-optimization/optimize.md b/qdrant-landing/content/documentation/ops-optimization/optimize.md index ec230f2cb..80f0e3ab6 100644 --- a/qdrant-landing/content/documentation/ops-optimization/optimize.md +++ b/qdrant-landing/content/documentation/ops-optimization/optimize.md @@ -25,6 +25,10 @@ This guide will walk you three main optimization strategies: This page covers the memory parameter introduced in Qdrant v1.19. If you're using an older version, see the Legacy Settings section for how to map the new parameter to the old ones. +If you would rather have an agent work through this with you, the prompt below asks it to find which component is actually using the memory before it suggests any changes. + +{{< prompt "diagnose-memory-usage" >}} + ## 1. High-Speed Search with Low Memory Usage To achieve high search speed with minimal memory usage, you can store vectors on disk while minimizing the number of disk reads. Vector quantization is a technique that compresses vectors, allowing more of them to be stored in memory, thus reducing the need to read from disk. From 61743cf3a76bfc6dba2c4d4d6be725c705162bb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Mon, 14 Sep 2026 14:34:04 +0200 Subject: [PATCH 09/26] Fix CI. --- .github/workflows/prompts.yml | 21 ++------- automation/prompts/README.md | 10 +++- automation/prompts/check-prompts.sh | 72 ++++++++++++++++++++--------- 3 files changed, 60 insertions(+), 43 deletions(-) diff --git a/.github/workflows/prompts.yml b/.github/workflows/prompts.yml index 901eabd25..d99b28ae4 100644 --- a/.github/workflows/prompts.yml +++ b/.github/workflows/prompts.yml @@ -3,7 +3,6 @@ name: Check documentation prompts on: pull_request: paths: - - 'qdrant-landing/content/documentation/headless/prompts/**' - 'qdrant-landing/content/**/*.md' - 'qdrant-landing/layouts/shortcodes/prompt.markdown.md' - 'qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html' @@ -16,22 +15,8 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install Hugo - uses: peaceiris/actions-hugo@v3 - with: - hugo-version: '0.160.1' - extended: true - - - name: Install Dart Sass - run: | - curl -sSL -o dart-sass.tar.gz \ - https://github.com/sass/dart-sass/releases/download/1.70.0/dart-sass-1.70.0-linux-x64.tar.gz - tar -xzf dart-sass.tar.gz - echo "$PWD/dart-sass" >> "$GITHUB_PATH" - - - name: Build site - working-directory: qdrant-landing - run: hugo --destination public - + # Source checks only: no Hugo, no Dart Sass, no npm install. The rules + # this guards are all visible in the source, so a full site build would + # cost minutes on every docs PR to verify something that takes seconds. - name: Check prompts run: automation/prompts/check-prompts.sh diff --git a/automation/prompts/README.md b/automation/prompts/README.md index c8bb8a730..f0262d921 100644 --- a/automation/prompts/README.md +++ b/automation/prompts/README.md @@ -32,7 +32,9 @@ pages include them by id. 2. Add `{{< prompt "" >}}` to that page, near the top of the section it relates to rather than at the bottom. -3. Run `automation/prompts/check-prompts.sh` after a build. +3. Run `automation/prompts/check-prompts.sh`. It needs no build. Pass a built + site directory to also verify the real output, for example + `automation/prompts/check-prompts.sh qdrant-landing/public`. ## Writing one @@ -68,4 +70,8 @@ prompt is never written as a plain fenced block on the page. who includes them, so a stale declaration would put a wrong link in the index, and a prompt that is never included would still be listed. -`check-prompts.sh` guards both. +`check-prompts.sh` guards both, plus a third rule that keeps them equivalent: +the Markdown variant of the shortcode must never render the body. Rule one is +checked in the source rather than in the built output, because pasting a body +inline is a source-level mistake and catching it there means CI needs no site +build. diff --git a/automation/prompts/check-prompts.sh b/automation/prompts/check-prompts.sh index 726f24382..355586149 100755 --- a/automation/prompts/check-prompts.sh +++ b/automation/prompts/check-prompts.sh @@ -1,25 +1,34 @@ #!/usr/bin/env bash -# Guards the two rules that keep documentation prompts working. Both fail +# Guards the rules that keep documentation prompts working. All of them fail # silently otherwise, which is why they are checked rather than reviewed. # -# 1. No prompt body reaches a built index.md. Those files are consumed by -# agents, and a prompt is an instruction addressed to an agent, so it can -# displace the question the agent was actually asked. Writing a prompt as a -# plain fenced block instead of using the shortcode is how this breaks. -# 2. Every prompt's declared `page:` really includes it. The prompt files live +# 1. No prompt body is written inline on a page. Prompt bodies must not reach +# a built index.md, because those files are consumed by agents and a prompt +# is an instruction addressed to an agent, so it can displace the question +# the agent was actually asked. The shortcode's Markdown variant drops the +# body, so the only way a body reaches index.md is an author pasting it as +# a fenced block instead of using the shortcode. That is a source-level +# mistake, so it is caught in the source. +# 2. The Markdown variant of the shortcode still drops the body. Rule 1 is +# only equivalent to "no body in index.md" while this holds. +# 3. Every prompt's declared `page:` really includes it. The prompt files live # in one folder and cannot know who includes them, so the declaration is # what the index trusts. This also catches a prompt that is written but # never used, which would otherwise appear in the index anyway. # -# Usage: automation/prompts/check-prompts.sh [built-site-dir] -# Default built-site-dir is qdrant-landing/public. +# These are all source checks, so no site build is needed and the run takes +# seconds. Pass a built-site directory to additionally verify the real output: +# +# automation/prompts/check-prompts.sh # source checks only +# automation/prompts/check-prompts.sh qdrant-landing/public # and the build set -Eeuo pipefail repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -public_dir="${1:-$repo_root/qdrant-landing/public}" +public_dir="${1:-}" prompts_dir="$repo_root/qdrant-landing/content/documentation/headless/prompts" content_dir="$repo_root/qdrant-landing/content" +md_shortcode="$repo_root/qdrant-landing/layouts/shortcodes/prompt.markdown.md" failures=0 @@ -33,23 +42,23 @@ if [[ ! -d "$prompts_dir" ]]; then exit 0 fi -if [[ ! -d "$public_dir" ]]; then - fail "built site not found at $public_dir (run hugo first, or pass the directory)" - exit 1 +# --- rule 2: the Markdown variant must not render the prompt body --- +if [[ ! -f "$md_shortcode" ]]; then + fail "missing $md_shortcode: without it, prompt bodies reach the agent-facing Markdown" +elif grep -qE '\.(RawContent|Content|Inner)\b' "$md_shortcode"; then + fail "$md_shortcode renders the prompt body; it must emit only the skill pointer" fi shopt -s nullglob -prompt_files=("$prompts_dir"/*.md) checked=0 -for file in "${prompt_files[@]}"; do +for file in "$prompts_dir"/*.md; do id="$(basename "$file" .md)" [[ "$id" == "_index" ]] && continue checked=$((checked + 1)) - # --- rule 1: the body must not appear in any built index.md --- - # Use the first non-empty body line as the probe. Front matter is delimited - # by the first two '---' lines. + # First non-empty body line, used as the probe. Front matter is delimited by + # the first two '---' lines. probe="$(awk ' /^---[[:space:]]*$/ { d++; next } d >= 2 && NF { print; exit } @@ -60,13 +69,15 @@ for file in "${prompt_files[@]}"; do continue fi - if hits="$(grep -rlF "$probe" --include='index.md' "$public_dir" 2>/dev/null)" && [[ -n "$hits" ]]; then - fail "$id: prompt body reached the agent-facing Markdown output:" + # --- rule 1: the body must not appear inline anywhere in the content tree --- + if hits="$(grep -rlF "$probe" --include='*.md' "$content_dir" 2>/dev/null \ + | grep -v "^$prompts_dir/" || true)" && [[ -n "$hits" ]]; then + fail "$id: prompt body is written inline instead of using the shortcode:" printf ' %s\n' $hits >&2 - printf ' Use {{< prompt "%s" >}} rather than a fenced block.\n' "$id" >&2 + printf ' Replace it with {{< prompt "%s" >}}\n' "$id" >&2 fi - # --- rule 2: the declared page must include the shortcode --- + # --- rule 3: the declared page must include the shortcode --- page="$(awk -F': *' ' /^---[[:space:]]*$/ { d++; if (d >= 2) exit; next } d == 1 && $1 == "page" { print $2; exit } @@ -77,7 +88,6 @@ for file in "${prompt_files[@]}"; do continue fi - # /documentation/foo/bar/ -> content/documentation/foo/bar.md or .../bar/_index.md rel="${page#/}" rel="${rel%/}" src="" @@ -94,6 +104,18 @@ for file in "${prompt_files[@]}"; do fail "$id: declared page $page does not include it" printf ' Expected {{< prompt "%s" >}} in %s\n' "$id" "${src#"$repo_root"/}" >&2 fi + + # --- optional: verify the real built output when a build is available --- + if [[ -n "$public_dir" ]]; then + if [[ ! -d "$public_dir" ]]; then + fail "built site not found at $public_dir" + public_dir="" + elif built="$(grep -rlF "$probe" --include='index.md' "$public_dir" 2>/dev/null || true)" \ + && [[ -n "$built" ]]; then + fail "$id: prompt body reached the agent-facing Markdown output:" + printf ' %s\n' $built >&2 + fi + fi done if (( failures > 0 )); then @@ -101,4 +123,8 @@ if (( failures > 0 )); then exit 1 fi -printf 'Prompt checks passed: %d prompt(s).\n' "$checked" +if [[ -n "$public_dir" ]]; then + printf 'Prompt checks passed (source and build): %d prompt(s).\n' "$checked" +else + printf 'Prompt checks passed: %d prompt(s).\n' "$checked" +fi From b60ad42022598c51c137735d671bf328797281bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Mon, 14 Sep 2026 14:41:12 +0200 Subject: [PATCH 10/26] Fine-tune text. --- qdrant-landing/content/documentation/manage-data/collections.md | 2 +- .../content/documentation/ops-optimization/optimize.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qdrant-landing/content/documentation/manage-data/collections.md b/qdrant-landing/content/documentation/manage-data/collections.md index 8b9a67b69..d1666d80e 100644 --- a/qdrant-landing/content/documentation/manage-data/collections.md +++ b/qdrant-landing/content/documentation/manage-data/collections.md @@ -29,7 +29,7 @@ Qdrant supports these most popular types of metrics: In addition to metrics and vector size, each collection uses its own set of parameters that controls collection optimization, index construction, and vacuum. These settings can be changed at any time by a corresponding request. -If you would rather have an agent design this with you, the prompt below asks it for your data and query shape first, then commits to a vector configuration and the payload indexes to create. +If you would rather have an agent design this with you, the following prompt asks it for your data and query shape first, then commits to a vector configuration and the payload indexes to create. {{< prompt "design-a-collection" >}} diff --git a/qdrant-landing/content/documentation/ops-optimization/optimize.md b/qdrant-landing/content/documentation/ops-optimization/optimize.md index 80f0e3ab6..fd6c16a85 100644 --- a/qdrant-landing/content/documentation/ops-optimization/optimize.md +++ b/qdrant-landing/content/documentation/ops-optimization/optimize.md @@ -25,7 +25,7 @@ This guide will walk you three main optimization strategies: This page covers the memory parameter introduced in Qdrant v1.19. If you're using an older version, see the Legacy Settings section for how to map the new parameter to the old ones. -If you would rather have an agent work through this with you, the prompt below asks it to find which component is actually using the memory before it suggests any changes. +If you would rather have an agent work through this with you, the following prompt asks it to find which component is actually using the memory before it suggests any changes. {{< prompt "diagnose-memory-usage" >}} From 3e3191a5171c871a11d34819fc5adc4817dd24f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Mon, 14 Sep 2026 16:33:59 +0200 Subject: [PATCH 11/26] Fine-tuning. --- automation/prompts/README.md | 14 +++++++++++--- .../headless/prompts/start-building.md | 3 +++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/automation/prompts/README.md b/automation/prompts/README.md index f0262d921..043193f97 100644 --- a/automation/prompts/README.md +++ b/automation/prompts/README.md @@ -23,11 +23,19 @@ pages include them by id. - `title` is what shows when the element is collapsed, which is the only thing most readers will ever see of it. - `skill` is a path under `skills.qdrant.tech`, without the `/SKILL.md` - suffix. Omit it when no skill applies. + suffix. Omit it when no skill applies. Check the path resolves before + using it: `curl -I https://skills.qdrant.tech//SKILL.md`. The + published paths are listed in `https://skills.qdrant.tech/llms.txt`, and a + path in the `qdrant/skills` repo is not automatically published, so the + repo is not a reliable source for this value. Note the meta skills sit + under `meta/`, as in `meta/qdrant-advisor`. - `page` is where the prompt is included. CI checks that page really includes it. - - `open: true` renders the element expanded. Use it only where the prompt is - the point of the page, as on the Agentic Tools hub. + - `open: true` renders the element expanded. **In-page prompts are always + collapsed**, so leave this unset. It exists for a page whose whole purpose + is the prompt, which today means only the Agentic Tools hub. A prompt + feeling important is not a reason to set it: every prompt feels important + to its author, and the collapsed state is what keeps a docs page readable. 2. Add `{{< prompt "" >}}` to that page, near the top of the section it relates to rather than at the bottom. diff --git a/qdrant-landing/content/documentation/headless/prompts/start-building.md b/qdrant-landing/content/documentation/headless/prompts/start-building.md index 496fded53..395ae0f92 100644 --- a/qdrant-landing/content/documentation/headless/prompts/start-building.md +++ b/qdrant-landing/content/documentation/headless/prompts/start-building.md @@ -1,7 +1,10 @@ --- title: "Start building with an AI agent" page: /documentation/agentic-tools/ +# Expanded because this prompt is the point of the hub page. Do not copy +# this to an in-page prompt; those are always collapsed. open: true +skill: meta/qdrant-advisor --- Help me get started building on Qdrant. From 93e30f3486a27f7051dc3317953b20403722f357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Mon, 14 Sep 2026 16:45:16 +0200 Subject: [PATCH 12/26] Add a review prompt. --- .../headless/prompts/review-before-launch.md | 12 ++++++++++++ .../content/documentation/production-checklist.md | 4 ++++ 2 files changed, 16 insertions(+) create mode 100644 qdrant-landing/content/documentation/headless/prompts/review-before-launch.md diff --git a/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md b/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md new file mode 100644 index 000000000..9ce2cf60e --- /dev/null +++ b/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md @@ -0,0 +1,12 @@ +--- +title: "Review my deployment with an AI agent" +skill: qdrant-sizing +page: /documentation/production-checklist/ +--- +Review my Qdrant deployment before I put production traffic on it. Read +https://skills.qdrant.tech/qdrant-sizing/SKILL.md, then ask me for my +collection configuration, my expected vector count and query rate, and the +hardware I have provisioned. Tell me which of my settings will not survive real +load, ordered by how much it would hurt, and separate what I can change later +from what needs the collection recreated. Where my numbers do not support a +conclusion, say what to measure rather than guessing. diff --git a/qdrant-landing/content/documentation/production-checklist.md b/qdrant-landing/content/documentation/production-checklist.md index 58f7f9127..4c128be34 100644 --- a/qdrant-landing/content/documentation/production-checklist.md +++ b/qdrant-landing/content/documentation/production-checklist.md @@ -10,6 +10,10 @@ weight: 147 A practical checklist to ensure Qdrant is optimized, stable, and ready to handle real-world load. +If you would rather have an agent run through this with you, use the following prompt to get a prioritized list of what would break first under real load. + +{{< prompt "review-before-launch" >}} + --- ## 1. Distributed Deployment & Sharding From 37ddb1c78b0acc13cc0e119f7fae2340a939d94b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Tue, 15 Sep 2026 11:06:47 +0200 Subject: [PATCH 13/26] Prompt index. --- .../documentation/agentic-tools/_index.md | 8 ++- .../documentation/agentic-tools/prompts.md | 17 ++++++ .../shortcodes/prompt-index.markdown.md | 19 +++++++ .../layouts/shortcodes/prompt-index.html | 55 +++++++++++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 qdrant-landing/content/documentation/agentic-tools/prompts.md create mode 100644 qdrant-landing/layouts/shortcodes/prompt-index.markdown.md create mode 100644 qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html diff --git a/qdrant-landing/content/documentation/agentic-tools/_index.md b/qdrant-landing/content/documentation/agentic-tools/_index.md index a745f1b9e..ee9d25cbe 100644 --- a/qdrant-landing/content/documentation/agentic-tools/_index.md +++ b/qdrant-landing/content/documentation/agentic-tools/_index.md @@ -1,6 +1,6 @@ --- title: "Agentic Tools" -short_description: "Tools that help AI coding assistants work with Qdrant: a prompt to get started, and agent skills that carry solutions architect knowledge into your agent." +short_description: "Tools that help AI coding assistants work with Qdrant: a prompt to get started, agent skills that carry solutions architect knowledge, and prompts embedded across the documentation." description: "Qdrant agentic tools for AI coding assistants. Start from a single prompt that runs Qdrant locally and installs the Qdrant Advisor, then use agent skills to diagnose and tune search, memory, scaling, and relevance in a running deployment." weight: 303 partition: develop @@ -29,3 +29,9 @@ A wrong collection configuration rarely fails loudly in vector search: a mismatc [Agent skills](/documentation/agentic-tools/skills/) encode solutions architect knowledge as structured files your agent loads on demand. They're organized around symptoms, so they answer "why is this happening, and what should I check first?" Reach for skills when something is already running and behaving unexpectedly: slow search, growing memory, a stuck optimizer, poor relevance. + +## Prompts in the Docs + +Short, ready-to-use prompts appear directly on the documentation pages where they are relevant, so you can use the prompts when you need them instead of looking for them elsewhere. +Each prompt points to the agent skill your assistant should load. The prompt gets the task started; the skill provides the deeper Qdrant-specific guidance. +The [prompt index](/documentation/agentic-tools/prompts/) lists all available prompts. diff --git a/qdrant-landing/content/documentation/agentic-tools/prompts.md b/qdrant-landing/content/documentation/agentic-tools/prompts.md new file mode 100644 index 000000000..05b272a42 --- /dev/null +++ b/qdrant-landing/content/documentation/agentic-tools/prompts.md @@ -0,0 +1,17 @@ +--- +title: "Prompts in the Docs" +short_description: "Every prompt in the Qdrant documentation, with the page it appears on and the agent skill it uses." +description: "An index of the ready-to-paste prompts embedded in the Qdrant documentation. Each one sits on the page it relates to, links the relevant agent skill, and is written to be handed straight to a coding assistant." +weight: 20 +partition: develop +--- + +# Prompts in the Docs + +Qdrant documentation includes short, ready-to-use prompts on the pages where they are relevant: setting up monitoring on the monitoring page, diagnosing memory issues on the optimization page, and so on. + +Each prompt is collapsed by default, requires no additional input, and tells your assistant which [agent skill](/documentation/agentic-tools/skills/) to load. The prompt defines the task; the skill provides the Qdrant-specific guidance needed to complete it. + +This page lists all available prompts. Follow a link to open the prompt alongside the documentation that provides its context. + +{{< prompt-index >}} diff --git a/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md b/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md new file mode 100644 index 000000000..217f32c9c --- /dev/null +++ b/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md @@ -0,0 +1,19 @@ +{{- /* + Markdown variant of the prompt index. + + Titles, pages, and skill pointers only. Prompt bodies never appear here, for + the same reason the `prompt` shortcode drops them: an index.md is consumed by + agents, and a prompt is an instruction addressed to an agent. + + Keep in step with prompt-index.html, which emits table markup instead of + pipes because shortcode output is not re-parsed as markdown. +*/ -}} +{{- $section := site.GetPage "documentation/headless/prompts" -}} +{{- if not $section -}} + {{- errorf "prompt-index: cannot resolve documentation/headless/prompts (see prompt-index.html for the cause)." -}} +{{- end -}} +| Prompt | Page | Agent skill | +|---|---|---| +{{ range $section.RegularPages.ByTitle -}} +| {{ .Title }} | {{ with .Params.page }}{{ . }}{{ else }}none{{ end }} | {{ with .Params.skill }}https://skills.qdrant.tech/{{ . }}/SKILL.md{{ else }}none{{ end }} | +{{ end -}} diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html new file mode 100644 index 000000000..98f6e5918 --- /dev/null +++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html @@ -0,0 +1,55 @@ +{{- /* + Generated index of every prompt in the docs. + + Ranges the headless prompts section rather than scraping pages, so the table + cannot drift from the prompt files. Each row's page comes from the prompt's + own `page:` param; check-prompts.sh verifies that page really includes it. + + This emits real table markup because a shortcode's output is inserted as HTML + and never re-parsed as markdown, so pipe rows would render as literal text. + The Markdown output format has its own variant, prompt-index.markdown.md, + which does use pipes. Keep the two in step. +*/ -}} +{{- $section := site.GetPage "documentation/headless/prompts" -}} +{{- if not $section -}} + {{- errorf "prompt-index: cannot resolve documentation/headless/prompts. The section needs an _index.md setting build.list to 'local'; the parent headless bundle cascades 'never', which makes this lookup nil." -}} +{{- end -}} +{{- /* Emitted without attributes on purpose: article-content.html matches a + bare ``, wraps it in .table-responsive and adds `table mb-5`, so + this picks up the same styling and mobile scrolling as every other docs + table. Adding a class here would silently opt out of both. */ -}} +
+ + + + + {{- range $section.RegularPages.ByTitle }} + {{- $p := . }} + + + + + + {{- end }} + +
PromptPageAgent skill
+ {{- with $p.Params.page -}} + {{ $p.Title }} + {{- else -}} + {{ $p.Title }} + {{- end -}} + + {{- with $p.Params.page -}} + {{- with site.GetPage . -}} + {{ .Title }} + {{- else -}} + {{ $p.Params.page }} + {{- end -}} + {{- end -}} + + {{- with $p.Params.skill -}} + {{ . }} + {{- else -}} + None + {{- end -}} +
From 90d8b1470d7a30b725fa4ffe04b4cd26f26f72a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Tue, 15 Sep 2026 12:26:38 +0200 Subject: [PATCH 14/26] Add prompt marker to box. --- .../headless/prompts/design-a-collection.md | 2 +- .../headless/prompts/diagnose-memory-usage.md | 2 +- .../headless/prompts/review-before-launch.md | 2 +- .../headless/prompts/set-up-monitoring.md | 2 +- .../headless/prompts/start-building.md | 2 +- .../assets/css/components/_prompt.scss | 22 ++++++++++++++++++- .../layouts/shortcodes/prompt.html | 5 +++++ 7 files changed, 31 insertions(+), 6 deletions(-) diff --git a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md index ffccf3b2e..2ae1470f4 100644 --- a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md +++ b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md @@ -1,5 +1,5 @@ --- -title: "Design a collection with an AI agent" +title: "Design a collection" skill: qdrant-multitenancy page: /documentation/manage-data/collections/ --- diff --git a/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md b/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md index dbcf4c261..76f1aa006 100644 --- a/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md +++ b/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md @@ -1,5 +1,5 @@ --- -title: "Diagnose high memory usage with an AI agent" +title: "Diagnose high memory usage" skill: qdrant-performance-optimization/memory-usage-optimization page: /documentation/ops-optimization/optimize/ --- diff --git a/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md b/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md index 9ce2cf60e..4d9cb7808 100644 --- a/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md +++ b/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md @@ -1,5 +1,5 @@ --- -title: "Review my deployment with an AI agent" +title: "Review my deployment" skill: qdrant-sizing page: /documentation/production-checklist/ --- diff --git a/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md b/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md index 4d7e493a9..e6fab07fa 100644 --- a/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md +++ b/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md @@ -1,5 +1,5 @@ --- -title: "Set up monitoring with an AI agent" +title: "Set up monitoring" skill: qdrant-monitoring/setup page: /documentation/ops-monitoring/monitoring/ --- diff --git a/qdrant-landing/content/documentation/headless/prompts/start-building.md b/qdrant-landing/content/documentation/headless/prompts/start-building.md index 395ae0f92..0c7796338 100644 --- a/qdrant-landing/content/documentation/headless/prompts/start-building.md +++ b/qdrant-landing/content/documentation/headless/prompts/start-building.md @@ -1,5 +1,5 @@ --- -title: "Start building with an AI agent" +title: "Start building on Qdrant" page: /documentation/agentic-tools/ # Expanded because this prompt is the point of the hub page. Do not copy # this to an in-page prompt; those are always collapsed. diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index 5932674b2..236925e8a 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -55,6 +55,21 @@ $prompt-accent: $primary-60; transform: rotate(45deg); } + // The kind marker: a category label, not disabled metadata. It uses the + // secondary text color rather than a true grey, because the collapsed + // summary is the only surface that tells a reader this element exists. + &__kind { + flex: none; + font-size: pxToRem(11); + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: $prompt-text-muted; + // Separates the marker from the title without a divider glyph. + padding-right: pxToRem(10); + border-right: 1px solid $prompt-border; + } + &__summary-label { // A prompt title can be long; wrap rather than overflow. min-width: 0; @@ -106,10 +121,15 @@ $prompt-accent: $primary-60; color: $primary-40; } -[data-theme='light'] .prompt__skill { +[data-theme='light'] .prompt__skill, +[data-theme='light'] .prompt__kind { color: $neutral-50; } +[data-theme='light'] .prompt__kind { + border-right-color: $neutral-94; +} + @media (prefers-reduced-motion: reduce) { .prompt__summary::before { transition: none; diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html index b2db91964..51ca27bc9 100644 --- a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html +++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html @@ -19,6 +19,11 @@ {{- end -}}
+ {{- /* Names the kind of thing this is while collapsed. The summary line is + the only discovery surface a prompt has, so the type marker is placed + here by the shortcode rather than left to each author to work into the + title. Prompt titles are therefore plain task names. */ -}} + Prompt {{ $p.Title }}
From 0b9b11b152f0a40286c7934b8d345d6d187862b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Tue, 15 Sep 2026 12:27:13 +0200 Subject: [PATCH 15/26] Adjust README. --- automation/prompts/README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/automation/prompts/README.md b/automation/prompts/README.md index 043193f97..55a32cde7 100644 --- a/automation/prompts/README.md +++ b/automation/prompts/README.md @@ -20,8 +20,10 @@ pages include them by id. me whether I am self-hosted, on Qdrant Cloud, or on Hybrid Cloud. ``` - - `title` is what shows when the element is collapsed, which is the only - thing most readers will ever see of it. + - `title` is a plain task name: "Set up monitoring", not "Set up monitoring + with an AI agent". The collapsed element already carries a `Prompt` marker + placed by the shortcode, so working the word into the title says the same + thing twice. Write it as the task, starting with a verb. - `skill` is a path under `skills.qdrant.tech`, without the `/SKILL.md` suffix. Omit it when no skill applies. Check the path resolves before using it: `curl -I https://skills.qdrant.tech//SKILL.md`. The @@ -61,9 +63,11 @@ re-explains the feature earns nothing. that make an agent commit to a judgment call: which setup applies to the reader's deployment, what to check first, what to ignore. -**Title it as an offer, not a label.** "Set up monitoring with an AI agent" -tells a reader what they get. "Prompt" does not, and the element is collapsed -by default, so the title is the whole invitation. +**Title it as the task.** The collapsed line reads `PROMPT | Set up +monitoring`: the marker says what kind of thing it is, the title says what it +does. That split is why titles stay short, and why the type signal is +consistent across every prompt rather than depending on each author phrasing it +the same way. ## Two rules that break silently From 204d6269361812bcbb1c3946878e8a2405d59bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Tue, 15 Sep 2026 12:58:09 +0200 Subject: [PATCH 16/26] Add AGENTS.md. --- .github/workflows/prompts.yml | 18 +++ AGENTS.md | 114 ++++++++++++++++ automation/prompts/README.md | 28 +++- automation/prompts/check-skill-links.sh | 124 ++++++++++++++++++ .../shortcodes/prompt-index.markdown.md | 2 +- .../layouts/shortcodes/prompt-index.html | 2 + 6 files changed, 284 insertions(+), 4 deletions(-) create mode 100644 AGENTS.md create mode 100755 automation/prompts/check-skill-links.sh diff --git a/.github/workflows/prompts.yml b/.github/workflows/prompts.yml index d99b28ae4..f866498fb 100644 --- a/.github/workflows/prompts.yml +++ b/.github/workflows/prompts.yml @@ -8,9 +8,16 @@ on: - 'qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html' - 'automation/prompts/**' - '.github/workflows/prompts.yml' + # A skill link breaks when a skill is renamed or unpublished in qdrant/skills, + # which does not touch this repository and so never triggers the pull request + # run. The weekly run is what catches that. + schedule: + - cron: '0 6 * * 1' + workflow_dispatch: jobs: check-prompts: + if: github.event_name != 'schedule' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -20,3 +27,14 @@ jobs: # cost minutes on every docs PR to verify something that takes seconds. - name: Check prompts run: automation/prompts/check-prompts.sh + + check-skill-links: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + # Kept separate from check-prompts because this one reaches the network. + # An unreachable skills.qdrant.tech skips rather than fails, so the job + # only goes red on a skill that is genuinely not published. + - name: Check agent skill links + run: automation/prompts/check-skill-links.sh diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..5eacc582d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,114 @@ +# AGENTS.md + +Guidance for AI coding agents working in this repository. This is the Hugo site +behind [qdrant.tech](https://qdrant.tech): the marketing pages, the blog, and +the documentation. + +This file is about editing the repository. It is not the agent-facing entry +point for the published site, which is +[`qdrant.tech/llms.txt`](https://qdrant.tech/llms.txt), generated from +`themes/qdrant-2024/layouts/index.llms.txt`. + +## Build and serve + +```bash +./run.sh # npm install, then hugo serve on :1313 +./install-and-build.sh # what Netlify runs: fetches Dart Sass, builds to public/ +``` + +Three things about the build cause more lost time than everything else combined: + +- **Hugo 0.160.1 exactly.** `install-and-build.sh` refuses any other version and + `run.sh` warns. A different version produces failures that look like content + bugs. +- **Dart Sass is required, and the npm package named `sass` is not it.** It is a + different implementation. Without Dart Sass on `PATH`, Hugo still reports a + successful build and serves stale CSS out of `qdrant-landing/resources/_gen`. + A panel that renders unstyled after an SCSS change almost always means this + rather than a mistake in the SCSS. +- **`hugo --quiet` hides build errors.** It has reported exit 0 through a pipe + while the site failed to render. Grep unpiped output for `ERROR` before + trusting a green build. + +## Layout of the repository + +| Path | What it holds | +|---|---| +| `qdrant-landing/content/` | All content. `documentation/` is the docs tree | +| `qdrant-landing/content/headless/`, `.../documentation/headless/` | Page bundles that are never published as URLs: code snippets, prompts | +| `qdrant-landing/themes/qdrant-2024/` | The theme: layouts, shortcodes, SCSS, JS | +| `qdrant-landing/layouts/` | Project layouts, which override the theme's | +| `automation/` | Checks and generators, each with its own README | +| `.github/workflows/` | CI | + +`qdrant-landing/public/`, `qdrant-landing/resources/_gen/`, and `node_modules/` +are generated and git-ignored. Never edit them, and never cite a path under +`public/` as the source of anything. + +Project layouts win over theme layouts, which is why `layouts/shortcodes/` +holds the per-output-format variants while the theme holds the HTML ones. + +## Every page has two outputs + +A content page renders as HTML and as Markdown at `/index.md`. The Markdown +output is what AI agents consume, and `qdrant.tech/llms.txt` indexes it. It is +not a format conversion of the HTML: `layouts/_default/single.markdown.md` +prepends pointers to the skills catalog and rewrites internal links to their +`index.md` form. + +So a change to a page changes two published artifacts. When a shortcode should +behave differently for agents, give it a `.markdown.md` variant in +`layouts/shortcodes/` rather than trying to detect the format inside the HTML +one. `code-snippet`, `include`, `prompt`, and `prompt-index` all do this. + +## Content conventions + +- **`weight` in front matter orders the docs sidebar.** Adding a page without + one puts it in an unpredictable position. +- **Moving or renaming a page needs `aliases`** in the destination's front + matter. Old URLs are linked from blog posts, from articles, and from the + pointers prepended to every documentation `index.md`. +- **Code samples belong in `documentation/headless/snippets/`**, not written + inline. They are compilable sources that CI type-checks against the real + client libraries, and `automation/snippets/generate-md.py` derives the + Markdown. See `automation/snippets/README.md`. +- **Prompts belong in `documentation/headless/prompts/`**, one file per prompt, + included with `{{< prompt "id" >}}`. A prompt body written inline on a page + reaches the agent-facing `index.md`, where an instruction addressed to an + agent can displace the question that agent was actually asked. See + `automation/prompts/README.md`. +- **Agent skill links are `https://skills.qdrant.tech//SKILL.md`.** The + bare path without the suffix returns 404, meta skills live under `meta/`, and + a path that exists in the `qdrant/skills` repository is not necessarily + published. `https://skills.qdrant.tech/llms.txt` lists what is actually + served. + +## Writing style + +American English, Oxford commas, straight quotes. No em dashes. No directional +language: an element is not "below" or "above", because the Markdown output, +the mobile layout, and a screen reader all order things differently. Name the +thing instead. + +## Before opening a pull request + +```bash +automation/prompts/check-prompts.sh # prompt rules, source only, seconds +automation/prompts/check-skill-links.sh # skill links resolve, needs network +automation/snippets/generate-md.py # if you touched snippets, then commit the result +``` + +Run `git add -A` or `git add :/` from anywhere other than the repository root. +Plain `git add .` inside `qdrant-landing/` silently misses changes to +`automation/` and `.github/`. + +## Two traps in the templates + +- **`.Section` returns the top-level section, not the nested one.** For + `/documentation/agentic-tools/skills/` it is `documentation`. Gating an asset + on it loads that asset on every documentation page, several hundred of them. + Check the path instead. +- **`[data-theme='light'] &` does not work inside a compound selector.** Nested + under `&__a &__b` it compiles to `.a [data-theme=light] .b`, which puts the + attribute in descendant position where it can never match, because the theme + attribute sits on ``. Write those rules out longhand. diff --git a/automation/prompts/README.md b/automation/prompts/README.md index 55a32cde7..efaadf455 100644 --- a/automation/prompts/README.md +++ b/automation/prompts/README.md @@ -42,9 +42,15 @@ pages include them by id. 2. Add `{{< prompt "" >}}` to that page, near the top of the section it relates to rather than at the bottom. -3. Run `automation/prompts/check-prompts.sh`. It needs no build. Pass a built - site directory to also verify the real output, for example - `automation/prompts/check-prompts.sh qdrant-landing/public`. +3. Run both checks: + + ```bash + automation/prompts/check-prompts.sh # source rules, no build, seconds + automation/prompts/check-skill-links.sh # skill links resolve, needs network + ``` + + `check-prompts.sh` also accepts a built site directory, to verify the real + output as well: `automation/prompts/check-prompts.sh qdrant-landing/public`. ## Writing one @@ -87,3 +93,19 @@ the Markdown variant of the shortcode must never render the body. Rule one is checked in the source rather than in the built output, because pasting a body inline is a source-level mistake and catching it there means CI needs no site build. + +## The third rule, which breaks without a commit + +**A skill link rots on its own.** A skill renamed or unpublished in +`qdrant/skills` breaks every reference to it here without anything in this +repository changing, so no pull request run would ever notice. +`check-skill-links.sh` covers that. It checks both places a skill path appears, +the `skill:` front matter and the `SKILL.md` URLs written inside prompt bodies +and documentation prose, against the catalog at +`https://skills.qdrant.tech/llms.txt`, and it also runs weekly on a schedule. + +It reaches the network, which is why it is a separate script and a separate CI +job. An unreachable catalog skips the run rather than failing it, so a docs pull +request never goes red because skills.qdrant.tech was down. A path missing from +the catalog is confirmed with a request before it is reported, since the catalog +can lag a freshly published skill. diff --git a/automation/prompts/check-skill-links.sh b/automation/prompts/check-skill-links.sh new file mode 100755 index 000000000..67618dedb --- /dev/null +++ b/automation/prompts/check-skill-links.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +# Verifies that every agent skill this repository points at is actually +# published on skills.qdrant.tech. +# +# Why this needs its own check. A skill reference breaks without anything in +# this repository changing: a skill gets renamed or unpublished in qdrant/skills +# and the link here rots in place. It is also easy to get wrong when writing, +# for two reasons that have each already produced a 404: +# +# - A path that exists in the qdrant/skills repository is not automatically +# served. The repository is not the source of truth; llms.txt is. +# - Meta skills live under meta/, as in meta/qdrant-advisor, not at the root +# alongside the domain skills. +# +# Two kinds of reference are checked, because both exist and they can disagree: +# +# 1. `skill:` in the front matter of a prompt, which the shortcode turns into +# a link and which the prompt index renders as a column. +# 2. Any https://skills.qdrant.tech//SKILL.md URL written in the content +# tree, which includes the URLs inside prompt bodies that tell the agent +# what to read, and ordinary prose links in the documentation. +# +# This check reaches the network, unlike check-prompts.sh, which is why it is a +# separate script and a separate CI job: skills.qdrant.tech being unreachable +# must not turn a documentation pull request red. An unreachable catalog skips +# the run; only a catalog that answers and does not list a path fails it. +# +# automation/prompts/check-skill-links.sh + +set -Eeuo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +content_dir="$repo_root/qdrant-landing/content" +prompts_dir="$content_dir/documentation/headless/prompts" +catalog_url="${SKILLS_CATALOG_URL:-https://skills.qdrant.tech/llms.txt}" +base_url="https://skills.qdrant.tech" + +failures=0 +fail() { + printf 'FAIL: %s\n' "$1" >&2 + failures=$((failures + 1)) +} + +# --- collect references, as "\t" --- + +refs="$( + # 1. skill: values in prompt front matter. + if [[ -d "$prompts_dir" ]]; then + for file in "$prompts_dir"/*.md; do + [[ -f "$file" ]] || continue + awk -v src="${file#"$repo_root"/}" -F': *' ' + /^---[[:space:]]*$/ { d++; if (d >= 2) exit; next } + d == 1 && $1 == "skill" { + gsub(/^[ \t"'"'"']+|[ \t"'"'"']+$/, "", $2) + if ($2 != "") print $2 "\t" src " (skill: front matter)" + exit + } + ' "$file" + done + fi + + # 2. SKILL.md URLs written anywhere in the content tree. The path is + # everything between the host and the /SKILL.md suffix. + grep -roE "https://skills\.qdrant\.tech/[A-Za-z0-9._/-]+/SKILL\.md" \ + --include='*.md' "$content_dir" 2>/dev/null \ + | sed -E "s|^${repo_root}/||" \ + | awk -F':' '{ src = $1; url = $0; sub(/^[^:]*:/, "", url) + sub(/^https:\/\/skills\.qdrant\.tech\//, "", url); sub(/\/SKILL\.md$/, "", url) + print url "\t" src " (SKILL.md link)" }' || true +)" + +if [[ -z "$refs" ]]; then + echo "No agent skill references found; nothing to check." + exit 0 +fi + +# --- fetch the catalog of what is actually served --- + +catalog="" +if ! catalog="$(curl -fsS --max-time 30 "$catalog_url" 2>/dev/null)" || [[ -z "$catalog" ]]; then + echo "Skipping: could not reach $catalog_url." + echo "This check is advisory and does not fail on an unreachable catalog." + exit 0 +fi + +# --- check each distinct path --- + +checked=0 +while IFS=$'\t' read -r path sources; do + [[ -n "$path" ]] || continue + checked=$((checked + 1)) + url="$base_url/$path/SKILL.md" + + if grep -qF "$url" <<<"$catalog"; then + continue + fi + + # The catalog can lag a freshly published skill, so a miss is confirmed with + # a request before it is reported. Only a path that is absent from both the + # catalog and the live site is a failure. + status="$(curl -fsS -o /dev/null -w '%{http_code}' --max-time 30 "$url" 2>/dev/null || true)" + if [[ "$status" == "200" ]]; then + printf 'note: %s is served but missing from the catalog at %s\n' "$path" "$catalog_url" + continue + fi + + fail "$path is not a published skill (${url} returned ${status:-no response})" + printf ' Referenced by: %s\n' "$sources" >&2 + printf ' Published skills are listed at %s\n' "$catalog_url" >&2 + printf ' Meta skills are under meta/, as in meta/qdrant-advisor.\n' >&2 +done < <( + # Distinct paths, with their sources joined so one bad path reports once. + sort -u <<<"$refs" | awk -F'\t' ' + { if ($1 in seen) seen[$1] = seen[$1] ", " $2; else { seen[$1] = $2; order[++n] = $1 } } + END { for (i = 1; i <= n; i++) print order[i] "\t" seen[order[i]] } + ' +) + +if (( failures > 0 )); then + printf '\n%d broken skill link(s) across %d referenced skill(s).\n' "$failures" "$checked" >&2 + exit 1 +fi + +printf 'Skill link checks passed: %d referenced skill(s).\n' "$checked" diff --git a/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md b/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md index 217f32c9c..d683c069b 100644 --- a/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md +++ b/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md @@ -15,5 +15,5 @@ | Prompt | Page | Agent skill | |---|---|---| {{ range $section.RegularPages.ByTitle -}} -| {{ .Title }} | {{ with .Params.page }}{{ . }}{{ else }}none{{ end }} | {{ with .Params.skill }}https://skills.qdrant.tech/{{ . }}/SKILL.md{{ else }}none{{ end }} | +| {{ .Title }} | {{ with .Params.page }}{{ . }}{{ else }}None{{ end }} | {{ with .Params.skill }}https://skills.qdrant.tech/{{ . }}/SKILL.md{{ else }}None{{ end }} | {{ end -}} diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html index 98f6e5918..ad52e49da 100644 --- a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html +++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html @@ -40,6 +40,8 @@ {{- else -}} {{ $p.Params.page }} {{- end -}} + {{- else -}} + None {{- end -}} From 0a2683237f5fc0ee4256e498cffbb0c3609696ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Tue, 15 Sep 2026 16:07:01 +0200 Subject: [PATCH 17/26] Small fixes. --- .github/workflows/prompts.yml | 7 ++- AGENTS.md | 6 +-- automation/prompts/README.md | 13 +++++ automation/prompts/check-prompts.sh | 29 ++++++++---- .../documentation/agentic-tools/_index.md | 9 ++-- .../documentation/agentic-tools/prompts.md | 2 +- .../headless/prompts/design-a-collection.md | 15 ++---- .../headless/prompts/diagnose-memory-usage.md | 9 +--- .../headless/prompts/review-before-launch.md | 8 +--- .../headless/prompts/set-up-monitoring.md | 7 +-- .../documentation/manage-data/collections.md | 2 +- .../ops-monitoring/monitoring.md | 2 +- .../ops-optimization/optimize.md | 2 +- .../documentation/production-checklist.md | 2 +- .../shortcodes/prompt-index.markdown.md | 6 ++- .../assets/css/components/_prompt.scss | 47 +++++++++++++++---- .../layouts/shortcodes/prompt.html | 17 ++++--- 17 files changed, 111 insertions(+), 72 deletions(-) diff --git a/.github/workflows/prompts.yml b/.github/workflows/prompts.yml index f866498fb..0546046df 100644 --- a/.github/workflows/prompts.yml +++ b/.github/workflows/prompts.yml @@ -4,8 +4,11 @@ on: pull_request: paths: - 'qdrant-landing/content/**/*.md' - - 'qdrant-landing/layouts/shortcodes/prompt.markdown.md' - - 'qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html' + # Every shortcode, not just the prompt ones: the Markdown variants are + # what keep prompt bodies out of the agent-facing output, and naming them + # individually is how prompt-index.markdown.md went unguarded. + - 'qdrant-landing/layouts/shortcodes/**' + - 'qdrant-landing/themes/qdrant-2024/layouts/shortcodes/**' - 'automation/prompts/**' - '.github/workflows/prompts.yml' # A skill link breaks when a skill is renamed or unpublished in qdrant/skills, diff --git a/AGENTS.md b/AGENTS.md index 5eacc582d..2e8d99b35 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -98,9 +98,9 @@ automation/prompts/check-skill-links.sh # skill links resolve, needs network automation/snippets/generate-md.py # if you touched snippets, then commit the result ``` -Run `git add -A` or `git add :/` from anywhere other than the repository root. -Plain `git add .` inside `qdrant-landing/` silently misses changes to -`automation/` and `.github/`. +When you are not at the repository root, stage with `git add -A` or +`git add :/`. Plain `git add .` inside `qdrant-landing/` silently misses +changes to `automation/` and `.github/`. ## Two traps in the templates diff --git a/automation/prompts/README.md b/automation/prompts/README.md index efaadf455..93c8e95b9 100644 --- a/automation/prompts/README.md +++ b/automation/prompts/README.md @@ -75,6 +75,19 @@ does. That split is why titles stay short, and why the type signal is consistent across every prompt rather than depending on each author phrasing it the same way. +## Formatting a prompt body + +**Do not hard-wrap prose.** Write each paragraph as one long line and let the +page wrap it. The element renders the body with `white-space: pre-wrap`, so any +line breaks you type are preserved, and a body wrapped at 80 columns keeps those +breaks in a content column that is narrower than that. `start-building` is the +exception: its numbered steps and indented commands are structure, so its line +breaks are content. + +**A body can contain anything, including fenced blocks.** The shortcode passes +it to Chroma as a value rather than re-parsing it as markdown, so a prompt that +includes a YAML or JSON snippet renders correctly. + ## Two rules that break silently **Prompt bodies must never reach a built `index.md`.** Those files are consumed diff --git a/automation/prompts/check-prompts.sh b/automation/prompts/check-prompts.sh index 355586149..9d4539981 100755 --- a/automation/prompts/check-prompts.sh +++ b/automation/prompts/check-prompts.sh @@ -9,8 +9,11 @@ # body, so the only way a body reaches index.md is an author pasting it as # a fenced block instead of using the shortcode. That is a source-level # mistake, so it is caught in the source. -# 2. The Markdown variant of the shortcode still drops the body. Rule 1 is -# only equivalent to "no body in index.md" while this holds. +# 2. No Markdown variant renders the body. Rule 1 is only equivalent to "no +# body in index.md" while this holds, and it has to cover every template +# that can reach a prompt's content, not just the element's. The index +# ranges the same pages, so a body added there lands in the built +# index.md exactly the same way. # 3. Every prompt's declared `page:` really includes it. The prompt files live # in one folder and cannot know who includes them, so the declaration is # what the index trusts. This also catches a prompt that is written but @@ -28,7 +31,12 @@ repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" public_dir="${1:-}" prompts_dir="$repo_root/qdrant-landing/content/documentation/headless/prompts" content_dir="$repo_root/qdrant-landing/content" -md_shortcode="$repo_root/qdrant-landing/layouts/shortcodes/prompt.markdown.md" +# Every Markdown-output template that can reach a prompt page. Add to this list +# rather than writing a new check if another one appears. +md_shortcodes=( + "$repo_root/qdrant-landing/layouts/shortcodes/prompt.markdown.md" + "$repo_root/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md" +) failures=0 @@ -42,12 +50,15 @@ if [[ ! -d "$prompts_dir" ]]; then exit 0 fi -# --- rule 2: the Markdown variant must not render the prompt body --- -if [[ ! -f "$md_shortcode" ]]; then - fail "missing $md_shortcode: without it, prompt bodies reach the agent-facing Markdown" -elif grep -qE '\.(RawContent|Content|Inner)\b' "$md_shortcode"; then - fail "$md_shortcode renders the prompt body; it must emit only the skill pointer" -fi +# --- rule 2: no Markdown variant may render the prompt body --- +for md_shortcode in "${md_shortcodes[@]}"; do + rel="${md_shortcode#"$repo_root"/}" + if [[ ! -f "$md_shortcode" ]]; then + fail "missing $rel: without it, prompt bodies reach the agent-facing Markdown" + elif grep -qE '\.(RawContent|Content|Inner)\b' "$md_shortcode"; then + fail "$rel renders the prompt body; it must emit only titles, pages, and skill pointers" + fi +done shopt -s nullglob checked=0 diff --git a/qdrant-landing/content/documentation/agentic-tools/_index.md b/qdrant-landing/content/documentation/agentic-tools/_index.md index ee9d25cbe..539a9ca0d 100644 --- a/qdrant-landing/content/documentation/agentic-tools/_index.md +++ b/qdrant-landing/content/documentation/agentic-tools/_index.md @@ -13,16 +13,17 @@ Use them to give your agent task-specific guidance, troubleshoot existing deploy ## Start Building -If you're new to Qdrant, paste this into your coding assistant. +If you're new to Qdrant, the Start building on Qdrant prompt takes your coding assistant from an empty project to a working search query. It stands up a local instance, installs the client with local embeddings, adds the [Qdrant Advisor](/documentation/agentic-tools/skills/#the-qdrant-advisor) skill, and then builds against your own use case. {{< prompt "start-building" >}} -Nothing in those four steps needs an account. +None of that needs an account. Qdrant runs in Docker and [FastEmbed](/documentation/fastembed/fastembed-quickstart/) generates embeddings on your machine, so you can go from nothing to a working search query without signing up for anything. -Step 4 does the work that matters. -A wrong collection configuration rarely fails loudly in vector search: a mismatched distance metric or a missing payload index returns plausible results and quietly costs you relevance, so it's worth making your agent commit to those choices out loud before it writes code. +The part that matters most is the collection configuration. +A wrong one rarely fails loudly in vector search: a mismatched distance metric or a missing payload index returns plausible results and quietly costs you relevance. +The prompt is written to make your assistant ask what you are building, then commit to those choices out loud before it writes any code. ## Agent Skills diff --git a/qdrant-landing/content/documentation/agentic-tools/prompts.md b/qdrant-landing/content/documentation/agentic-tools/prompts.md index 05b272a42..858b9d6bb 100644 --- a/qdrant-landing/content/documentation/agentic-tools/prompts.md +++ b/qdrant-landing/content/documentation/agentic-tools/prompts.md @@ -12,6 +12,6 @@ Qdrant documentation includes short, ready-to-use prompts on the pages where the Each prompt is collapsed by default, requires no additional input, and tells your assistant which [agent skill](/documentation/agentic-tools/skills/) to load. The prompt defines the task; the skill provides the Qdrant-specific guidance needed to complete it. -This page lists all available prompts. Follow a link to open the prompt alongside the documentation that provides its context. +This page lists all available prompts. Follow a link to jump to the prompt on the page that provides its context. {{< prompt-index >}} diff --git a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md index 2ae1470f4..0391021e9 100644 --- a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md +++ b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md @@ -1,15 +1,8 @@ --- title: "Design a collection" -skill: qdrant-multitenancy +# No skill: on purpose. The catalog has no collection-design skill, and +# qdrant-multitenancy would label the whole prompt as a tenancy prompt in +# the index. The body still links it where it is actually relevant. page: /documentation/manage-data/collections/ --- -Help me design a Qdrant collection for my data. Ask me what I am searching -over, roughly how many vectors I expect, which embedding model I am using, and -what I will filter on, before you write any code. Decide first whether this -should be one collection or many, reading -https://skills.qdrant.tech/qdrant-multitenancy/SKILL.md, since that choice -drives the index layout. Then derive the vector size from the model rather than -hardcoding it, name the distance metric the model was trained for and say why -you picked it, and add a payload index for every field I will filter on. Finish -by telling me which of these I cannot change later without recreating the -collection. +Help me design a Qdrant collection for my data. Ask me what I am searching over, roughly how many vectors I expect, which embedding model I am using, and what I will filter on, before you write any code. Decide first whether this should be one collection or many, reading https://skills.qdrant.tech/qdrant-multitenancy/SKILL.md, since that choice drives the index layout. Then derive the vector size from the model rather than hardcoding it, name the distance metric the model was trained for and say why you picked it, and add a payload index for every field I will filter on. Finish by telling me which of these I cannot change later without recreating the collection. diff --git a/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md b/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md index 76f1aa006..7a1c35b8e 100644 --- a/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md +++ b/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md @@ -3,11 +3,4 @@ title: "Diagnose high memory usage" skill: qdrant-performance-optimization/memory-usage-optimization page: /documentation/ops-optimization/optimize/ --- -My Qdrant memory usage is higher than I expected, or a node was killed for -running out of memory. Read -https://skills.qdrant.tech/qdrant-performance-optimization/memory-usage-optimization/SKILL.md -first, then ask me for my collection configuration before proposing anything. -Tell me which component is actually consuming the memory, whether that is the -vectors, the HNSW index, or the payload indexes, and give me the fixes in order -of impact. Say which ones need a reindex, and what recall I would lose if I -quantize. +My Qdrant memory usage is higher than I expected, or a node was killed for running out of memory. Read https://skills.qdrant.tech/qdrant-performance-optimization/memory-usage-optimization/SKILL.md first, then ask me for my collection configuration before proposing anything. Tell me which component is actually consuming the memory, whether that is the vectors, the HNSW index, or the payload indexes, and give me the fixes in order of impact. Say which ones need a reindex, and what recall I would lose if I quantize. diff --git a/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md b/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md index 4d9cb7808..1641b420c 100644 --- a/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md +++ b/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md @@ -3,10 +3,4 @@ title: "Review my deployment" skill: qdrant-sizing page: /documentation/production-checklist/ --- -Review my Qdrant deployment before I put production traffic on it. Read -https://skills.qdrant.tech/qdrant-sizing/SKILL.md, then ask me for my -collection configuration, my expected vector count and query rate, and the -hardware I have provisioned. Tell me which of my settings will not survive real -load, ordered by how much it would hurt, and separate what I can change later -from what needs the collection recreated. Where my numbers do not support a -conclusion, say what to measure rather than guessing. +Review my Qdrant deployment before I put production traffic on it. Read https://skills.qdrant.tech/qdrant-sizing/SKILL.md, then ask me for my collection configuration, my expected vector count and query rate, and the hardware I have provisioned. Tell me which of my settings will not survive real load, ordered by how much it would hurt, and separate what I can change later from what needs the collection recreated. Where my numbers do not support a conclusion, say what to measure rather than guessing. diff --git a/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md b/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md index e6fab07fa..cd7bdbb9e 100644 --- a/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md +++ b/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md @@ -3,9 +3,4 @@ title: "Set up monitoring" skill: qdrant-monitoring/setup page: /documentation/ops-monitoring/monitoring/ --- -Help me set up monitoring for my Qdrant deployment. Read -https://skills.qdrant.tech/qdrant-monitoring/setup/SKILL.md first, then ask me -whether I am self-hosted, on Qdrant Cloud, or on Hybrid Cloud, since the scrape -setup differs. Give me the Prometheus scrape config, the health probes worth -wiring up, and the three or four alerts that would actually have caught a real -incident. Tell me which metrics to ignore. +Help me set up monitoring for my Qdrant deployment. Read https://skills.qdrant.tech/qdrant-monitoring/setup/SKILL.md first, then ask me whether I am self-hosted, on Qdrant Cloud, or on Hybrid Cloud, since the scrape setup differs. Give me the Prometheus scrape config, the health probes worth wiring up, and the three or four alerts that would actually have caught a real incident. Tell me which metrics to ignore. diff --git a/qdrant-landing/content/documentation/manage-data/collections.md b/qdrant-landing/content/documentation/manage-data/collections.md index d1666d80e..9bfd9664c 100644 --- a/qdrant-landing/content/documentation/manage-data/collections.md +++ b/qdrant-landing/content/documentation/manage-data/collections.md @@ -29,7 +29,7 @@ Qdrant supports these most popular types of metrics: In addition to metrics and vector size, each collection uses its own set of parameters that controls collection optimization, index construction, and vacuum. These settings can be changed at any time by a corresponding request. -If you would rather have an agent design this with you, the following prompt asks it for your data and query shape first, then commits to a vector configuration and the payload indexes to create. +To hand this to an agent instead, the Design a collection prompt makes it ask about your data and query shape first, then commit to a vector configuration and the payload indexes to create. {{< prompt "design-a-collection" >}} diff --git a/qdrant-landing/content/documentation/ops-monitoring/monitoring.md b/qdrant-landing/content/documentation/ops-monitoring/monitoring.md index 1784c4aa0..9289d5cf8 100644 --- a/qdrant-landing/content/documentation/ops-monitoring/monitoring.md +++ b/qdrant-landing/content/documentation/ops-monitoring/monitoring.md @@ -21,7 +21,7 @@ The integration with Qdrant is easy to [configure](https://prometheus.io/docs/prometheus/latest/getting_started/#configure-prometheus-to-monitor-the-sample-targets) with Prometheus and Grafana. -If you would rather have an agent handle this, use the following prompt to select the appropriate configuration for your deployment type and recommend relevant alerts. +If you would rather have an agent handle this, the Set up monitoring prompt asks it to select the right configuration for your deployment type and recommend the alerts worth wiring up. {{< prompt "set-up-monitoring" >}} diff --git a/qdrant-landing/content/documentation/ops-optimization/optimize.md b/qdrant-landing/content/documentation/ops-optimization/optimize.md index fd6c16a85..e6e797425 100644 --- a/qdrant-landing/content/documentation/ops-optimization/optimize.md +++ b/qdrant-landing/content/documentation/ops-optimization/optimize.md @@ -25,7 +25,7 @@ This guide will walk you three main optimization strategies: This page covers the memory parameter introduced in Qdrant v1.19. If you're using an older version, see the Legacy Settings section for how to map the new parameter to the old ones. -If you would rather have an agent work through this with you, the following prompt asks it to find which component is actually using the memory before it suggests any changes. +An agent can work through this with you. The Diagnose high memory usage prompt makes it find which component is actually using the memory before it suggests any changes. {{< prompt "diagnose-memory-usage" >}} diff --git a/qdrant-landing/content/documentation/production-checklist.md b/qdrant-landing/content/documentation/production-checklist.md index 4c128be34..3a8676982 100644 --- a/qdrant-landing/content/documentation/production-checklist.md +++ b/qdrant-landing/content/documentation/production-checklist.md @@ -10,7 +10,7 @@ weight: 147 A practical checklist to ensure Qdrant is optimized, stable, and ready to handle real-world load. -If you would rather have an agent run through this with you, use the following prompt to get a prioritized list of what would break first under real load. +An agent can run the checklist with you. The Review my deployment prompt asks it for a prioritized list of what would break first under real load. {{< prompt "review-before-launch" >}} diff --git a/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md b/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md index d683c069b..4ad6b6e74 100644 --- a/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md +++ b/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md @@ -7,6 +7,10 @@ Keep in step with prompt-index.html, which emits table markup instead of pipes because shortcode output is not re-parsed as markdown. + + Page links are absolute and index.md-suffixed to match every other link in + this output, which single.markdown.md rewrites that way. A bare site path + would be the one column an agent reading this table could not resolve. */ -}} {{- $section := site.GetPage "documentation/headless/prompts" -}} {{- if not $section -}} @@ -15,5 +19,5 @@ | Prompt | Page | Agent skill | |---|---|---| {{ range $section.RegularPages.ByTitle -}} -| {{ .Title }} | {{ with .Params.page }}{{ . }}{{ else }}None{{ end }} | {{ with .Params.skill }}https://skills.qdrant.tech/{{ . }}/SKILL.md{{ else }}None{{ end }} | +| {{ .Title }} | {{ with .Params.page }}{{ with site.GetPage . }}{{ .Permalink }}index.md{{ else }}{{ . }}{{ end }}{{ else }}None{{ end }} | {{ with .Params.skill }}https://skills.qdrant.tech/{{ . }}/SKILL.md{{ else }}None{{ end }} | {{ end -}} diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index 236925e8a..8d1a2f1cf 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -1,10 +1,22 @@ @use '../helpers/functions' as *; +// Both themes are declared here so a palette change is a one-block edit. The +// light values were previously written as literals at the use site, which is +// how a palette silently stops being the palette. $prompt-surface: $neutral-20; $prompt-border: $neutral-40; $prompt-text: $neutral-98; $prompt-text-muted: $neutral-70; $prompt-accent: $primary-60; +// The body block sits deeper than the card. Without this it renders the same +// $neutral-20 as the card and the prompt reads as loose monospace in a box. +$prompt-block-surface: $neutral-10; + +$prompt-surface-light: $neutral-98; +$prompt-border-light: $neutral-94; +$prompt-text-light: $neutral-10; +$prompt-text-muted-light: $neutral-50; +$prompt-accent-light: $primary-40; .prompt { background: $prompt-surface; @@ -79,9 +91,24 @@ $prompt-accent: $primary-60; padding: 0 pxToRem(16) pxToRem(16); } - // The fenced block Chroma emits inside the body. + // The block Chroma emits inside the body. .highlight { margin: 0; + background: $prompt-block-surface; + } + + // A prompt is prose, not code. Its line breaks come from how the author + // wrapped the source file, so a fixed-width
 clips every line at any
+  // window narrower than the wrap width instead of reflowing. Sideways
+  // scrolling is a fair bargain for code and a bad one for a paragraph.
+  // pre-wrap keeps the deliberate line structure in prompts that have one.
+  .highlight > pre {
+    white-space: pre-wrap;
+    overflow-wrap: break-word;
+    // copy-code.js absolutely positions its button at the top right of
+    // .highlight. Wrapped text now reaches the full width, so the first line
+    // would run underneath it.
+    padding-right: pxToRem(56);
   }
 
   &__skill {
@@ -99,9 +126,9 @@ $prompt-accent: $primary-60;
   }
 
   [data-theme='light'] & {
-    background: $neutral-98;
-    border-color: $neutral-94;
-    border-left-color: $primary-40;
+    background: $prompt-surface-light;
+    border-color: $prompt-border-light;
+    border-left-color: $prompt-accent-light;
   }
 }
 
@@ -109,25 +136,25 @@ $prompt-accent: $primary-60;
 // lands in the descendant position, where it can never match, because the
 // theme attribute sits on .
 [data-theme='light'] .prompt__summary {
-  color: $neutral-10;
+  color: $prompt-text-light;
 }
 
 [data-theme='light'] .prompt__summary::before {
-  border-right-color: $primary-40;
-  border-bottom-color: $primary-40;
+  border-right-color: $prompt-accent-light;
+  border-bottom-color: $prompt-accent-light;
 }
 
 [data-theme='light'] .prompt__summary:hover {
-  color: $primary-40;
+  color: $prompt-accent-light;
 }
 
 [data-theme='light'] .prompt__skill,
 [data-theme='light'] .prompt__kind {
-  color: $neutral-50;
+  color: $prompt-text-muted-light;
 }
 
 [data-theme='light'] .prompt__kind {
-  border-right-color: $neutral-94;
+  border-right-color: $prompt-border-light;
 }
 
 @media (prefers-reduced-motion: reduce) {
diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html
index 51ca27bc9..5b162db80 100644
--- a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html
+++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html
@@ -3,10 +3,15 @@
 
   Usage: {{< prompt "set-up-monitoring" >}}
 
-  The prompt file's body is plain text. This template wraps it in a fenced
-  block and runs it through markdownify so Chroma produces a real
-  `.highlight > pre`, which copy-code.js finds and adds a copy button to. That
-  is why this element needs no JavaScript of its own.
+  The prompt file's body is plain text. `highlight` hands it to Chroma as a
+  value, producing a real `.highlight > pre`, which copy-code.js finds and adds
+  a copy button to. That is why this element needs no JavaScript of its own.
+
+  It is deliberately not wrapped in a fence and run through markdownify. A body
+  containing its own ``` would close that outer fence early, truncating the
+  prompt and spilling the rest of it onto the page as loose markdown, with a
+  clean build and a green check. `highlight` never re-parses the body, so a
+  prompt can contain any characters at all.
 
   The Markdown output format has its own variant, prompt.markdown.md, which
   deliberately drops the body so an agent reading index.md is not handed an
@@ -15,7 +20,7 @@
 {{- $id := .Get 0 -}}
 {{- $p := site.GetPage (printf "documentation/headless/prompts/%s" $id) -}}
 {{- if not $p -}}
-  {{- errorf "prompt: no prompt file found for id %q (looked in content/documentation/headless/prompts/). Called from %s" $id .Page.File.Path -}}
+  {{- errorf "prompt: no prompt file found for id %q (looked in content/documentation/headless/prompts/). Called from %s" $id .Page.RelPermalink -}}
 {{- end -}}
 
@@ -27,7 +32,7 @@ {{ $p.Title }}
- {{ printf "```text\n%s\n```" (trim $p.RawContent "\n") | markdownify }} + {{ highlight (trim $p.RawContent "\n") "text" "" }} {{- with $p.Params.skill }}

Uses the From b64e2bd9688bc14c9b333e56e3cc796b59c59b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Wed, 16 Sep 2026 10:14:18 +0200 Subject: [PATCH 18/26] Adjust SCSS. --- .../headless/prompts/start-building.md | 29 ++++++++++--------- .../layouts/shortcodes/prompt.markdown.md | 12 ++++++-- .../assets/css/components/_prompt.scss | 8 +++-- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/qdrant-landing/content/documentation/headless/prompts/start-building.md b/qdrant-landing/content/documentation/headless/prompts/start-building.md index 0c7796338..e9101d286 100644 --- a/qdrant-landing/content/documentation/headless/prompts/start-building.md +++ b/qdrant-landing/content/documentation/headless/prompts/start-building.md @@ -3,31 +3,32 @@ title: "Start building on Qdrant" page: /documentation/agentic-tools/ # Expanded because this prompt is the point of the hub page. Do not copy # this to an in-page prompt; those are always collapsed. +# +# This is the one prompt whose line breaks are structure rather than wrapping, +# so it keeps them. Two rules follow from that, both about pre-wrap wrapping a +# second time on a narrow screen: +# - Commands go on one line, however long. A backslash continuation wraps +# again and lands the continuation under the wrong column. +# - Prose inside a step is one line per step or bullet, never hard-wrapped. +# A 65-column source wrap colliding with a 37-column screen wrap leaves +# orphan fragments on their own lines. open: true skill: meta/qdrant-advisor --- Help me get started building on Qdrant. 1. Start Qdrant locally with Docker. No signup and no API key needed: - docker run -p 6333:6333 -p 6334:6334 \ - -v "$(pwd)/qdrant_storage:/qdrant/storage:z" \ - qdrant/qdrant + docker run -p 6333:6333 -p 6334:6334 -v "$(pwd)/qdrant_storage:/qdrant/storage:z" qdrant/qdrant Confirm it's running at http://localhost:6333/dashboard -2. Install the client with local embeddings, so I don't need an - embedding provider key either: +2. Install the client with local embeddings, so I don't need an embedding provider key either: pip install "qdrant-client[fastembed]" 3. Install the Qdrant Advisor agent skill: npx skills add qdrant/skills/meta/qdrant-advisor -4. Then ask me what I'm building and what I'll search over before you - write any code. Once you know, build the integration against my - local instance, and get the collection right the first time: - - Derive the vector size from the model with - client.get_embedding_size(model_name). Never hardcode a dimension. - - Choose the distance metric the model was trained for, and say - which one you picked and why. - - Create a payload index for every field I'll filter on, before I - load data rather than after. +4. Then ask me what I'm building and what I'll search over before you write any code. Once you know, build the integration against my local instance, and get the collection right the first time: + - Derive the vector size from the model with client.get_embedding_size(model_name). Never hardcode a dimension. + - Choose the distance metric the model was trained for, and say which one you picked and why. + - Create a payload index for every field I'll filter on, before I load data rather than after. Then load a small sample, run a real query, and show me the results. diff --git a/qdrant-landing/layouts/shortcodes/prompt.markdown.md b/qdrant-landing/layouts/shortcodes/prompt.markdown.md index dd56b4db0..edfd05245 100644 --- a/qdrant-landing/layouts/shortcodes/prompt.markdown.md +++ b/qdrant-landing/layouts/shortcodes/prompt.markdown.md @@ -6,11 +6,17 @@ it risks an agent following the prompt instead of answering the question it was actually asked. The skill pointer survives, because that is the part with genuine value to an agent. + + The title is always emitted, even when there is no skill. The prose around a + prompt refers to it by name, so a prompt that left no trace here would turn + that sentence into a reference to nothing, which is the failure this whole + variant exists to avoid creating. */ -}} {{- $id := .Get 0 -}} {{- $p := site.GetPage (printf "documentation/headless/prompts/%s" $id) -}} -{{- with $p -}} - {{- with .Params.skill }} +{{- with $p }} +> Prompt: {{ .Title }} +{{- with .Params.skill }} > Related agent skill: https://skills.qdrant.tech/{{ . }}/SKILL.md +{{- end }} {{ end -}} -{{- end -}} diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index 8d1a2f1cf..859e8bf8d 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -9,7 +9,8 @@ $prompt-text: $neutral-98; $prompt-text-muted: $neutral-70; $prompt-accent: $primary-60; // The body block sits deeper than the card. Without this it renders the same -// $neutral-20 as the card and the prompt reads as loose monospace in a box. +// $neutral-20 as the card, from .chroma, and the prompt reads as loose +// monospace in a box rather than as a block. $prompt-block-surface: $neutral-10; $prompt-surface-light: $neutral-98; @@ -94,7 +95,6 @@ $prompt-accent-light: $primary-40; // The block Chroma emits inside the body. .highlight { margin: 0; - background: $prompt-block-surface; } // A prompt is prose, not code. Its line breaks come from how the author @@ -103,6 +103,10 @@ $prompt-accent-light: $primary-40; // scrolling is a fair bargain for code and a bad one for a paragraph. // pre-wrap keeps the deliberate line structure in prompts that have one. .highlight > pre { + // On the pre, not on .highlight: Chroma puts class="chroma" on this + // element and syntax-highlight.scss gives .chroma its own background, so a + // color set on the parent is painted over and the change is invisible. + background: $prompt-block-surface; white-space: pre-wrap; overflow-wrap: break-word; // copy-code.js absolutely positions its button at the top right of From 78cd5e0c7660f9fae6a86581c595042ad98aa340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Wed, 16 Sep 2026 10:50:20 +0200 Subject: [PATCH 19/26] More SCSS. --- .../assets/css/components/_prompt.scss | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index 859e8bf8d..fadf1443e 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -14,6 +14,9 @@ $prompt-accent: $primary-60; $prompt-block-surface: $neutral-10; $prompt-surface-light: $neutral-98; +// In light mode the card is already light, so the block needs no extra depth +// to read as a block. It matches the other code blocks on the page instead. +$prompt-block-surface-light: $neutral-20; $prompt-border-light: $neutral-94; $prompt-text-light: $neutral-10; $prompt-text-muted-light: $neutral-50; @@ -102,6 +105,16 @@ $prompt-accent-light: $primary-40; // window narrower than the wrap width instead of reflowing. Sideways // scrolling is a fair bargain for code and a bad one for a paragraph. // pre-wrap keeps the deliberate line structure in prompts that have one. + // Chroma wraps every line in `.line > .cl`, and syntax-highlight.scss makes + // `.line` a flex container. A flex item will not shrink below its min-content + // width, so the `overflow-wrap` set on the pre never reaches a long token + // inside `.cl` and a docker command or a URL is clipped instead of wrapped. + // Letting the item shrink is what makes the wrapping rule take effect; + // setting `word-break` on the pre does not, because the constraint is here. + .highlight .cl { + min-width: 0; + } + .highlight > pre { // On the pre, not on .highlight: Chroma puts class="chroma" on this // element and syntax-highlight.scss gives .chroma its own background, so a @@ -152,6 +165,10 @@ $prompt-accent-light: $primary-40; color: $prompt-accent-light; } +[data-theme='light'] .prompt .highlight > pre { + background: $prompt-block-surface-light; +} + [data-theme='light'] .prompt__skill, [data-theme='light'] .prompt__kind { color: $prompt-text-muted-light; From 5270c2e9c4022f4a1b18b3668300ee2b2c23bd3e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 17 Sep 2026 09:42:49 +0000 Subject: [PATCH 20/26] Address requested review comments Co-authored-by: szabosteve <22324794+szabosteve@users.noreply.github.com> --- qdrant-landing/content/documentation/agentic-tools/_index.md | 4 +--- .../documentation/headless/prompts/design-a-collection.md | 2 +- .../content/documentation/headless/prompts/start-building.md | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/qdrant-landing/content/documentation/agentic-tools/_index.md b/qdrant-landing/content/documentation/agentic-tools/_index.md index 539a9ca0d..1916a36d9 100644 --- a/qdrant-landing/content/documentation/agentic-tools/_index.md +++ b/qdrant-landing/content/documentation/agentic-tools/_index.md @@ -18,11 +18,9 @@ It stands up a local instance, installs the client with local embeddings, adds t {{< prompt "start-building" >}} -None of that needs an account. Qdrant runs in Docker and [FastEmbed](/documentation/fastembed/fastembed-quickstart/) generates embeddings on your machine, so you can go from nothing to a working search query without signing up for anything. -The part that matters most is the collection configuration. -A wrong one rarely fails loudly in vector search: a mismatched distance metric or a missing payload index returns plausible results and quietly costs you relevance. +Collection configuration is important. A mismatched distance metric or a missing payload index can result in slower or lower quality search. The prompt is written to make your assistant ask what you are building, then commit to those choices out loud before it writes any code. ## Agent Skills diff --git a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md index 0391021e9..16fcdfca7 100644 --- a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md +++ b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md @@ -5,4 +5,4 @@ title: "Design a collection" # the index. The body still links it where it is actually relevant. page: /documentation/manage-data/collections/ --- -Help me design a Qdrant collection for my data. Ask me what I am searching over, roughly how many vectors I expect, which embedding model I am using, and what I will filter on, before you write any code. Decide first whether this should be one collection or many, reading https://skills.qdrant.tech/qdrant-multitenancy/SKILL.md, since that choice drives the index layout. Then derive the vector size from the model rather than hardcoding it, name the distance metric the model was trained for and say why you picked it, and add a payload index for every field I will filter on. Finish by telling me which of these I cannot change later without recreating the collection. +Help me design a Qdrant collection for my data. Ask me what I am searching over, roughly how many vectors I expect, which embedding model I am using, and what I will filter on, before you write any code. If the use case requires supporting multiple users, customers, or organizations, decide on a multitenancy strategy by reading https://skills.qdrant.tech/qdrant-multitenancy/SKILL.md. Then derive the vector size from the model rather than hardcoding it, name the distance metric the model was trained for and say why you picked it, and add a payload index for every field I will filter on. Finish by telling me which of these I cannot change later without recreating the collection. diff --git a/qdrant-landing/content/documentation/headless/prompts/start-building.md b/qdrant-landing/content/documentation/headless/prompts/start-building.md index e9101d286..71f6c1943 100644 --- a/qdrant-landing/content/documentation/headless/prompts/start-building.md +++ b/qdrant-landing/content/documentation/headless/prompts/start-building.md @@ -18,7 +18,7 @@ skill: meta/qdrant-advisor Help me get started building on Qdrant. 1. Start Qdrant locally with Docker. No signup and no API key needed: - docker run -p 6333:6333 -p 6334:6334 -v "$(pwd)/qdrant_storage:/qdrant/storage:z" qdrant/qdrant + docker run -d -p 6333:6333 -p 6334:6334 -v "$(pwd)/qdrant_storage:/qdrant/storage:z" qdrant/qdrant Confirm it's running at http://localhost:6333/dashboard 2. Install the client with local embeddings, so I don't need an embedding provider key either: From 540277fda37432e8e7a95d964164309ea13ebe26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 17 Sep 2026 12:38:04 +0200 Subject: [PATCH 21/26] Address human review feedback. --- automation/prompts/README.md | 26 ++++++++++------ automation/prompts/check-skill-links.sh | 31 +++++++++++++++---- .../headless/prompts/design-a-collection.md | 11 ++++--- .../headless/prompts/diagnose-memory-usage.md | 3 +- .../headless/prompts/review-before-launch.md | 3 +- .../headless/prompts/set-up-monitoring.md | 3 +- .../headless/prompts/start-building.md | 7 +++-- .../shortcodes/prompt-index.markdown.md | 4 +-- .../layouts/shortcodes/prompt.markdown.md | 2 +- qdrant-landing/static/_redirects | 9 ++++++ .../layouts/shortcodes/prompt-index.html | 10 ++++-- .../layouts/shortcodes/prompt.html | 14 ++++++--- 12 files changed, 88 insertions(+), 35 deletions(-) diff --git a/automation/prompts/README.md b/automation/prompts/README.md index 93c8e95b9..d0f097c42 100644 --- a/automation/prompts/README.md +++ b/automation/prompts/README.md @@ -11,9 +11,10 @@ pages include them by id. ```yaml --- - title: "Set up monitoring with an AI agent" - skill: qdrant-monitoring/setup + title: "Set up monitoring" page: /documentation/ops-monitoring/monitoring/ + skills: + - qdrant-monitoring/setup --- Help me set up monitoring for my Qdrant deployment. Read https://skills.qdrant.tech/qdrant-monitoring/setup/SKILL.md first, then ask @@ -24,13 +25,20 @@ pages include them by id. with an AI agent". The collapsed element already carries a `Prompt` marker placed by the shortcode, so working the word into the title says the same thing twice. Write it as the task, starting with a verb. - - `skill` is a path under `skills.qdrant.tech`, without the `/SKILL.md` - suffix. Omit it when no skill applies. Check the path resolves before - using it: `curl -I https://skills.qdrant.tech//SKILL.md`. The - published paths are listed in `https://skills.qdrant.tech/llms.txt`, and a - path in the `qdrant/skills` repo is not automatically published, so the - repo is not a reliable source for this value. Note the meta skills sit - under `meta/`, as in `meta/qdrant-advisor`. + - `skills` is **always a YAML sequence**, even for a single skill, so the + four templates that render it have one shape to handle rather than two. + The old scalar `skill:` key is rejected by CI rather than ignored. Each + entry is a path under `skills.qdrant.tech` without the `/SKILL.md` suffix. + List more than one when the prompt genuinely spans them, as + `design-a-collection` does across tenancy and sizing; the index renders + every entry. Omit the key entirely when no skill applies, rather than + reaching for the nearest one, because this value is what labels the prompt + in the index. Published paths are listed at + `https://skills.qdrant.tech/llms.txt`, and a path in the `qdrant/skills` + repo is not automatically published, so the repo is not a reliable source + for this value. Meta skills sit under `meta/`, as in `meta/qdrant-advisor`. + `check-skill-links.sh` verifies all of this, so there is no need to curl + by hand. - `page` is where the prompt is included. CI checks that page really includes it. - `open: true` renders the element expanded. **In-page prompts are always diff --git a/automation/prompts/check-skill-links.sh b/automation/prompts/check-skill-links.sh index 67618dedb..7cb8667f8 100755 --- a/automation/prompts/check-skill-links.sh +++ b/automation/prompts/check-skill-links.sh @@ -44,17 +44,26 @@ fail() { # --- collect references, as "\t" --- refs="$( - # 1. skill: values in prompt front matter. + # 1. skills: values in prompt front matter. Always a YAML sequence, even for + # a single skill, so there is one shape here and in all four templates. + # A file still using the old scalar `skill:` key emits a LEGACY marker + # rather than being silently skipped, which would leave it unchecked. if [[ -d "$prompts_dir" ]]; then for file in "$prompts_dir"/*.md; do [[ -f "$file" ]] || continue - awk -v src="${file#"$repo_root"/}" -F': *' ' + awk -v src="${file#"$repo_root"/}" ' /^---[[:space:]]*$/ { d++; if (d >= 2) exit; next } - d == 1 && $1 == "skill" { - gsub(/^[ \t"'"'"']+|[ \t"'"'"']+$/, "", $2) - if ($2 != "") print $2 "\t" src " (skill: front matter)" - exit + d != 1 { next } + /^skill:[[:space:]]/ { print "LEGACY-SKILL-KEY\t" src; next } + /^skills:[[:space:]]*$/ { inlist = 1; next } + inlist && /^[[:space:]]*-[[:space:]]*/ { + v = $0 + sub(/^[[:space:]]*-[[:space:]]*/, "", v) + gsub(/^["\x27[:space:]]+|["\x27[:space:]]+$/, "", v) + if (v != "") print v "\t" src " (skills: front matter)" + next } + /^[^[:space:]#]/ { inlist = 0 } ' "$file" done fi @@ -69,6 +78,16 @@ refs="$( print url "\t" src " (SKILL.md link)" }' || true )" +# A prompt still on the old scalar `skill:` key would contribute no references +# at all, so this check would pass while that prompt's link went unverified. +if legacy="$(grep -F 'LEGACY-SKILL-KEY' <<<"$refs" || true)" && [[ -n "$legacy" ]]; then + while IFS=$'\t' read -r _ src; do + [[ -n "$src" ]] && fail "$src uses the old scalar 'skill:' key; it must be a 'skills:' sequence" + done <<<"$legacy" + printf '\n%d prompt(s) on the legacy key.\n' "$failures" >&2 + exit 1 +fi + if [[ -z "$refs" ]]; then echo "No agent skill references found; nothing to check." exit 0 diff --git a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md index 16fcdfca7..b071d79cc 100644 --- a/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md +++ b/qdrant-landing/content/documentation/headless/prompts/design-a-collection.md @@ -1,8 +1,11 @@ --- title: "Design a collection" -# No skill: on purpose. The catalog has no collection-design skill, and -# qdrant-multitenancy would label the whole prompt as a tenancy prompt in -# the index. The body still links it where it is actually relevant. page: /documentation/manage-data/collections/ +# Two skills because the prompt genuinely spans both. Naming only one would +# label the whole prompt as that one thing, which is why this prompt had no +# skill at all before the body grew to cover sizing. +skills: + - qdrant-multitenancy + - qdrant-sizing --- -Help me design a Qdrant collection for my data. Ask me what I am searching over, roughly how many vectors I expect, which embedding model I am using, and what I will filter on, before you write any code. If the use case requires supporting multiple users, customers, or organizations, decide on a multitenancy strategy by reading https://skills.qdrant.tech/qdrant-multitenancy/SKILL.md. Then derive the vector size from the model rather than hardcoding it, name the distance metric the model was trained for and say why you picked it, and add a payload index for every field I will filter on. Finish by telling me which of these I cannot change later without recreating the collection. +Help me design a Qdrant collection for my data. Ask me what I am searching over, roughly how many vectors I expect and how fast that will grow, which embedding model I am using, what I will filter on, and what query rate I need, before you write any code. If the use case has to support multiple users, customers, or organizations, decide on a multitenancy strategy by reading https://skills.qdrant.tech/qdrant-multitenancy/SKILL.md. Then derive the vector size from the embedding model rather than hardcoding it, name the distance metric the model was trained for and say why you picked it, and add a payload index for every field I will filter on. Size it before I create anything, reading https://skills.qdrant.tech/qdrant-sizing/SKILL.md: tell me how much memory the vectors and the index will need, how many shards to create and why, whether I need replication, and whether the vectors belong in memory or on disk. If quantization would change that answer, say which kind, what it saves, and what it costs me in recall. Finish by telling me which of these I cannot change later without recreating the collection. diff --git a/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md b/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md index 7a1c35b8e..09968b896 100644 --- a/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md +++ b/qdrant-landing/content/documentation/headless/prompts/diagnose-memory-usage.md @@ -1,6 +1,7 @@ --- title: "Diagnose high memory usage" -skill: qdrant-performance-optimization/memory-usage-optimization +skills: + - qdrant-performance-optimization/memory-usage-optimization page: /documentation/ops-optimization/optimize/ --- My Qdrant memory usage is higher than I expected, or a node was killed for running out of memory. Read https://skills.qdrant.tech/qdrant-performance-optimization/memory-usage-optimization/SKILL.md first, then ask me for my collection configuration before proposing anything. Tell me which component is actually consuming the memory, whether that is the vectors, the HNSW index, or the payload indexes, and give me the fixes in order of impact. Say which ones need a reindex, and what recall I would lose if I quantize. diff --git a/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md b/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md index 1641b420c..70870855b 100644 --- a/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md +++ b/qdrant-landing/content/documentation/headless/prompts/review-before-launch.md @@ -1,6 +1,7 @@ --- title: "Review my deployment" -skill: qdrant-sizing +skills: + - qdrant-sizing page: /documentation/production-checklist/ --- Review my Qdrant deployment before I put production traffic on it. Read https://skills.qdrant.tech/qdrant-sizing/SKILL.md, then ask me for my collection configuration, my expected vector count and query rate, and the hardware I have provisioned. Tell me which of my settings will not survive real load, ordered by how much it would hurt, and separate what I can change later from what needs the collection recreated. Where my numbers do not support a conclusion, say what to measure rather than guessing. diff --git a/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md b/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md index cd7bdbb9e..fd900ab3c 100644 --- a/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md +++ b/qdrant-landing/content/documentation/headless/prompts/set-up-monitoring.md @@ -1,6 +1,7 @@ --- title: "Set up monitoring" -skill: qdrant-monitoring/setup +skills: + - qdrant-monitoring/setup page: /documentation/ops-monitoring/monitoring/ --- Help me set up monitoring for my Qdrant deployment. Read https://skills.qdrant.tech/qdrant-monitoring/setup/SKILL.md first, then ask me whether I am self-hosted, on Qdrant Cloud, or on Hybrid Cloud, since the scrape setup differs. Give me the Prometheus scrape config, the health probes worth wiring up, and the three or four alerts that would actually have caught a real incident. Tell me which metrics to ignore. diff --git a/qdrant-landing/content/documentation/headless/prompts/start-building.md b/qdrant-landing/content/documentation/headless/prompts/start-building.md index 71f6c1943..6faf2c195 100644 --- a/qdrant-landing/content/documentation/headless/prompts/start-building.md +++ b/qdrant-landing/content/documentation/headless/prompts/start-building.md @@ -13,7 +13,8 @@ page: /documentation/agentic-tools/ # A 65-column source wrap colliding with a 37-column screen wrap leaves # orphan fragments on their own lines. open: true -skill: meta/qdrant-advisor +skills: + - meta/qdrant-advisor --- Help me get started building on Qdrant. @@ -21,14 +22,14 @@ Help me get started building on Qdrant. docker run -d -p 6333:6333 -p 6334:6334 -v "$(pwd)/qdrant_storage:/qdrant/storage:z" qdrant/qdrant Confirm it's running at http://localhost:6333/dashboard -2. Install the client with local embeddings, so I don't need an embedding provider key either: +2. Ask me which language I want to build in, then install the Qdrant client for it. If I have no preference, use Python with local embeddings so I don't need an embedding provider key either: pip install "qdrant-client[fastembed]" 3. Install the Qdrant Advisor agent skill: npx skills add qdrant/skills/meta/qdrant-advisor 4. Then ask me what I'm building and what I'll search over before you write any code. Once you know, build the integration against my local instance, and get the collection right the first time: - - Derive the vector size from the model with client.get_embedding_size(model_name). Never hardcode a dimension. + - Derive the vector size from the embedding model itself. Never hardcode a dimension. - Choose the distance metric the model was trained for, and say which one you picked and why. - Create a payload index for every field I'll filter on, before I load data rather than after. Then load a small sample, run a real query, and show me the results. diff --git a/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md b/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md index 4ad6b6e74..f27f38ab9 100644 --- a/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md +++ b/qdrant-landing/layouts/shortcodes/prompt-index.markdown.md @@ -16,8 +16,8 @@ {{- if not $section -}} {{- errorf "prompt-index: cannot resolve documentation/headless/prompts (see prompt-index.html for the cause)." -}} {{- end -}} -| Prompt | Page | Agent skill | +| Prompt | Page | Agent skills | |---|---|---| {{ range $section.RegularPages.ByTitle -}} -| {{ .Title }} | {{ with .Params.page }}{{ with site.GetPage . }}{{ .Permalink }}index.md{{ else }}{{ . }}{{ end }}{{ else }}None{{ end }} | {{ with .Params.skill }}https://skills.qdrant.tech/{{ . }}/SKILL.md{{ else }}None{{ end }} | +| {{ .Title }} | {{ with .Params.page }}{{ with site.GetPage . }}{{ .Permalink }}index.md{{ else }}{{ . }}{{ end }}{{ else }}None{{ end }} | {{ with .Params.skills }}{{ range $i, $s := . }}{{ if $i }}, {{ end }}https://skills.qdrant.tech/{{ $s }}/SKILL.md{{ end }}{{ else }}None{{ end }} | {{ end -}} diff --git a/qdrant-landing/layouts/shortcodes/prompt.markdown.md b/qdrant-landing/layouts/shortcodes/prompt.markdown.md index edfd05245..e219ad326 100644 --- a/qdrant-landing/layouts/shortcodes/prompt.markdown.md +++ b/qdrant-landing/layouts/shortcodes/prompt.markdown.md @@ -16,7 +16,7 @@ {{- $p := site.GetPage (printf "documentation/headless/prompts/%s" $id) -}} {{- with $p }} > Prompt: {{ .Title }} -{{- with .Params.skill }} +{{- range .Params.skills }} > Related agent skill: https://skills.qdrant.tech/{{ . }}/SKILL.md {{- end }} {{ end -}} diff --git a/qdrant-landing/static/_redirects b/qdrant-landing/static/_redirects index ed7d693c4..8f92913e4 100644 --- a/qdrant-landing/static/_redirects +++ b/qdrant-landing/static/_redirects @@ -87,3 +87,12 @@ # ACORN blog post converted into an internals article /blog/filtered-vector-search-acorn/ /articles/filtered-vector-search-acorn/ 301 + +# Agent Skills moved under the Agentic Tools hub. The page's `aliases:` front +# matter already covers the HTML, but Hugo writes an alias as index.html with +# no index.md beside it, so the agent-facing form of the old URL 404s. That URL +# is linked from the pointers prepended to every documentation index.md, so the +# .md case is the one that matters most here. Left unforced on purpose: the +# alias stub is a real file and so keeps serving the HTML, and this rule applies +# where there is no file to shadow it. +/documentation/skills/* /documentation/agentic-tools/skills/:splat 301 diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html index ad52e49da..28d4780be 100644 --- a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html +++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt-index.html @@ -20,7 +20,7 @@ table. Adding a class here would silently opt out of both. */ -}} - + {{- range $section.RegularPages.ByTitle }} @@ -45,8 +45,12 @@ {{- end -}}
PromptPageAgent skill
PromptPageAgent skills
- {{- with $p.Params.skill -}} - {{ . }} + {{- $skills := $p.Params.skills -}} + {{- with $skills -}} + {{- range $i, $s := $skills -}} + {{- if $i }}, {{ end -}} + {{ $s }} + {{- end -}} {{- else -}} None {{- end -}} diff --git a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html index 5b162db80..b5e710c7b 100644 --- a/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html +++ b/qdrant-landing/themes/qdrant-2024/layouts/shortcodes/prompt.html @@ -28,16 +28,22 @@ the only discovery surface a prompt has, so the type marker is placed here by the shortcode rather than left to each author to work into the title. Prompt titles are therefore plain task names. */ -}} - Prompt + Agent Prompt {{ $p.Title }}
{{ highlight (trim $p.RawContent "\n") "text" "" }} - {{- with $p.Params.skill }} + {{- /* `skills` is always a sequence, even with one entry, so there is one + shape to render rather than two to keep in step. */ -}} + {{- $skills := $p.Params.skills }} + {{- with $skills }}

Uses the - {{ . }} - agent skill. + {{- range $i, $s := $skills -}} + {{- if $i }}{{ if eq (add $i 1) (len $skills) }} and{{ else }},{{ end }}{{ end }} + {{ $s }} + {{- end }} + agent skill{{ if gt (len $skills) 1 }}s{{ end }}. What are agent skills?

{{- end }} From 8130cdb680a19bea0406fe8fd724a98960f95807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Thu, 17 Sep 2026 15:09:51 +0200 Subject: [PATCH 22/26] Design changes. --- .../assets/css/components/_prompt.scss | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index fadf1443e..20fb1c9ab 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -4,10 +4,18 @@ // light values were previously written as literals at the use site, which is // how a palette silently stops being the palette. $prompt-surface: $neutral-20; -$prompt-border: $neutral-40; +$prompt-border: $neutral-30; $prompt-text: $neutral-98; $prompt-text-muted: $neutral-70; -$prompt-accent: $primary-60; +// Violet rather than red. Red is the site's interactive color, on buttons, +// links, and CTAs, so an accent bar in it reads as another call to action +// competing with the real ones on the page. Violet is the brand secondary and +// is unclaimed in the documentation callouts, where amber is alerts and +// $secondary-blue-10 is the status aside, so it marks a prompt as its own kind +// of thing. The surface stays neutral: the alerts pattern of a hue-tinted card +// works for a few lines of text and turns a card holding a code block into a +// slab that fights the code for attention. +$prompt-accent: $secondary-violet-50; // The body block sits deeper than the card. Without this it renders the same // $neutral-20 as the card, from .chroma, and the prompt reads as loose // monospace in a box rather than as a block. @@ -20,7 +28,7 @@ $prompt-block-surface-light: $neutral-20; $prompt-border-light: $neutral-94; $prompt-text-light: $neutral-10; $prompt-text-muted-light: $neutral-50; -$prompt-accent-light: $primary-40; +$prompt-accent-light: $secondary-violet-30; .prompt { background: $prompt-surface; @@ -91,6 +99,16 @@ $prompt-accent-light: $primary-40; min-width: 0; } + // `.documentation-article summary` sets margin-bottom: 1rem for the sidebar + // disclosures. Inside this element that margin lands below the summary, and + // `overflow: hidden` keeps it inside the box, so a collapsed prompt is 16px + // taller than its content and the title sits above center. Written as a + // descendant selector because the plain BEM class loses to that rule on + // specificity: one class against a class plus an element. + & &__summary { + margin-bottom: 0; + } + &__body { padding: 0 pxToRem(16) pxToRem(16); } From cc40d47f4f86c628eeeb05bfd446d8034d53687a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Fri, 18 Sep 2026 09:53:33 +0200 Subject: [PATCH 23/26] Address design feeback. --- .../qdrant-2024/assets/css/components/_prompt.scss | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index 20fb1c9ab..2570146ce 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -32,8 +32,10 @@ $prompt-accent-light: $secondary-violet-30; .prompt { background: $prompt-surface; + // A plain border on all four sides. An accent bar down the left was the + // first attempt at "visually distinct" and read as decoration rather than + // meaning. The surface, the kind marker, and the caret carry that job. border: 1px solid $prompt-border; - border-left: 3px solid $prompt-accent; border-radius: pxToRem(8); margin: pxToRem(24) 0; overflow: hidden; @@ -133,6 +135,15 @@ $prompt-accent-light: $secondary-violet-30; min-width: 0; } + // copy-code.js styles its button with a $neutral-20 fill, which is invisible + // on a normal code block because that is exactly the block's own color. This + // element gives its block a deeper surface so it reads as a block inside the + // card, and that made the fill show up as a grey chip around the icon. Only + // the icon is wanted, so the fill goes. + .copy-code { + background: transparent; + } + .highlight > pre { // On the pre, not on .highlight: Chroma puts class="chroma" on this // element and syntax-highlight.scss gives .chroma its own background, so a @@ -163,7 +174,6 @@ $prompt-accent-light: $secondary-violet-30; [data-theme='light'] & { background: $prompt-surface-light; border-color: $prompt-border-light; - border-left-color: $prompt-accent-light; } } From aa9766eebdfa964f74111a8150102947779ce290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Mon, 21 Sep 2026 11:13:28 +0200 Subject: [PATCH 24/26] Amend prompt layout. --- .../assets/css/components/_prompt.scss | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index 2570146ce..009d15144 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -20,6 +20,11 @@ $prompt-accent: $secondary-violet-50; // $neutral-20 as the card, from .chroma, and the prompt reads as loose // monospace in a box rather than as a block. $prompt-block-surface: $neutral-10; +// One step down from the $neutral-94 Chroma uses for code. At 15.3:1 on the +// block that is glare for something people read a paragraph of; this is 9.9:1, +// still comfortably AAA. The block is dark in both themes, so one value serves +// both. +$prompt-body-text: $neutral-80; $prompt-surface-light: $neutral-98; // In light mode the card is already light, so the block needs no extra depth @@ -144,6 +149,24 @@ $prompt-accent-light: $secondary-violet-30; background: transparent; } + // Chroma sets `.line` to font-size 16px with line-height 16px, a ratio of + // exactly 1, and supplies the breathing room with a margin between source + // lines. That works for code, where a line is short and never wraps. A + // prompt is prose: one long source line that pre-wrap breaks into many + // visual lines, and every one of those gets the 1.0 ratio with no margin at + // all, so the text packs into a slab. A real line height fixes it, and the + // margin goes so wrapped lines and source lines share one rhythm. Blank + // source lines still separate the steps in a structured prompt. + .highlight .line { + font-size: pxToRem(15); + line-height: 1.65; + color: $prompt-body-text; + + &:not(:last-of-type) { + margin-bottom: 0; + } + } + .highlight > pre { // On the pre, not on .highlight: Chroma puts class="chroma" on this // element and syntax-highlight.scss gives .chroma its own background, so a From cd184b84e1d713106c651f2a29ac5ca5d9aab459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20Zolt=C3=A1n=20Szab=C3=B3?= Date: Mon, 21 Sep 2026 13:14:37 +0200 Subject: [PATCH 25/26] Adjust lower box padding. --- .../qdrant-2024/assets/css/components/_prompt.scss | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index 009d15144..03f26901e 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -116,8 +116,20 @@ $prompt-accent-light: $secondary-violet-30; margin-bottom: 0; } + // The skill line is a

, and the same rule catches it: the shorthand on + // `&__skill` already sets its bottom margin to zero, but + // `.documentation-article p` outranks a single class and puts 1rem back, + // which then stacks on the body's bottom padding and pushes the line off + // centre. Anything in here that the docs article also styles by tag name + // needs this descendant form to win. + & &__skill { + margin-bottom: 0; + } + &__body { - padding: 0 pxToRem(16) pxToRem(16); + // The bottom padding matches the skill line's top margin, so that line + // sits centred between the prompt block and the bottom edge of the card. + padding: 0 pxToRem(16) pxToRem(12); } // The block Chroma emits inside the body. From f050578691c5aa724f3bdb44bcd3b2b4dbd16ec9 Mon Sep 17 00:00:00 2001 From: trean Date: Tue, 22 Sep 2026 09:46:31 +0200 Subject: [PATCH 26/26] propose prompt style (#2767) --- .../assets/css/components/_prompt.scss | 176 ++++++++++-------- 1 file changed, 97 insertions(+), 79 deletions(-) diff --git a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss index 03f26901e..9f16dfe0a 100644 --- a/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss +++ b/qdrant-landing/themes/qdrant-2024/assets/css/components/_prompt.scss @@ -1,58 +1,51 @@ @use '../helpers/functions' as *; -// Both themes are declared here so a palette change is a one-block edit. The -// light values were previously written as literals at the use site, which is -// how a palette silently stops being the palette. -$prompt-surface: $neutral-20; +// Both themes are declared here so a palette change is a one-block edit. $prompt-border: $neutral-30; $prompt-text: $neutral-98; -$prompt-text-muted: $neutral-70; -// Violet rather than red. Red is the site's interactive color, on buttons, -// links, and CTAs, so an accent bar in it reads as another call to action -// competing with the real ones on the page. Violet is the brand secondary and -// is unclaimed in the documentation callouts, where amber is alerts and -// $secondary-blue-10 is the status aside, so it marks a prompt as its own kind -// of thing. The surface stays neutral: the alerts pattern of a hue-tinted card -// works for a few lines of text and turns a card holding a code block into a -// slab that fights the code for attention. -$prompt-accent: $secondary-violet-50; -// The body block sits deeper than the card. Without this it renders the same -// $neutral-20 as the card, from .chroma, and the prompt reads as loose -// monospace in a box rather than as a block. +$prompt-text-secondary: $neutral-70; +// The site's interactive red. Used for the disclosure caret and the skill-line +// links, the only interactive marks in the component. +$prompt-accent: $primary-50; +// The dark card fill and the dark code block fill. Swapped from the usual +// arrangement: the card is the lighter $neutral-20 and the code block recesses +// to the $neutral-10 page tone. +$prompt-surface: $neutral-20; $prompt-block-surface: $neutral-10; -// One step down from the $neutral-94 Chroma uses for code. At 15.3:1 on the -// block that is glare for something people read a paragraph of; this is 9.9:1, -// still comfortably AAA. The block is dark in both themes, so one value serves -// both. -$prompt-body-text: $neutral-80; +// The code text color Chroma uses on this site. The block text is dark in both +// themes, so one value serves both. +$prompt-body-text: $neutral-94; -$prompt-surface-light: $neutral-98; -// In light mode the card is already light, so the block needs no extra depth -// to read as a block. It matches the other code blocks on the page instead. -$prompt-block-surface-light: $neutral-20; -$prompt-border-light: $neutral-94; +$prompt-border-light: $neutral-80; $prompt-text-light: $neutral-10; -$prompt-text-muted-light: $neutral-50; -$prompt-accent-light: $secondary-violet-30; +$prompt-text-secondary-light: $neutral-50; +// The light card fill, and the light code block's own darker fill on top of it. +$prompt-surface-light: $neutral-98; +$prompt-block-surface-light: $neutral-20; .prompt { + // Dark: the card is the lighter $neutral-20 and the code block recesses to + // $neutral-10. Light overrides this below with its own card and code fills. background: $prompt-surface; - // A plain border on all four sides. An accent bar down the left was the - // first attempt at "visually distinct" and read as decoration rather than - // meaning. The surface, the kind marker, and the caret carry that job. border: 1px solid $prompt-border; - border-radius: pxToRem(8); + border-radius: pxToRem(12); margin: pxToRem(24) 0; overflow: hidden; + // Grayscale antialiasing for the summary text, so Mona Sans renders light and + // crisp rather than the heavier subpixel default on macOS. + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; &__summary { display: flex; align-items: center; - gap: pxToRem(10); - padding: pxToRem(14) pxToRem(16); + gap: pxToRem(8); + padding: pxToRem(12) pxToRem(16); cursor: pointer; font-size: $font-size-md; font-weight: 600; + // The title inherits this; the kind marker overrides it with the secondary + // tier below. color: $prompt-text; list-style: none; @@ -60,24 +53,32 @@ $prompt-accent-light: $secondary-violet-30; display: none; } - // Disclosure caret, drawn rather than an icon file so it inherits color. + // Disclosure caret, drawn rather than an icon file. It sets its own color to + // the accent red and draws its borders in currentColor, so it stays red + // regardless of the summary text color. &::before { content: ''; flex: none; width: pxToRem(8); height: pxToRem(8); - border-right: 2px solid $prompt-accent; - border-bottom: 2px solid $prompt-accent; + border-right: 2px solid currentColor; + border-bottom: 2px solid currentColor; transform: rotate(-45deg); transition: transform 0.15s ease; - } - - &:hover { color: $prompt-accent; } + // On hover the kind marker lifts to the prominent color (the `&__kind` hover + // rule below) and the title is only underlined, not recolored. Same in both + // themes. + &:hover { + .prompt__summary-label { + text-decoration: underline; + } + } + &:focus-visible { - outline: 2px solid $prompt-accent; + outline: 2px solid currentColor; outline-offset: -2px; } } @@ -86,24 +87,29 @@ $prompt-accent-light: $secondary-violet-30; transform: rotate(45deg); } - // The kind marker: a category label, not disabled metadata. It uses the - // secondary text color rather than a true grey, because the collapsed - // summary is the only surface that tells a reader this element exists. + // The category label. It shares the title's type and differs only in color, + // dropping to the secondary tier, with the divider rule setting it apart. &__kind { flex: none; - font-size: pxToRem(11); - font-weight: 600; - letter-spacing: 0.08em; - text-transform: uppercase; - color: $prompt-text-muted; + color: $prompt-text-secondary; // Separates the marker from the title without a divider glyph. - padding-right: pxToRem(10); + padding-right: pxToRem(12); border-right: 1px solid $prompt-border; + transition: color 0.15s ease; + } + + // The one part that changes color on hover: the kind marker rises from the + // secondary tier to the title's prominent color, while the title only gains an + // underline. Light mode overrides the target below, where the prominent text + // is dark. Beats the base and light-theme `&__kind` colors on specificity. + &__summary:hover &__kind { + color: $prompt-text; } &__summary-label { // A prompt title can be long; wrap rather than overflow. min-width: 0; + transition: color 0.15s ease; } // `.documentation-article summary` sets margin-bottom: 1rem for the sidebar @@ -129,12 +135,15 @@ $prompt-accent-light: $secondary-violet-30; &__body { // The bottom padding matches the skill line's top margin, so that line // sits centred between the prompt block and the bottom edge of the card. - padding: 0 pxToRem(16) pxToRem(12); + padding: 0 pxToRem(16) pxToRem(16); } - // The block Chroma emits inside the body. + // The block Chroma emits inside the body. The card is transparent, so this + // is the only filled surface; it takes the card's corner radius itself + // rather than borrowing it from the card's overflow clip. .highlight { margin: 0; + border-radius: pxToRem(12); } // A prompt is prose, not code. Its line breaks come from how the author @@ -152,11 +161,8 @@ $prompt-accent-light: $secondary-violet-30; min-width: 0; } - // copy-code.js styles its button with a $neutral-20 fill, which is invisible - // on a normal code block because that is exactly the block's own color. This - // element gives its block a deeper surface so it reads as a block inside the - // card, and that made the fill show up as a grey chip around the icon. Only - // the icon is wanted, so the fill goes. + // copy-code.js gives its button a $neutral-20 fill, which shows as a grey chip + // against the surface behind it. Only the icon is wanted, so the fill goes. .copy-code { background: transparent; } @@ -170,8 +176,8 @@ $prompt-accent-light: $secondary-violet-30; // margin goes so wrapped lines and source lines share one rhythm. Blank // source lines still separate the steps in a structured prompt. .highlight .line { - font-size: pxToRem(15); - line-height: 1.65; + font-size: pxToRem(16); + line-height: 1.625; color: $prompt-body-text; &:not(:last-of-type) { @@ -183,7 +189,13 @@ $prompt-accent-light: $secondary-violet-30; // On the pre, not on .highlight: Chroma puts class="chroma" on this // element and syntax-highlight.scss gives .chroma its own background, so a // color set on the parent is painted over and the change is invisible. + // $neutral-10 in dark, so the block recesses below the lighter card; light + // gives it a $neutral-20 fill below. background: $prompt-block-surface; + // The pre carries the same radius as its .highlight wrapper so the fill's + // own corners are rounded, not just clipped by the wrapper. + border-radius: pxToRem(12); + padding: pxToRem(16); white-space: pre-wrap; overflow-wrap: break-word; // copy-code.js absolutely positions its button at the top right of @@ -194,16 +206,30 @@ $prompt-accent-light: $secondary-violet-30; &__skill { font-size: $font-size-s; - color: $prompt-text-muted; - margin: pxToRem(12) 0 0; + color: $prompt-text-secondary; + margin: pxToRem(16) 0 0; line-height: 1.5; code { font-family: $font-family-code; font-size: pxToRem(12); - background: none; - padding: 0; } + + a { + color: $prompt-accent; + text-decoration: none; + text-underline-offset: pxToRem(2); + + &:hover { + text-decoration: underline; + } + } + } + + & &__skill a code:not([class]) { + background: none; + padding: 0; + color: inherit; } [data-theme='light'] & { @@ -212,35 +238,27 @@ $prompt-accent-light: $secondary-violet-30; } } -// Written out longhand: inside a compound selector `[data-theme='light'] &` -// lands in the descendant position, where it can never match, because the -// theme attribute sits on . [data-theme='light'] .prompt__summary { color: $prompt-text-light; } -[data-theme='light'] .prompt__summary::before { - border-right-color: $prompt-accent-light; - border-bottom-color: $prompt-accent-light; -} - -[data-theme='light'] .prompt__summary:hover { - color: $prompt-accent-light; -} - -[data-theme='light'] .prompt .highlight > pre { - background: $prompt-block-surface-light; +[data-theme='light'] .prompt__summary:hover .prompt__kind { + color: $prompt-text-light; } [data-theme='light'] .prompt__skill, [data-theme='light'] .prompt__kind { - color: $prompt-text-muted-light; + color: $prompt-text-secondary-light; } [data-theme='light'] .prompt__kind { border-right-color: $prompt-border-light; } +[data-theme='light'] .prompt .highlight > pre { + background: $prompt-block-surface-light; +} + @media (prefers-reduced-motion: reduce) { .prompt__summary::before { transition: none;