Miyo Node Service API
Base URL: http://127.0.0.1:8742
All request and response bodies are JSON. Errors always return { "detail": "<message>" }.
Health
GET /v0/health
Returns service and sidecar status.
Response 200
{ "status": "ok | degraded", "service": "running", "qdrant": "connected | ...", "llama_server": "running | ...", "model_download_progress": 0.75, "embedding_model": "nomic-embed-text-v1.5", "batch_size_preset": "default", "gpu_variant": "metal | null", "indexed_files": 1234}Search
POST /v0/search
Hybrid semantic + keyword search (dense + BM25, fused via RRF).
Request body
{ "query": "string (required)", "folder_path": "string | null — restrict to this folder", "path": "string | null — substring filter on file path (case-insensitive)", "limit": 10, "filters": [ /* MetadataFilter[], see below */ ]}Response 200
{ "results": [ /* SearchResult[] */ ], "query": "string", "count": 5, "execution_time_ms": 42.0}Errors: 400 (missing query), 503 (llama-server or Qdrant unavailable)
POST /v0/search/related
Find files related to a given file using vector similarity.
Request body
{ "file_path": "string (required) — absolute path", "folder_path": "string | null", "limit": 10, "filters": [ /* MetadataFilter[] */ ]}Response 200
{ "results": [{ "path": "string", "score": 0.95 }], "file_path": "string", "count": 5, "execution_time_ms": 12.0}Errors: 400, 404 (no indexed chunks for the file), 503
Folders
GET /v0/folder
- With
?path=<folder_path>: returns a singleFolderEntry(404 if not registered) - Without
path: returns{ "folders": [ FolderEntry[] ] }
POST /v0/folder
Register a folder for indexing. Starts watching and scanning immediately.
Request body
{ "path": "string (required) — absolute path", "include_patterns": ["**/*.md"], "exclude_patterns": ["**/node_modules/**"], "recursive": true}Response 201 — FolderEntry
Errors: 400 (invalid), 409 (already registered)
PATCH /v0/folder
Update folder configuration. Only provided fields are changed.
Request body
{ "path": "string (required)", "include_patterns": ["**/*.md"], "exclude_patterns": ["**/node_modules/**"], "recursive": false}Response 200 — updated FolderEntry
Errors: 400, 404
DELETE /v0/folder
Unregister a folder and remove all its indexed data.
Request body
{ "path": "string (required)" }Response 200 — deletion summary object
Errors: 400, 404
POST /v0/folder/pause
Stop file watching for a folder without removing it.
Request body
{ "path": "string (required)" }Response 200
{ "status": "paused", "path": "string" }Errors: 400, 404
POST /v0/folder/resume
Resume file watching and trigger a rescan.
Request body
{ "path": "string (required)" }Response 202
{ "status": "scanning", "path": "string" }Errors: 400, 404
POST /v0/scan
Manually trigger a rescan of a registered folder.
Request body
{ "path": "string (required)", "force": false}force: true re-indexes all files even if unchanged.
Response 202
{ "status": "started", "path": "string" }Errors: 400, 404
Files & Documents
GET /v0/folder/files
List indexed files with optional filtering and pagination.
Query parameters
| Param | Type | Description |
|---|---|---|
folder_path | string | Filter by folder |
title | string | Substring match on title |
file_path | string | Exact file path match |
mtime_after | number | Unix timestamp lower bound |
mtime_before | number | Unix timestamp upper bound |
offset | integer (default 0) | Pagination offset |
limit | integer | Max results (omit for no limit) |
order_by | mtime | updated_at (default) | Sort order |
Response 200
{ "files": [ /* FileEntry[] */ ], "total": 99}GET /v0/folder/documents
Fetch all indexed chunks for a specific file, sorted by chunk index.
Query parameters
| Param | Required | Description |
|---|---|---|
path | yes | Absolute file path |
folder_path | no | Scope to a specific folder |
Response 200
{ "documents": [ /* DocumentChunk[] */ ]}Errors: 400, 503
Utilities
POST /v0/parse-doc
Parse a file and return its extracted text content.
Request body
{ "path": "string (required) — absolute file path" }Response 200 — parsed content object (shape varies by file type)
Errors:
| Code | Meaning |
|---|---|
| 400 | Invalid input |
| 403 | File not readable |
| 404 | File not found |
| 415 | Unsupported file type |
| 422 | Parse failed |
| 500 | Internal error |
POST /v0/rebuild-metadata
Rebuild the manifest by re-syncing metadata from Qdrant. Use when manifest is out of sync.
Response 200 — { "elapsed_ms": 123, ...stats }
Errors: 409 (rebuild already in progress), 503
POST /v0/llama-server/restart
Restart the llama-server sidecar, optionally changing the batch size preset.
Request body
{ "batch_size_preset": "default" }Response 200
{ "restarted": true, "batch_size_preset": "default", "status": "running"}Errors: 400
POST /v1/embeddings
Generate embeddings. OpenAI-compatible interface, proxied to llama-server.
Request body
{ "model": "nomic-embed-text-v1.5", "input": "string or string[]"}model is optional but must match the configured embedding model if provided.
Response 200 — standard OpenAI embeddings response
Errors: 400, 503
Schemas
MetadataFilter
Range filter on a metadata field.
{ "field": "mtime", "gt": 1700000000, "gte": 1700000000, "lt": 1800000000, "lte": 1800000000}fieldcan bemtime,ctime, or any metadata key- Bare field names (not
mtime/ctimeand not prefixed withmetadata.) are automatically prefixed withmetadata. - At least one of
gt,gte,lt,ltemust be present
SearchResult
{ "path": "string", "score": 0.95, "title": "string | null", "mtime": 1700000000, "ctime": 1700000000, "file_name": "string | null", "chunk_index": 0, "total_chunks": 5, "chunk_text": "string | null", "metadata": {}, "embedding_model": "string | null", "tags": ["string"], "extension": ".md", "created_at": "string | null", "nchars": 1024, "folder_path": "string | null"}FileEntry
{ "path": "string", "title": "string | null", "mtime": 1700000000, "updated_at": "ISO8601 string", "folder_path": "string | null", "total_chunks": 5}DocumentChunk
{ "id": "string", "path": "string | null", "title": "string | null", "chunk_index": 0, "chunk_text": "string | null", "metadata": {}, "embedding_model": "string | null", "ctime": 1700000000, "mtime": 1700000000, "tags": ["string"], "extension": ".md", "created_at": "ISO8601 string | null", "nchars": 1024, "folder_path": "string | null"}FolderEntry
Shape varies — includes at minimum:
{ "path": "string", "include_patterns": ["**/*.md"], "exclude_patterns": [], "recursive": true}Additional live stats fields are populated by the folder manager.