{"type":"session","version":3,"id":"01a087fa-3448-755c-b81b-43cbc263c020","timestamp":"2026-09-09T21:01:56.680Z","cwd":"/app"}
{"type":"session_info","id":"6ef31679","parentId":null,"timestamp":"2026-09-09T21:01:56.681Z","name":"Natural quickstart session"}
{"type":"model_change","id":"12a66243","parentId":"6ef31679","timestamp":"2026-09-09T21:01:59.499Z","provider":"openrouter","modelId":"z-ai/glm-5.3-flash"}
{"type":"thinking_level_change","id":"d6087a24","parentId":"12a66243","timestamp":"2026-09-09T21:01:59.499Z","thinkingLevel":"high"}
{"type":"message","id":"26986628","parentId":"d6087a24","timestamp":"2026-09-09T21:01:59.571Z","message":{"role":"user","content":[{"type":"text","text":"Read /app/quickstart.mdx and implement the Antfly quickstart in /app. Run it and confirm that the quickstart's first search returns results. The target release is v0.2.1, not latest. Install that exact release with curl -fsSL https://releases.antfly.io/antfly/v0.2.1/install.sh | sh -s -- v0.2.1 and confirm antfly --version reports 0.2.1. The stopping objective is specifically the guide's 'Verify the basic data path' query on table hello: confirm it returns key first, title Hello, and body 'Antfly is ready.', then stop immediately and report the result. Do not continue to model installation, Wikipedia sample data, the later Search heading, embedding indexing, semantic search, or RAG. Use only the supplied guide and installed CLI help; do not inspect product source or the benchmark evaluator, substitute another release, or replace the documented standalone inference configuration."}],"timestamp":1788987719568}}
{"type":"message","id":"e550f4cb","parentId":"26986628","timestamp":"2026-09-09T21:02:01.390Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_bb88b26258134aa4bab41454","name":"read","arguments":{"path":"/app/quickstart.mdx"}}],"api":"openai-completions","provider":"openrouter","model":"z-ai/glm-5.3-flash","usage":{"input":1540,"output":16,"cacheRead":0,"cacheWrite":0,"reasoning":0,"totalTokens":1556,"cost":{"input":0.00011549999999999999,"output":0.000004,"cacheRead":0,"cacheWrite":0,"total":0.00011949999999999999}},"stopReason":"toolUse","timestamp":1788987719584,"responseId":"gen-1788987719-yneoIePYQxhdik6Q5L4R","rawStopReason":"tool_calls"}}
{"type":"message","id":"a6625a3c","parentId":"e550f4cb","timestamp":"2026-09-09T21:02:01.416Z","message":{"role":"toolResult","toolCallId":"call_bb88b26258134aa4bab41454","toolName":"read","content":[{"type":"text","text":"---\ntitle: Quickstart\ndescription: Install Antfly, load data, and run your first queries\nprerequisites:\n  - \"curl and jq (for sample data)\"\ndifficulty: beginner\nestimatedTime: \"45–90 min\"\ntags: [getting-started, setup, quickstart]\n---\n\nThis guide walks you through installing Antfly, loading data, and running your first queries — from full-text search to semantic search to AI-powered RAG.\n\nAllow 45–90 minutes on a laptop, excluding a source build. The basic full-text\ncheck takes seconds; model downloads and background indexing take most of the\ntime. Slower hardware may need longer timeouts.\n\n## Install Antfly\n\n<Tabs defaultValue=\"macos\">\n  <TabsList>\n    <TabsTrigger value=\"macos\">macOS</TabsTrigger>\n    <TabsTrigger value=\"linux\">Linux</TabsTrigger>\n    <TabsTrigger value=\"docker\">Docker</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"macos\">\n```bash\nbrew install antflydb/taps/antfly\n\n# Verify\nantfly --version\n```\n  </TabsContent>\n\n  <TabsContent value=\"linux\">\n```bash\ncurl -fsSL https://releases.antfly.io/antfly/latest/install.sh | sh\nexport PATH=\"$HOME/.local/bin:$PATH\"\n\n# Verify\nantfly --version\n```\n  </TabsContent>\n\n  <TabsContent value=\"docker\">\nSee the [Downloads page](/docs/downloads) for a complete Docker Compose setup with Antfly and Ollama.\n  </TabsContent>\n</Tabs>\n\n## Start Antfly\n\nStart Antfly in standalone mode:\n\n```bash\nantfly standalone --inference-host-budget-mb 8192 2>&1 | tee \"antfly.log\"\n```\n\nIf you installed with Homebrew, you can run Antfly as a service instead:\n\n```bash\nbrew services start antfly\n```\n\n<Callout type=\"info\">\nStandalone mode starts metadata, data nodes, and Antfly inference in a single process — ideal for local development. You can also access the [web dashboard](/docs/guides/dashboard) at `http://127.0.0.1:8080` to manage tables, run queries, and monitor your cluster. The numeric loopback address matches standalone's secure default bind on systems where `localhost` resolves to IPv6 first.\n</Callout>\n\nThe 8 GiB inference host budget lets the later all-local RAG example use the\nembedding, reranking, and Gemma models in one request. If you use a hosted\ngenerator instead, you can omit that option.\n\n### Verify the basic data path\n\nBefore starting the longer semantic workflow, verify that storage and full-text\nsearch work with one document:\n\n```bash\ncurl -fsS -X POST http://127.0.0.1:8080/db/v1/tables/hello \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\n\ncurl -fsS -X POST http://127.0.0.1:8080/db/v1/tables/hello/batch \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"inserts\":{\"first\":{\"title\":\"Hello\",\"body\":\"Antfly is ready.\"}},\"sync_level\":\"full_text\"}'\n\nantfly query --table hello \\\n  --full-text-search 'body:Antfly' \\\n  --fields 'title,body'\n```\n\nThe last command should return the document with key `first`. If it does not,\nstop here and use [Troubleshooting](#troubleshooting).\n\n### Install the text embedding model\n\nNow pull the text embedding model used for semantic search. [Antfly\ninference](/docs/guides/inference) runs models locally without an external API:\n\n```bash\nantfly inference pull hf:Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1\nantfly inference list\n```\n\nQwen3-Embedding uses an instruction for search queries but embeds indexed\ndocuments without it. Antfly applies that distinction automatically: index and\nartifact writes use the document role, while semantic searches use the query\nrole. The Q8_0 bundle runs on native CPU on Linux and macOS, and uses Metal\nautomatically when it is available.\n\nIf the running standalone process does not detect the newly installed model,\nrestart it once before creating the embeddings index.\n\nOnce the embeddings index reaches `queryable`, Antfly durably preserves that\npublished snapshot across later restarts while the remaining embeddings resume\nin the background. `complete` still means all source outcomes and the final\nvector publication have settled.\n\n## Download Sample Data\n\nIn a new terminal, download 10,000 Wikipedia articles enriched with thumbnail images:\n\n```bash\ncurl -L -o wiki-articles.jsonl https://cdn.antfly.io/datasets/wiki-articles-10k-v001.json\nhead -n 1 wiki-articles.jsonl | jq '.'\n```\n\nThe fixture is newline-delimited JSON (JSONL): one article per line. Every\narticle has `title`, `body`, and `url`; 2,446 of the 10,000 articles also have\nan optional `thumbnail_url` used later for image search.\n\n## Create a Table\n\nCreate a table with a text embedding index for semantic search:\n\n<Tabs defaultValue=\"cli\">\n  <TabsList>\n    <TabsTrigger value=\"cli\">CLI</TabsTrigger>\n    <TabsTrigger value=\"curl\">cURL</TabsTrigger>\n    <TabsTrigger value=\"typescript\">TypeScript</TabsTrigger>\n    <TabsTrigger value=\"python\">Python</TabsTrigger>\n    <TabsTrigger value=\"go\">Go</TabsTrigger>\n    <TabsTrigger value=\"rust\">Rust</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"cli\">\n```bash\nantfly table create --table wikipedia \\\n  --index '{\n    \"name\": \"title_body\",\n    \"type\": \"embeddings\",\n    \"template\": \"{{title}} {{body}}\",\n    \"embedder\": {\n      \"provider\": \"antfly\",\n      \"model\": \"Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1\"\n    },\n    \"chunker\": {\n      \"provider\": \"antfly\",\n      \"text\": {\n        \"target_tokens\": 200,\n        \"overlap_tokens\": 25\n      }\n    }\n  }'\n```\n  </TabsContent>\n\n  <TabsContent value=\"curl\">\n```bash\ncurl -X POST http://127.0.0.1:8080/db/v1/tables/wikipedia \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"indexes\": {\n      \"title_body\": {\n        \"type\": \"embeddings\",\n        \"template\": \"{{title}} {{body}}\",\n        \"embedder\": {\n          \"provider\": \"antfly\",\n          \"model\": \"Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1\"\n        },\n        \"chunker\": {\n          \"provider\": \"antfly\",\n          \"text\": {\n            \"target_tokens\": 200,\n            \"overlap_tokens\": 25\n          }\n        }\n      }\n    }\n  }'\n```\n  </TabsContent>\n\n  <TabsContent value=\"typescript\">\n```typescript\nimport { AntflyClient } from '@antfly/sdk';\n\nconst client = new AntflyClient({\n  baseUrl: 'http://127.0.0.1:8080',\n});\n\nawait client.tables.create('wikipedia', {\n  indexes: {\n    title_body: {\n      type: 'embeddings',\n      template: '{{title}} {{body}}',\n      embedder: {\n        provider: 'antfly',\n        model: 'Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1',\n      },\n      chunker: {\n        provider: 'antfly',\n        text: { target_tokens: 200, overlap_tokens: 25 },\n      },\n    },\n  },\n});\n```\n  </TabsContent>\n\n  <TabsContent value=\"python\">\n```python\nfrom antfly import AntflyClient\n\nclient = AntflyClient(base_url='http://127.0.0.1:8080')\n\nclient.create_table(\n    name='wikipedia',\n    indexes={\n        'title_body': {\n            'type': 'embeddings',\n            'template': '{{title}} {{body}}',\n            'embedder': {\n                'provider': 'antfly',\n                'model': 'Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1',\n            },\n            'chunker': {\n                'provider': 'antfly',\n                'text': {'target_tokens': 200, 'overlap_tokens': 25},\n            },\n        },\n    },\n)\n```\n  </TabsContent>\n\n  <TabsContent value=\"go\">\n```go\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net/http\"\n\n\tantfly \"github.com/antflydb/antfly/go/pkg/sdk\"\n\t\"github.com/antflydb/antfly/go/pkg/sdk/query\"\n)\n\nctx := context.Background()\nclient, err := antfly.NewAntflyClient(\"http://127.0.0.1:8080\", http.DefaultClient)\nif err != nil {\n\tlog.Fatal(err)\n}\n\nembedder, err := antfly.NewIndexEmbedderConfig(antfly.AntflyEmbedderConfig{\n\tModel: \"Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1\",\n})\nif err != nil { log.Fatal(err) }\n\ntitleBody, err := antfly.NewCreateIndexRequest(antfly.EmbeddingsIndexConfig{\n\tTemplate: \"{{title}} {{body}}\",\n\tEmbedder: *embedder,\n\tChunker: antfly.ChunkerConfig{\n\t\tProvider: antfly.ChunkerProviderAntfly,\n\t\tText: antfly.TextChunkOptions{\n\t\t\tTargetTokens: 200,\n\t\t\tOverlapTokens: 25,\n\t\t},\n\t},\n})\nif err != nil { log.Fatal(err) }\n\nerr = client.CreateTable(ctx, \"wikipedia\", antfly.CreateTableRequest{\n\tIndexes: map[string]antfly.CreateIndexRequest{\"title_body\": *titleBody},\n})\nif err != nil { log.Fatal(err) }\n```\n  </TabsContent>\n\n  <TabsContent value=\"rust\">\n```rust\nuse antfly_sdk::Client;\nuse serde_json::json;\n\nlet client = Client::new(\"http://127.0.0.1:8080\");\n\nclient.create_table(\"wikipedia\", &json!({\n    \"indexes\": {\n        \"title_body\": {\n            \"type\": \"embeddings\",\n            \"template\": \"{{title}} {{body}}\",\n            \"embedder\": {\n                \"provider\": \"antfly\",\n                \"model\": \"Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1\"\n            },\n            \"chunker\": {\n                \"provider\": \"antfly\",\n                \"text\": {\n                    \"target_tokens\": 200,\n                    \"overlap_tokens\": 25\n                }\n            }\n        }\n    }\n})).await?;\n```\n  </TabsContent>\n</Tabs>\n\nVerify the table and index were created:\n\n```bash\nantfly table list\nantfly index list --table wikipedia\n```\n\nAntfly also provisions `full_text_index_v0` automatically. That default index\nis what makes the full-text query later in this guide work; `title_body` is the\nmanaged embeddings index created above.\n\n## Load Data\n\n```bash\n# Load all 10,000 articles using the title as the document ID\nantfly load --table wikipedia \\\n  --file wiki-articles.jsonl \\\n  --id-field title \\\n  --sync-level full_text\n```\n\n<Callout type=\"info\">\nThis shared load step ensures that every query tab below runs against the same\ndataset. `full_text` fences the inexpensive text index for each load batch but\ndoes not wait for embeddings, which continue asynchronously. The CLI reads\nJSONL and batches documents automatically. Applications\nthat need to own ingestion should use the SDK [Batch Operations](/docs/api/data-operations)\nworkflow with bounded batches and retries.\n</Callout>\n\nEmbedding generation runs in the background. Wait until 10% of documents\nhave searchable embeddings; skipped documents are excluded:\n\n```bash\nantfly index wait --table wikipedia \\\n  --index title_body \\\n  --until source-covered=10% \\\n  --timeout 45m\n```\n\nContinue when this succeeds. Results improve as the remaining documents are\nindexed. To wait for the full corpus instead, use `--until complete`.\n\nUse `antfly index list --table wikipedia` to check progress. Timing depends on\nhardware; if the wait times out, see [Troubleshooting](#troubleshooting) before\ncontinuing.\n\n<Callout type=\"info\">\nArticles can produce multiple chunks, so `SEARCHABLE` may exceed the document\ncount. `avg_embeddings` measures chunk embeddings per second, not documents.\n</Callout>\n\n## Search\n\n<Callout type=\"info\">\nYou can run these queries using the CLI (shown below) or the [web dashboard](/docs/guides/dashboard) at `http://127.0.0.1:8080`.\n</Callout>\n\n### Full-Text Search\n\nSearch for articles containing specific terms:\n\n<Tabs defaultValue=\"cli\">\n  <TabsList>\n    <TabsTrigger value=\"cli\">CLI</TabsTrigger>\n    <TabsTrigger value=\"curl\">cURL</TabsTrigger>\n    <TabsTrigger value=\"typescript\">TypeScript</TabsTrigger>\n    <TabsTrigger value=\"python\">Python</TabsTrigger>\n    <TabsTrigger value=\"go\">Go</TabsTrigger>\n    <TabsTrigger value=\"rust\">Rust</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"cli\">\n```bash\nantfly query --table wikipedia \\\n  --full-text-search 'body:\"Korea\"' \\\n  --fields \"title,url\" \\\n  --limit 5\n```\n  </TabsContent>\n\n  <TabsContent value=\"curl\">\n```bash\ncurl -X POST http://127.0.0.1:8080/db/v1/query \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"table\": \"wikipedia\",\n    \"full_text_search\": {\"query\": \"body:\\\"Korea\\\"\"},\n    \"fields\": [\"title\", \"url\"],\n    \"limit\": 5\n  }'\n```\n  </TabsContent>\n\n  <TabsContent value=\"typescript\">\n```typescript\nconst results = await client.query({\n  table: 'wikipedia',\n  full_text_search: { query: 'body:\"Korea\"' },\n  fields: ['title', 'url'],\n  limit: 5,\n});\n\nfor (const hit of results.hits) {\n  console.log(hit.key, hit.fields);\n}\n```\n  </TabsContent>\n\n  <TabsContent value=\"python\">\n```python\nresults = client.query(\n    table='wikipedia',\n    full_text_search={'query': 'body:\"Korea\"'},\n    fields=['title', 'url'],\n    limit=5,\n)\n\nfor hit in results.hits:\n    print(hit.key, hit.fields)\n```\n  </TabsContent>\n\n  <TabsContent value=\"go\">\n```go\nfullText := query.NewQueryString(`body:\"Korea\"`)\nresults, err := client.Query(ctx, antfly.QueryRequest{\n\tTable:          \"wikipedia\",\n\tFullTextSearch: &fullText,\n\tFields:         []string{\"title\", \"url\"},\n\tLimit:          5,\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", results)\n```\n  </TabsContent>\n\n  <TabsContent value=\"rust\">\n```rust\nuse antfly_sdk::types::{GlobalQueryBody, FullTextSearch};\n\nlet resp = client\n    .global_query(&GlobalQueryBody {\n        table: Some(\"wikipedia\".to_string()),\n        full_text_search: Some(FullTextSearch {\n            query: Some(\"body:\\\"Korea\\\"\".to_string()),\n            ..Default::default()\n        }),\n        fields: Some(vec![\"title\".to_string(), \"url\".to_string()]),\n        limit: Some(5),\n        ..Default::default()\n    })\n    .await?;\n\nfor response in &resp.into_inner().responses {\n    if let Some(hits) = &response.hits {\n        for hit in &hits.hits {\n            println!(\"{}: {:?}\", hit.id, hit.source);\n        }\n    }\n}\n```\n  </TabsContent>\n</Tabs>\n\n### Semantic Search\n\nFind articles semantically similar to a natural language query:\n\n<Tabs defaultValue=\"cli\">\n  <TabsList>\n    <TabsTrigger value=\"cli\">CLI</TabsTrigger>\n    <TabsTrigger value=\"curl\">cURL</TabsTrigger>\n    <TabsTrigger value=\"typescript\">TypeScript</TabsTrigger>\n    <TabsTrigger value=\"python\">Python</TabsTrigger>\n    <TabsTrigger value=\"go\">Go</TabsTrigger>\n    <TabsTrigger value=\"rust\">Rust</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"cli\">\n```bash\nantfly query --table wikipedia \\\n  --semantic-search \"anatomy and physiology\" \\\n  --indexes \"title_body\" \\\n  --fields \"title,url\" \\\n  --limit 5\n```\n  </TabsContent>\n\n  <TabsContent value=\"curl\">\n```bash\ncurl -X POST http://127.0.0.1:8080/db/v1/query \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"table\": \"wikipedia\",\n    \"semantic_search\": \"anatomy and physiology\",\n    \"indexes\": [\"title_body\"],\n    \"fields\": [\"title\", \"url\"],\n    \"limit\": 5\n  }'\n```\n  </TabsContent>\n\n  <TabsContent value=\"typescript\">\n```typescript\nconst results = await client.query({\n  table: 'wikipedia',\n  semantic_search: 'anatomy and physiology',\n  indexes: ['title_body'],\n  fields: ['title', 'url'],\n  limit: 5,\n});\n\nfor (const hit of results.hits) {\n  console.log(hit.key, hit.fields);\n}\n```\n  </TabsContent>\n\n  <TabsContent value=\"python\">\n```python\nresults = client.query(\n    table='wikipedia',\n    semantic_search='anatomy and physiology',\n    indexes=['title_body'],\n    fields=['title', 'url'],\n    limit=5,\n)\n\nfor hit in results.hits:\n    print(hit.key, hit.fields)\n```\n  </TabsContent>\n\n  <TabsContent value=\"go\">\n```go\nresults, err := client.Query(ctx, antfly.QueryRequest{\n\tTable:          \"wikipedia\",\n\tSemanticSearch: \"anatomy and physiology\",\n\tIndexes:        []string{\"title_body\"},\n\tFields:         []string{\"title\", \"url\"},\n\tLimit:          5,\n})\nif err != nil {\n\tlog.Fatal(err)\n}\nfmt.Printf(\"%+v\\n\", results)\n```\n  </TabsContent>\n\n  <TabsContent value=\"rust\">\n```rust\nlet resp = client\n    .global_query(&GlobalQueryBody {\n        table: Some(\"wikipedia\".to_string()),\n        semantic_search: Some(\"anatomy and physiology\".to_string()),\n        indexes: Some(vec![\"title_body\".to_string()]),\n        fields: Some(vec![\"title\".to_string(), \"url\".to_string()]),\n        limit: Some(5),\n        ..Default::default()\n    })\n    .await?;\n\nfor response in &resp.into_inner().responses {\n    if let Some(hits) = &response.hits {\n        for hit in &hits.hits {\n            println!(\"{}: {:?}\", hit.id, hit.source);\n        }\n    }\n}\n```\n  </TabsContent>\n</Tabs>\n\n<Callout type=\"tip\">\nYou've loaded 10,000 documents and run your first full-text and semantic searches. From here, the guide builds on what you have — adding reranking, image search, and RAG.\n</Callout>\n\n## Hybrid Search & Reranking\n\nHybrid search combines full-text and semantic search using Reciprocal Rank Fusion (RRF). The Qwen3 text reranker jointly scores each query-document pair to improve the ordering of those candidates.\n\nPull the reranker model:\n\n```bash\nantfly inference pull hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0 --tasks rerank\n```\n\n<Callout type=\"info\">\nIf Antfly doesn't detect the new model, restart `antfly standalone`.\n</Callout>\n\nThe Q8 model is about 610 MiB and runs on native CPU or Metal. The first query\nloads it; reranking full articles can take tens of seconds, especially while\nindexing continues.\n\n<Tabs defaultValue=\"cli\">\n  <TabsList>\n    <TabsTrigger value=\"cli\">CLI</TabsTrigger>\n    <TabsTrigger value=\"curl\">cURL</TabsTrigger>\n    <TabsTrigger value=\"typescript\">TypeScript</TabsTrigger>\n    <TabsTrigger value=\"python\">Python</TabsTrigger>\n    <TabsTrigger value=\"go\">Go</TabsTrigger>\n    <TabsTrigger value=\"rust\">Rust</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"cli\">\n```bash\nantfly query --table wikipedia \\\n  --full-text-search 'body:Einstein' \\\n  --semantic-search \"theory of relativity and physics\" \\\n  --indexes \"title_body\" \\\n  --fields \"title,url\" \\\n  --limit 10 \\\n  --reranker '{\n      \"provider\": \"antfly\",\n      \"model\": \"ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0\",\n      \"field\": \"body\"\n    }' \\\n  --pruner '{\"min_score_ratio\": 0.01}'\n```\n  </TabsContent>\n\n  <TabsContent value=\"curl\">\n```bash\ncurl -X POST http://127.0.0.1:8080/db/v1/query \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"table\": \"wikipedia\",\n    \"full_text_search\": {\"query\": \"body:Einstein\"},\n    \"semantic_search\": \"theory of relativity and physics\",\n    \"indexes\": [\"title_body\"],\n    \"fields\": [\"title\", \"url\"],\n    \"limit\": 10,\n    \"reranker\": {\n      \"provider\": \"antfly\",\n      \"model\": \"ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0\",\n      \"field\": \"body\"\n    },\n    \"pruner\": {\"min_score_ratio\": 0.01}\n  }'\n```\n  </TabsContent>\n\n  <TabsContent value=\"typescript\">\n```typescript\nconst results = await client.query({\n  table: 'wikipedia',\n  full_text_search: { query: 'body:Einstein' },\n  semantic_search: 'theory of relativity and physics',\n  indexes: ['title_body'],\n  fields: ['title', 'url'],\n  limit: 10,\n  reranker: {\n    provider: 'antfly',\n    model: 'ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0',\n    field: 'body',\n  },\n  pruner: { min_score_ratio: 0.01 },\n});\n```\n  </TabsContent>\n\n  <TabsContent value=\"python\">\n```python\nresults = client.query(\n    table='wikipedia',\n    full_text_search={'query': 'body:Einstein'},\n    semantic_search='theory of relativity and physics',\n    indexes=['title_body'],\n    fields=['title', 'url'],\n    limit=10,\n    reranker={\n        'provider': 'antfly',\n        'model': 'ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0',\n        'field': 'body',\n    },\n    pruner={'min_score_ratio': 0.01},\n)\n```\n  </TabsContent>\n\n  <TabsContent value=\"go\">\n```go\nreranker, err := antfly.NewRerankerConfig(antfly.AntflyRerankerConfig{\n\tModel: \"ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0\",\n})\nif err != nil { log.Fatal(err) }\nreranker.Field = \"body\"\nfullText = query.NewQueryString(\"body:Einstein\")\nresults, err := client.Query(ctx, antfly.QueryRequest{\n\tTable:          \"wikipedia\",\n\tFullTextSearch: &fullText,\n\tSemanticSearch: \"theory of relativity and physics\",\n\tIndexes:        []string{\"title_body\"},\n\tFields:         []string{\"title\", \"url\"},\n\tLimit:          10,\n\tReranker:       reranker,\n\tPruner:         antfly.Pruner{MinScoreRatio: 0.01},\n})\nif err != nil { log.Fatal(err) }\nfmt.Printf(\"%+v\\n\", results)\n```\n  </TabsContent>\n\n  <TabsContent value=\"rust\">\n```rust\nlet resp = client\n    .global_query(&GlobalQueryBody {\n        table: Some(\"wikipedia\".to_string()),\n        full_text_search: Some(FullTextSearch {\n            query: Some(\"body:Einstein\".to_string()),\n            ..Default::default()\n        }),\n        semantic_search: Some(\"theory of relativity and physics\".to_string()),\n        indexes: Some(vec![\"title_body\".to_string()]),\n        fields: Some(vec![\"title\".to_string(), \"url\".to_string()]),\n        limit: Some(10),\n        reranker: Some(json!({\n            \"provider\": \"antfly\",\n            \"model\": \"ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0\",\n            \"field\": \"body\"\n        })),\n        pruner: Some(json!({\"min_score_ratio\": 0.01})),\n        ..Default::default()\n    })\n    .await?;\n```\n  </TabsContent>\n</Tabs>\n\n<Callout type=\"info\">\n**Reranking vs Pruning:**\n- **Reranking** re-scores each query-document pair for relevance. It improves ordering but keeps the same number of results.\n- **Pruning** filters out low-relevance results based on score quality. Use `min_score_ratio` to keep only results scoring at least N% of the top result, or `max_score_gap_percent` to detect \"elbows\" in score distribution.\n</Callout>\n\n## Image Search\n\nSearch by visual content using ClipClap, a multimodal embedding model that understands text, images, and audio.\n\n<Steps>\n### Confirm the ClipClap model is available\n\n```bash\nantfly inference pull antflydb/clipclap:gguf:Q4_K\n```\n\n<Callout type=\"info\">\nIf Antfly doesn't detect the new model, restart `antfly standalone`.\n</Callout>\n\n### Add an image index to your table\n\nAdd a ClipClap-based index to embed each article's Wikipedia thumbnail:\n\n<Tabs defaultValue=\"cli\">\n  <TabsList>\n    <TabsTrigger value=\"cli\">CLI</TabsTrigger>\n    <TabsTrigger value=\"curl\">cURL</TabsTrigger>\n    <TabsTrigger value=\"typescript\">TypeScript</TabsTrigger>\n    <TabsTrigger value=\"python\">Python</TabsTrigger>\n    <TabsTrigger value=\"go\">Go</TabsTrigger>\n    <TabsTrigger value=\"rust\">Rust</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"cli\">\n```bash\nantfly index create --table wikipedia \\\n  --index thumbnail \\\n  --type embeddings \\\n  --coverage-policy partial \\\n  --template \"{{#if thumbnail_url}}{{remoteMedia url=thumbnail_url}}{{/if}}\" \\\n  --embedder '{\"provider\": \"antfly\", \"model\": \"antflydb/clipclap\"}'\n```\n  </TabsContent>\n\n  <TabsContent value=\"curl\">\n```bash\ncurl -X POST http://127.0.0.1:8080/db/v1/tables/wikipedia/indexes/thumbnail \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"type\": \"embeddings\",\n    \"coverage_policy\": \"partial\",\n    \"template\": \"{{#if thumbnail_url}}{{remoteMedia url=thumbnail_url}}{{/if}}\",\n    \"embedder\": {\n      \"provider\": \"antfly\",\n      \"model\": \"antflydb/clipclap\"\n    },\n    \"distance_metric\": \"cosine\"\n  }'\n```\n  </TabsContent>\n\n  <TabsContent value=\"typescript\">\n```typescript\nconst createdIndex = await client.indexes.create('wikipedia', 'thumbnail', {\n  type: 'embeddings',\n  coverage_policy: 'partial',\n  template: '{{#if thumbnail_url}}{{remoteMedia url=thumbnail_url}}{{/if}}',\n  embedder: {\n    provider: 'antfly',\n    model: 'antflydb/clipclap',\n  },\n  distance_metric: 'cosine',\n});\n```\n  </TabsContent>\n\n  <TabsContent value=\"python\">\n```python\nfrom antfly import (\n    CreateEmbeddingsIndexRequest,\n    CreateEmbeddingsIndexRequestType,\n    DerivedCoveragePolicy,\n    DistanceMetric,\n    antfly_embedder,\n)\n\ncreated_index = client.indexes.create(\n    'wikipedia',\n    'thumbnail',\n    CreateEmbeddingsIndexRequest(\n        type_=CreateEmbeddingsIndexRequestType.EMBEDDINGS,\n        coverage_policy=DerivedCoveragePolicy.PARTIAL,\n        template='{{#if thumbnail_url}}{{remoteMedia url=thumbnail_url}}{{/if}}',\n        embedder=antfly_embedder('antflydb/clipclap'),\n        distance_metric=DistanceMetric.COSINE,\n    ),\n)\n```\n  </TabsContent>\n\n  <TabsContent value=\"go\">\n```go\nembedder, err := antfly.NewEmbedderConfig(antfly.AntflyEmbedderConfig{\n\tModel: \"antflydb/clipclap\",\n})\nif err != nil { log.Fatal(err) }\nrequest, err := antfly.NewCreateIndexRequest(antfly.EmbeddingsIndexConfig{\n\tCoveragePolicy: antfly.DerivedCoveragePolicyPartial,\n\tTemplate:       \"{{#if thumbnail_url}}{{remoteMedia url=thumbnail_url}}{{/if}}\",\n\tEmbedder:       *embedder,\n\tDistanceMetric: antfly.DistanceMetricCosine,\n})\nif err != nil { log.Fatal(err) }\ncreatedIndex, err := client.CreateIndex(ctx, \"wikipedia\", \"thumbnail\", *request)\nif err != nil { log.Fatal(err) }\nfmt.Printf(\"%+v\\n\", createdIndex)\n```\n  </TabsContent>\n\n  <TabsContent value=\"rust\">\n```rust\nuse antfly_sdk::types;\n\nlet request = types::CreateEmbeddingsIndexRequest {\n    coverage_policy: Some(types::DerivedCoveragePolicy::Partial),\n    template: Some(\"{{#if thumbnail_url}}{{remoteMedia url=thumbnail_url}}{{/if}}\".into()),\n    embedder: Some(antfly_sdk::antfly_embedder(\"antflydb/clipclap\")),\n    distance_metric: Some(types::DistanceMetric::Cosine),\n    ..Default::default()\n};\nlet request: types::CreateIndexRequest = request.into();\nlet created_index = client\n    .create_index(\"wikipedia\", \"thumbnail\", &request)\n    .await?\n    .into_inner();\n```\n  </TabsContent>\n</Tabs>\n\nAntfly probes the selected embedding model during creation and stores its\ndimension in the normalized index definition. Specify `dimension` only when\nyou also want creation to verify an explicit expected size.\n\nAdding an index starts background image indexing. Articles without thumbnails\nare skipped; wait for 250 searchable images before continuing.\n\n```bash\nantfly index wait --table wikipedia \\\n  --index thumbnail \\\n  --until searchable-artifacts=250 \\\n  --timeout 45m\n```\n\nUse `antfly index list --table wikipedia` to monitor detailed progress.\n\n### Search by visual content\n\nClipClap understands visual concepts, so you can describe what you're looking for in natural language:\n\n<Tabs defaultValue=\"cli\">\n  <TabsList>\n    <TabsTrigger value=\"cli\">CLI</TabsTrigger>\n    <TabsTrigger value=\"curl\">cURL</TabsTrigger>\n    <TabsTrigger value=\"typescript\">TypeScript</TabsTrigger>\n    <TabsTrigger value=\"python\">Python</TabsTrigger>\n    <TabsTrigger value=\"go\">Go</TabsTrigger>\n    <TabsTrigger value=\"rust\">Rust</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"cli\">\n```bash\nantfly query --table wikipedia \\\n  --semantic-search \"map of a country\" \\\n  --indexes \"thumbnail\" \\\n  --fields \"title,url,thumbnail_url\" \\\n  --limit 5\n```\n  </TabsContent>\n\n  <TabsContent value=\"curl\">\n```bash\ncurl -X POST http://127.0.0.1:8080/db/v1/query \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"table\": \"wikipedia\",\n    \"semantic_search\": \"map of a country\",\n    \"indexes\": [\"thumbnail\"],\n    \"fields\": [\"title\", \"url\", \"thumbnail_url\"],\n    \"limit\": 5\n  }'\n```\n  </TabsContent>\n\n  <TabsContent value=\"typescript\">\n```typescript\nconst results = await client.query({\n  table: 'wikipedia',\n  semantic_search: 'map of a country',\n  indexes: ['thumbnail'],\n  fields: ['title', 'url', 'thumbnail_url'],\n  limit: 5,\n});\n```\n  </TabsContent>\n\n  <TabsContent value=\"python\">\n```python\nresults = client.query(\n    table='wikipedia',\n    semantic_search='map of a country',\n    indexes=['thumbnail'],\n    fields=['title', 'url', 'thumbnail_url'],\n    limit=5,\n)\n```\n  </TabsContent>\n\n  <TabsContent value=\"go\">\n```go\nresults, err := client.Query(ctx, antfly.QueryRequest{\n\tTable:          \"wikipedia\",\n\tSemanticSearch: \"map of a country\",\n\tIndexes:        []string{\"thumbnail\"},\n\tFields:         []string{\"title\", \"url\", \"thumbnail_url\"},\n\tLimit:          5,\n})\nif err != nil { log.Fatal(err) }\nfmt.Printf(\"%+v\\n\", results)\n```\n  </TabsContent>\n\n  <TabsContent value=\"rust\">\n```rust\nlet resp = client\n    .global_query(&GlobalQueryBody {\n        table: Some(\"wikipedia\".to_string()),\n        semantic_search: Some(\"map of a country\".to_string()),\n        indexes: Some(vec![\"thumbnail\".to_string()]),\n        fields: Some(vec![\n            \"title\".to_string(),\n            \"url\".to_string(),\n            \"thumbnail_url\".to_string(),\n        ]),\n        limit: Some(5),\n        ..Default::default()\n    })\n    .await?;\n```\n  </TabsContent>\n</Tabs>\n\n<Callout type=\"tip\">\nMultimodal image search responds best to concrete visual descriptions (\"red sports car\", \"mountain landscape\") rather than abstract concepts. For a deeper dive, see the [Image Search with CLIP](/docs/examples/image-search) example.\n</Callout>\n</Steps>\n\n## RAG (Retrieval-Augmented Generation)\n\nCombine search with local LLM answer generation using the retrieval agent.\n\n<Steps>\n### Pull a generation model\n\n```bash\nantfly inference pull hf:ggml-org/gemma-4-E4B-it-GGUF:gguf:Q4_0 \\\n  --tasks generate \\\n  --projector auto\n```\n\n<Callout type=\"info\">\n`--projector auto` includes image and audio support. Try a local file with\n`antfly inference generate <model-dir> \"Describe this input\" --image ./photo.jpg`\nor `--audio ./clip.wav`. Use `--projector none` for a smaller, text-only download.\nThe RAG example below uses text and limits output to 512 tokens per model turn.\nFor other providers, see the [next step](#rag-with-alternative-providers).\n</Callout>\n\n### Build a query and generate an answer\n\nGive Gemma an intent and a table. The retrieval agent delegates query planning\nto the query builder, searches, and answers from the results.\n\n<Tabs defaultValue=\"cli\">\n  <TabsList>\n    <TabsTrigger value=\"cli\">CLI</TabsTrigger>\n    <TabsTrigger value=\"curl\">cURL</TabsTrigger>\n    <TabsTrigger value=\"typescript\">TypeScript</TabsTrigger>\n    <TabsTrigger value=\"python\">Python</TabsTrigger>\n    <TabsTrigger value=\"go\">Go</TabsTrigger>\n    <TabsTrigger value=\"rust\">Rust</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"cli\">\n```bash\nantfly agents retrieval --table wikipedia \\\n  --intent \"What are the major events in Korean history?\" \\\n  --fields \"title,body\" \\\n  --limit 5 \\\n  --generator '{\n    \"provider\": \"antfly\",\n    \"model\": \"ggml-org/gemma-4-E4B-it-GGUF\",\n    \"max_tokens\": 512\n  }' \\\n  --max-internal-iterations 8 \\\n  --streaming\n```\n  </TabsContent>\n\n  <TabsContent value=\"curl\">\n```bash\ncurl -N -X POST http://127.0.0.1:8080/db/v1/agents/retrieval \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Accept: text/event-stream\" \\\n  -d '{\n    \"query\": \"What are the major events in Korean history?\",\n    \"queries\": [{\n      \"table\": \"wikipedia\",\n      \"fields\": [\"title\", \"body\"],\n      \"limit\": 5\n    }],\n    \"generator\": {\n      \"provider\": \"antfly\",\n      \"model\": \"ggml-org/gemma-4-E4B-it-GGUF\",\n      \"max_tokens\": 512\n    },\n    \"max_internal_iterations\": 8,\n    \"stream\": true,\n    \"steps\": {\n      \"generation\": {\"enabled\": true}\n    }\n  }'\n```\n  </TabsContent>\n\n  <TabsContent value=\"typescript\">\n```typescript\nconst result = await client.agents.retrieval({\n  query: 'What are the major events in Korean history?',\n  queries: [{\n    table: 'wikipedia',\n    fields: ['title', 'body'],\n    limit: 5,\n  }],\n  generator: {\n    provider: 'antfly',\n    model: 'ggml-org/gemma-4-E4B-it-GGUF',\n    max_tokens: 512,\n  },\n  max_internal_iterations: 8,\n  stream: false,\n  steps: {\n    generation: { enabled: true },\n  },\n});\n```\n  </TabsContent>\n\n  <TabsContent value=\"python\">\n```python\nresult = client.agents.retrieval(\n    query='What are the major events in Korean history?',\n    queries=[{\n        'table': 'wikipedia',\n        'fields': ['title', 'body'],\n        'limit': 5,\n    }],\n    generator={\n        'provider': 'antfly',\n        'model': 'ggml-org/gemma-4-E4B-it-GGUF',\n        'max_tokens': 512,\n    },\n    max_internal_iterations=8,\n    stream=False,\n    steps={\n        'generation': {'enabled': True},\n    },\n)\n```\n  </TabsContent>\n\n  <TabsContent value=\"go\">\n```go\ngenerator, err := antfly.NewGeneratorConfig(antfly.AntflyGeneratorConfig{\n\tModel: \"ggml-org/gemma-4-E4B-it-GGUF\",\n\tMaxTokens: 512,\n})\nif err != nil { log.Fatal(err) }\nfields := []string{\"title\", \"body\"}\nresult, err := client.RetrievalAgent(ctx, antfly.RetrievalAgentRequest{\n\tQuery: \"What are the major events in Korean history?\",\n\tQueries: []antfly.RetrievalQueryRequest{{\n\t\tTable:          \"wikipedia\",\n\t\tFields:         &fields,\n\t\tLimit:          5,\n\t}},\n\tGenerator:        *generator,\n\tMaxInternalIterations: 8,\n\tSteps: antfly.RetrievalAgentSteps{\n\t\tGeneration:     antfly.GenerationStepConfig{Enabled: true},\n\t},\n})\nif err != nil { log.Fatal(err) }\nfmt.Printf(\"%+v\\n\", result)\n```\n  </TabsContent>\n\n  <TabsContent value=\"rust\">\n```rust\nlet resp = client\n    .retrieval_agent(&json!({\n        \"query\": \"What are the major events in Korean history?\",\n        \"queries\": [{\n            \"table\": \"wikipedia\",\n            \"fields\": [\"title\", \"body\"],\n            \"limit\": 5\n        }],\n        \"generator\": {\n            \"provider\": \"antfly\",\n            \"model\": \"ggml-org/gemma-4-E4B-it-GGUF\",\n            \"max_tokens\": 512\n        },\n        \"max_internal_iterations\": 8,\n        \"stream\": false,\n        \"steps\": {\n            \"generation\": {\"enabled\": true}\n        }\n    }))\n    .await?;\n```\n  </TabsContent>\n</Tabs>\n\nThe CLI and cURL commands stream Server-Sent Events as each step completes. A\nterminal `event: done` marks success; an error or incomplete stream makes the\nCLI exit nonzero. The SDK examples request structured JSON instead. Each\nexample uses bounded, read-only tool calls and requests only a grounded answer.\nUse `--no-streaming` for JSON from the CLI.\n\n### Inspect a query plan (optional)\n\nTo build a query without retrieving documents:\n\n```bash\nantfly agents query-builder --table wikipedia \\\n  --intent \"Find articles about anatomy\" \\\n  --generator '{\"provider\":\"antfly\",\"model\":\"ggml-org/gemma-4-E4B-it-GGUF\",\"max_tokens\":512,\"temperature\":0}' \\\n  --max-internal-iterations 8\n```\n\nAdd `--execute` to run the same composed retrieval workflow shown above.\n\n### RAG with alternative providers\n\nThe previous step uses Antfly inference for local inference. You can also use cloud APIs or Ollama:\n\n<Tabs defaultValue=\"gemini\">\n  <TabsList>\n    <TabsTrigger value=\"gemini\">Gemini</TabsTrigger>\n    <TabsTrigger value=\"openai\">OpenAI</TabsTrigger>\n    <TabsTrigger value=\"ollama\">Ollama</TabsTrigger>\n  </TabsList>\n\n  <TabsContent value=\"gemini\">\nRequires a [Google AI API key](https://aistudio.google.com/apikey). Set the `GEMINI_API_KEY` environment variable — Antfly picks it up automatically:\n\n```bash\nexport GEMINI_API_KEY=\"your-api-key-here\"\n\nantfly agents retrieval --table wikipedia \\\n  --semantic-search \"What are the major events in Korean history?\" \\\n  --indexes \"title_body\" \\\n  --fields \"title,body\" \\\n  --limit 5 \\\n  --generator '{\"provider\": \"gemini\", \"model\": \"gemini-2.5-flash\"}' \\\n  --max-context-tokens 2048 \\\n  --generate\n```\n  </TabsContent>\n\n  <TabsContent value=\"openai\">\nRequires an [OpenAI API key](https://platform.openai.com/api-keys). Set the `OPENAI_API_KEY` environment variable — Antfly picks it up automatically:\n\n```bash\nexport OPENAI_API_KEY=\"your-api-key-here\"\n\nantfly agents retrieval --table wikipedia \\\n  --semantic-search \"What are the major events in Korean history?\" \\\n  --indexes \"title_body\" \\\n  --fields \"title,body\" \\\n  --limit 5 \\\n  --generator '{\"provider\": \"openai\", \"model\": \"gpt-4.1-mini\"}' \\\n  --max-context-tokens 2048 \\\n  --generate\n```\n  </TabsContent>\n\n  <TabsContent value=\"ollama\">\nRequires [Ollama](https://ollama.com) running locally. Pull the model first:\n\n```bash\nollama pull gemma3:4b-it-qat\n\nantfly agents retrieval --table wikipedia \\\n  --semantic-search \"What are the major events in Korean history?\" \\\n  --indexes \"title_body\" \\\n  --fields \"title,body\" \\\n  --limit 5 \\\n  --generator '{\"provider\": \"ollama\", \"model\": \"gemma3:4b-it-qat\"}' \\\n  --max-context-tokens 2048 \\\n  --generate\n```\n  </TabsContent>\n\n</Tabs>\n\n<Callout type=\"info\">\n**Choosing a generator model:**\n- **`ggml-org/gemma-4-E4B-it-GGUF`** — local GGUF inference via Antfly inference, no API key needed\n- **Ollama `gemma3:4b-it-qat`** — local inference via Ollama, quantized for fast CPU/GPU performance\n- **Gemini `gemini-2.5-flash`** — cloud API, fast and high quality, requires API key\n- **OpenAI `gpt-4.1-mini`** — cloud API, fast and high quality, requires API key\n</Callout>\n\n### Structured output\n\nAdd `--no-streaming` to get structured JSON output with source references instead of streaming text:\n\n```bash\nantfly agents retrieval --table wikipedia \\\n  --semantic-search \"Explain the theory of relativity\" \\\n  --indexes \"title_body\" \\\n  --fields \"title,body,url\" \\\n  --limit 5 \\\n  --generator '{\"provider\": \"gemini\", \"model\": \"gemini-2.5-flash\"}' \\\n  --no-streaming --generate\n```\n\n### Evaluation\n\nAdd `--eval` to score the quality of retrieval and generation:\n\n```bash\nantfly agents retrieval --table wikipedia \\\n  --semantic-search \"What are the major events in Korean history?\" \\\n  --indexes \"title_body\" \\\n  --fields \"title,body\" \\\n  --limit 5 \\\n  --generator '{\"provider\": \"gemini\", \"model\": \"gemini-2.5-flash\"}' \\\n  --generate \\\n  --eval '{\n    \"evaluators\": [\"faithfulness\", \"relevance\"],\n    \"judge\": {\"provider\": \"gemini\", \"model\": \"gemini-2.5-flash\"}\n  }'\n```\n\nAvailable evaluators:\n- **Retrieval metrics** (require `ground_truth.relevant_ids`): `recall`, `precision`, `ndcg`, `mrr`, `map`\n- **LLM-as-judge metrics** (require `judge` config): `relevance`, `faithfulness`, `completeness`, `coherence`, `safety`, `helpfulness`, `correctness`, `citation_quality`\n</Steps>\n\n## Troubleshooting\n\n### `antfly` is not found after the Linux install\n\nThe user installer places the binary in `~/.local/bin`. Make it available in\nthe current terminal, then retry:\n\n```bash\nexport PATH=\"$HOME/.local/bin:$PATH\"\nantfly --version\n```\n\n### Antfly reports a legacy data directory\n\nAntfly refuses to overwrite a legacy Go-runtime directory. Keep that directory\nintact, back it up with the old runtime, and start this quickstart with a new\ndatabase directory:\n\n```bash\nantfly standalone --data-dir \"$HOME/.antfly-zig\" 2>&1 | tee antfly.log\n```\n\nModels remain in the documented `~/.antfly/inference/models` store unless you\nexplicitly pass `--models-dir` or set `ANTFLY_INFERENCE_MODELS_DIR`.\n\n### `MODEL_NOT_FOUND`\n\nConfirm that the requested model is installed and inspect the resolved model\ndirectory printed in the standalone startup log:\n\n```bash\nantfly inference list\ngrep -F 'standalone inference paths' antfly.log\n```\n\nPull the missing model again, or pass the intended directory explicitly with\n`antfly standalone --models-dir <path>`.\n\n### An index remains pending or `index wait` times out\n\nDo not continue to semantic, image, or RAG steps until the relevant index has\nreached the guide's readiness threshold. `queryable_partial` is safe to\nuse while coverage grows, but an empty published generation cannot produce\nresults. If `index wait` times out, capture the full\nstatus and recent watchdog messages:\n\n```bash\nantfly index list --table wikipedia --output json | jq '.'\ngrep -E 'watchdog|derived worker|NotFound|EnrichmentWaitTimeout' antfly.log | tail -n 100\n```\n\nRemember that physical chunk/vector counts can exceed source-document counts.\nContinual growth for unchanged source data, no generation-coverage progress, or\nan unexplained `ready` to `pending` transition should be reported with the JSON\nstatus, log excerpt, Antfly version, and startup command.\n\n### Startup reports a port conflict or memory error\n\nStop the process already using ports 8080 or 4200, or select different public\nand health ports with `--port` and `--health-port`. For memory errors, stop\nother large local models and retry with a smaller model or a larger process\nmemory envelope appropriate for the machine.\n\n### Stop the quickstart\n\nPress <kbd>Ctrl</kbd>+<kbd>C</kbd> in the standalone terminal. If you used\nHomebrew services, run:\n\n```bash\nbrew services stop antfly\n```\n\n## Next Steps\n\n1. **[Explore the Dashboard](/docs/guides/dashboard)** — Manage tables, run queries, and monitor your cluster at `http://127.0.0.1:8080`\n2. **[Image Search with CLIP](/docs/examples/image-search)** — Build a full image search application\n3. **[Browse Models](/inference)** — Discover available embedding, reranking, and generation models with `antfly inference list --remote`\n4. **[SDKs](/docs/sdks)** — Build applications with Go, TypeScript, Python, or Rust\n5. **[Backup and Restore](/docs/api/data-operations)** — Protect your data\n6. **[Production Deployment](/docs/operator/getting-started/quickstart)** — Deploy on Kubernetes with the Antfly Operator\n\n## Additional Resources\n\n- [Antfly CLI & REST API Documentation](/docs/api)\n- [Hybrid Search Guide](/docs/guides/hybrid-search)\n- [Inference Guide](/docs/guides/inference) — Configure ML inference, embedding providers, and more\n- [Configuration Reference](/docs/configuration)\n\n<Questions>\n- How do I install Antfly?\n- How do I create my first table and index?\n- How do I load data into Antfly?\n- How do I run a search query?\n- How do I use RAG with Antfly inference for AI-powered answers?\n</Questions>\n"}],"isError":false,"timestamp":1788987721415}}
{"type":"message","id":"0d7493c7","parentId":"a6625a3c","timestamp":"2026-09-09T21:02:03.226Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_b12224a7165340a39ca8f3eb","name":"bash","arguments":{"command":"curl -fsSL https://releases.antfly.io/antfly/v0.2.1/install.sh | sh -s -- v0.2.1 && export PATH=\"$HOME/.local/bin:$PATH\" && antfly --version","timeout":300}}],"api":"openai-completions","provider":"openrouter","model":"z-ai/glm-5.3-flash","usage":{"input":48,"output":65,"cacheRead":12416,"cacheWrite":0,"reasoning":0,"totalTokens":12529,"cost":{"input":0.0000036,"output":0.00001625,"cacheRead":0.00018623999999999998,"cacheWrite":0,"total":0.00020608999999999997}},"stopReason":"toolUse","timestamp":1788987721417,"responseId":"gen-1788987721-4ZEZxURbz0GJgIP9CsIa","rawStopReason":"tool_calls"}}
{"type":"message","id":"f727e8be","parentId":"0d7493c7","timestamp":"2026-09-09T21:02:10.263Z","message":{"role":"toolResult","toolCallId":"call_b12224a7165340a39ca8f3eb","toolName":"bash","content":[{"type":"text","text":">>> Detecting platform...\n>>> Detected platform: Linux x86_64\n>>> Installing Antfly v0.2.1...\n>>> Selected Linux archive libc: gnu\n>>> Downloading from https://releases.antfly.io/antfly/v0.2.1/antfly_0.2.1_Linux_x86_64_gnu.tar.gz...\n>>> Downloading release checksums...\n>>> Verified SHA-256 for antfly_0.2.1_Linux_x86_64_gnu.tar.gz\n>>> Extracting archive...\n>>> Activating Antfly v0.2.1...\n>>> Antfly installation complete!\n>>> Installed antfly to /usr/local/bin/antfly\n>>> Run '/usr/local/bin/antfly --help' to get started\nantfly 0.2.1 (zig runtime)\n"}],"isError":false,"timestamp":1788987730263}}
{"type":"message","id":"aa91d142","parentId":"f727e8be","timestamp":"2026-09-09T21:02:11.928Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"Installed v0.2.1 confirmed. Start standalone in background and run the basic data path steps.","thinkingSignature":"[{\"type\":\"reasoning.text\",\"text\":\"Installed v0.2.1 confirmed. Start standalone in background and run the basic data path steps.\",\"format\":\"unknown\",\"index\":0}]"},{"type":"text","text":"Antfly 0.2.1 installed and verified. Now starting standalone mode:"},{"type":"toolCall","id":"call_74c021fe4a374be491c79aff","name":"bash","arguments":{"command":"nohup antfly standalone --inference-host-budget-mb 8192 > /app/antfly.log 2>&1 &\necho \"started pid $!\""}}],"api":"openai-completions","provider":"openrouter","model":"z-ai/glm-5.3-flash","usage":{"input":288,"output":83,"cacheRead":12416,"cacheWrite":0,"reasoning":24,"totalTokens":12787,"cost":{"input":0.0000216,"output":0.00002075,"cacheRead":0.00018623999999999998,"cacheWrite":0,"total":0.00022858999999999998}},"stopReason":"toolUse","timestamp":1788987730264,"responseId":"gen-1788987730-h4W7T1keoUCd7UQlHJ6r","rawStopReason":"tool_calls"}}
{"type":"message","id":"8990d3f7","parentId":"aa91d142","timestamp":"2026-09-09T21:02:11.935Z","message":{"role":"toolResult","toolCallId":"call_74c021fe4a374be491c79aff","toolName":"bash","content":[{"type":"text","text":"started pid 115\n"}],"isError":false,"timestamp":1788987731935}}
{"type":"message","id":"2de6607c","parentId":"8990d3f7","timestamp":"2026-09-09T21:02:13.299Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_a3990844d41241709a1c1fcc","name":"bash","arguments":{"command":"for i in $(seq 1 60); do curl -fsS http://127.0.0.1:8080/health >/dev/null 2>&1 && break; sleep 1; done; curl -s http://127.0.0.1:8080/health; echo; tail -5 /app/antfly.log","timeout":90}}],"api":"openai-completions","provider":"openrouter","model":"z-ai/glm-5.3-flash","usage":{"input":380,"output":92,"cacheRead":12416,"cacheWrite":0,"reasoning":0,"totalTokens":12888,"cost":{"input":0.000028499999999999998,"output":0.000023,"cacheRead":0.00018623999999999998,"cacheWrite":0,"total":0.00023773999999999998}},"stopReason":"toolUse","timestamp":1788987731936,"responseId":"gen-1788987731-c1lipsQeutHEP2sYV8Hm","rawStopReason":"tool_calls"}}
{"type":"message","id":"7fad4339","parentId":"2de6607c","timestamp":"2026-09-09T21:03:14.051Z","message":{"role":"toolResult","toolCallId":"call_a3990844d41241709a1c1fcc","toolName":"bash","content":[{"type":"text","text":"not found\ninfo: inference resource policy ownership=external_required process_memory_limit_bytes=16644272128 process_memory_limit_provenance=host\ninfo: standalone inference worker ready generation=1\nstandalone health api listening on http://127.0.0.1:4200\nstandalone public api listening on http://127.0.0.1:8080\nstandalone local metadata enabled (raft disabled)\n"}],"isError":false,"timestamp":1788987794051}}
{"type":"message","id":"659150a6","parentId":"7fad4339","timestamp":"2026-09-09T21:03:33.218Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_ac6dad77adc14729bd4f034e","name":"bash","arguments":{"command":"curl -fsS -X POST http://127.0.0.1:8080/db/v1/tables/hello \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'\necho\ncurl -fsS -X POST http://127.0.0.1:8080/db/v1/tables/hello/batch \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"inserts\":{\"first\":{\"title\":\"Hello\",\"body\":\"Antfly is ready.\"}},\"sync_level\":\"full_text\"}'","timeout":60}}],"api":"openai-completions","provider":"openrouter","model":"z-ai/glm-5.3-flash","usage":{"input":182,"output":132,"cacheRead":12800,"cacheWrite":0,"reasoning":0,"totalTokens":13114,"cost":{"input":0.00001365,"output":0.000032999999999999996,"cacheRead":0.00019199999999999998,"cacheWrite":0,"total":0.00023864999999999997}},"stopReason":"toolUse","timestamp":1788987794052,"responseId":"gen-1788987794-enHS3aV2yLRPPKXXnpmi","rawStopReason":"tool_calls"}}
{"type":"message","id":"ba271a56","parentId":"659150a6","timestamp":"2026-09-09T21:03:34.033Z","message":{"role":"toolResult","toolCallId":"call_ac6dad77adc14729bd4f034e","toolName":"bash","content":[{"type":"text","text":"{\"name\":\"hello\",\"indexes\":{\"full_text_index_v0\":{\"name\":\"full_text_index_v0\",\"type\":\"full_text\"}},\"shards\":{\"1278841902702993302\":{\"byte_range\":[\"\",\"\"]}},\"schema\":{\"version\":0,\"default_type\":\"doc\",\"enforce_types\":false,\"document_schemas\":{\"doc\":{\"schema\":{\"type\":\"object\",\"additionalProperties\":true,\"x-antfly-dynamic-indexing\":{\"mode\":\"infer_types\"}}}}},\"replication_sources\":[],\"field_capabilities\":[{\"field\":\"_id\",\"type\":\"keyword\",\"query_modes\":[\"exact\"],\"sortable\":true,\"provenance\":\"reserved\",\"missing_null_policy\":\"not_null\",\"sort_lifecycle_state\":\"queryable\"}],\"storage_status\":{\"empty\":false}}\n{\"status\":\"committed\",\"inserted\":1,\"deleted\":0,\"transformed\":0}"}],"isError":false,"timestamp":1788987814033}}
{"type":"message","id":"2d05b0a2","parentId":"ba271a56","timestamp":"2026-09-09T21:03:35.629Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_9180541421ff48a19a8b1e28","name":"bash","arguments":{"command":"export PATH=\"$HOME/.local/bin:$PATH\"; antfly query --table hello \\\n  --full-text-search 'body:Antfly' \\\n  --fields 'title,body'","timeout":60}}],"api":"openai-completions","provider":"openrouter","model":"z-ai/glm-5.3-flash","usage":{"input":233,"output":52,"cacheRead":13056,"cacheWrite":0,"reasoning":0,"totalTokens":13341,"cost":{"input":0.000017474999999999998,"output":0.000013,"cacheRead":0.00019584,"cacheWrite":0,"total":0.000226315}},"stopReason":"toolUse","timestamp":1788987814034,"responseId":"gen-1788987814-3PvFgE6jhPWVje0HCwfm","rawStopReason":"tool_calls"}}
{"type":"message","id":"c8438010","parentId":"2d05b0a2","timestamp":"2026-09-09T21:03:35.664Z","message":{"role":"toolResult","toolCallId":"call_9180541421ff48a19a8b1e28","toolName":"bash","content":[{"type":"text","text":"{\n  \"responses\": [\n    {\n      \"hits\": {\n        \"total\": {\n          \"value\": 1,\n          \"relation\": \"exact\"\n        },\n        \"hits\": [\n          {\n            \"_id\": \"first\",\n            \"_score\": 0.28768211603164673,\n            \"_source\": {\n              \"title\": \"Hello\",\n              \"body\": \"Antfly is ready.\"\n            }\n          }\n        ],\n        \"max_score\": 0.28768211603164673\n      },\n      \"took\": 0,\n      \"status\": 200,\n      \"table\": \"hello\"\n    }\n  ]\n}\n"}],"isError":false,"timestamp":1788987815664}}
{"type":"message","id":"de79714c","parentId":"c8438010","timestamp":"2026-09-09T21:03:41.423Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"Done. Stop immediately and report. Should I stop the standalone process? The stopping objective says stop immediately after confirming. I'll leave it running or kill it — \"stop immediately and report the result\" refers to stopping the workflow progression. I could optionally stop the server. The guide's \"Stop the quickstart\" section is Ctrl+C. I'll just report. Maybe cleaner to leave running since only task is to confirm. I'll report without further actions.","thinkingSignature":"[{\"type\":\"reasoning.text\",\"text\":\"Done. Stop immediately and report. Should I stop the standalone process? The stopping objective says stop immediately after confirming. I'll leave it running or kill it — \\\"stop immediately and report the result\\\" refers to stopping the workflow progression. I could optionally stop the server. The guide's \\\"Stop the quickstart\\\" section is Ctrl+C. I'll just report. Maybe cleaner to leave running since only task is to confirm. I'll report without further actions.\",\"format\":\"unknown\",\"index\":0}]"},{"type":"text","text":"Quickstart verified — stopping here as instructed.\n\n## Result\n\n**Antfly v0.2.1 quickstart basic data path: ✅ PASS**\n\n1. **Install** — Installed exactly `v0.2.1` via the pinned installer (`curl -fsSL https://releases.antfly.io/antfly/v0.2.1/install.sh | sh -s -- v0.2.1`); verified with checksum validation.\n   - `antfly --version` → **`antfly 0.2.1 (zig runtime)`** ✅\n2. **Start** — Ran the documented standalone inference configuration:\n   - `antfly standalone --inference-host-budget-mb 8192` (log at `/app/antfly.log`); public API on `http://127.0.0.1:8080`, health on `:4200`.\n3. **Verify the basic data path** (guide's stopping query on table `hello`):\n   - Created table `hello` via `POST /db/v1/tables/hello`\n   - Inserted via batch with `sync_level: full_text` → `{\"status\":\"committed\",\"inserted\":1}`\n   - Query: `antfly query --table hello --full-text-search 'body:Antfly' --fields 'title,body'`\n   - **Returned exactly 1 hit**:\n     - key: **`first`** ✅\n     - title: **`Hello`** ✅\n     - body: **`Antfly is ready.`** ✅ (score 0.2877, `relation: exact`)\n\nPer the guide, the basic full-text check succeeded, so I stopped immediately — no model installation, no Wikipedia sample data, no `wikipedia` table, no semantic/rerank/image/RAG steps were run. The standalone process is still running in the background (PID 115, log `/app/antfly.log`) if you want to continue the guide; press Ctrl-C or kill it to stop."}],"api":"openai-completions","provider":"openrouter","model":"z-ai/glm-5.3-flash","usage":{"input":174,"output":519,"cacheRead":13312,"cacheWrite":0,"reasoning":117,"totalTokens":14005,"cost":{"input":0.000013049999999999999,"output":0.00012974999999999998,"cacheRead":0.00019967999999999999,"cacheWrite":0,"total":0.00034247999999999993}},"stopReason":"stop","timestamp":1788987815666,"responseId":"gen-1788987815-EGlY92ywQ2CjbuAR693e","rawStopReason":"stop"}}
