REST API

HTTP endpoints exposed by gno serve for search, documents, graph data, models, jobs, and workspace automation.

The REST API is the HTTP version of the local GNO engine. Start it with gno serve, then call /api/* from curl, scripts, desktop launchers, internal dashboards, or small apps. It is best when you want automation without embedding the SDK or installing an MCP client.

What this is

Launch the server

gno serve # default port 3000
gno serve --port 8080
gno serve --detach # browser workspace + API in background

Read endpoints

Status is passive for connectors and models: it does not start MCP children, initialize or download models, or call remote inference. Connector evidence is a bounded projection of saved verification receipts. When connectorProjection.truncated is true, omitted target/collection pairs have no implied result and must not be treated as passed.

Status also projects contentTypeBoost.rules as rule IDs plus normalized factors and contentTypeBoost.rulesFingerprint as the full ranking fingerprint. It never exposes configured path prefixes.

curl localhost:3000/api/doc-asset?uri=gno://notes/papers/spec.pdf \
  -H 'Range: bytes=0-65535' -o spec.part.pdf

The pinned PDF.js worker, character maps, and standard fonts are also served same-origin under /vendor/pdfjs/*. Package-root containment and fixed file-type allowlists reject traversal and unknown assets; no CDN is involved.

Search endpoints

curl -X POST localhost:3000/api/search -d '{"query":"exact term"}'
curl -X POST localhost:3000/api/vsearch -d '{"query":"concept"}'
curl -X POST localhost:3000/api/query -d '{"query":"research question"}'
curl -X POST localhost:3000/api/ask -d '{"query":"what changed?"}'
curl -X POST localhost:3000/api/ask \
  -H 'content-type: application/json' \
  -d '{"query":"Who owns the launch decision?","verify":true}'

Search bodies mirror the CLI: collection, limit, since, until, category, author, intent, exclude, tagsAny, tagsAll, and mode-specific controls such as noExpand, noRerank, candidateLimit, and queryModes.

Search results include source.absPath when the hit is a resolvable file-backed document. If absPath is absent, show the URI tail and do not offer file-open for that row. Default snippets skip leading YAML frontmatter and prefer document prose. A frontmatter-dominated FTS window falls back to stripped chunk prose. line follows that trimmed display range. The Web UI document page is a separate surface: /doc?uri=<encodeURIComponent(uri)>, not GET /api/doc.

Retrieval bodies may include up to 16 projectHints. These values are opaque and untrusted: the server does not resolve or reflect them, does not probe the filesystem, and currently applies zero affinity. Omitting or supplying the field preserves the existing response contract exactly. In particular, REST diagnose stays on the closed query-diagnose@1.0 shape and omits affinity; the affinity-bearing v1.1 branch is reserved for trusted local CLI diagnose.

POST /api/ask keeps the existing raw Ask behavior when verify is absent or false. With "verify": true, it generates from one closed Context Capsule and returns the Capsule, freshness receipt, four-state per-claim verdicts, exact evidence IDs and line spans, coverage, gaps, semantic verifier state, and explicit abstention. The verified Ask body is closed: unknown fields fail validation.

Every substantive claim must be supported for the draft to be returned. Otherwise the response withholds it and reports answerStatus: "abstained". A contradiction requires positive conflicting evidence; missing evidence is insufficient, not contradicted. Unavailable or failed semantic verification remains visible rather than silently falling back to an unverified answer.

curl localhost:3000/api/query \
  -H 'content-type: application/json' \
  -d '{
    "query": "authentication",
    "collection": "notes",
    "limit": 20,
    "tagsAny": ["security"]
  }'

Context Capsules

POST /api/context compiles exact indexed evidence for one goal into a deterministic Capsule. The active server supplies the canonical index. The budget covers the complete payload—not each document separately—and the result includes exact URI/line spans, source and passage hashes, coverage gaps, omission counts, and requested capability fallbacks. It is returned to the caller and is not persisted.

Tag filters are normalized, lowercased, deduplicated, and validated before retrieval. Result and candidate limits stay global across multi-collection requests: result admission is capped after the merged rank, while rerank and graph work is distributed deterministically in canonical collection order.

curl localhost:3000/api/context \
  -H 'content-type: application/json' \
  -d '{"goal":"Compare launch proposals","collections":["work"],"budgetTokens":12000, "depthPolicy":"fast"}'

POST /api/context/verify accepts a complete saved Capsule and returns a read-only receipt classifying evidence as unchanged, stale, or missing, with independent fingerprint and ranking state. Index mismatch and malformed Capsules fail before evidence reads. Add "format":"md" for the trust-delimited readable projection. Each untrusted block uses a collision-resistant Markdown fence derived from its content, so indexed text cannot forge the closing boundary. JSON is canonical by default.

Context API errors are deliberate: invalid input, filters, budgets, or identity return 400; no evidence returns 404; source, index, context, mutation, and provenance conflicts return 409; tokenizer unavailability returns 503; retrieval, load, snapshot, and runtime failures return 500. Error messages come from a fixed public catalog; internal paths, causes, and stack traces are not returned.

Knowledge Delta

GET /api/changes?since=<ISO-8601-or-cursor>&collection=notes&limit=100
GET /api/diff?ref=<document-ref>&change=<opaque-change-id>
GET /api/impact?ref=<document-ref>&maxDepth=3&maxNodes=100&maxEdges=250

These read-only endpoints share the CLI, MCP, and SDK contracts. Changes contain bounded identity, hash, lifecycle, and structural metadata—not source bodies. Diff discloses partial, expired, or unavailable retained history. Impact returns one bounded evidence path per dependent document.

Saved-Capsule registration management remains CLI-only. The local /api/events stream can emit a closed capsule-reverified event after persistence, but never a question, label, path, URI, hash, receipt, credential, Capsule, passage, or source content.

Write and job endpoints

Reference-safe rename and move are deliberately two-step. Preview returns the canonical file-refactor-preview@1.0 plan, including every examined reference, canApply, and a deterministic SHA-256 planDigest. Apply requires that exact digest, schemaVersion: "1.0", and confirmation: "apply". Current state is replanned before mutation, so stale, ambiguous, malformed, unsupported, read-only, occupied, and cross-collection plans fail closed. applied_with_sync_pending means the filesystem committed and only the later index refresh needs Update All; it is not a failed file move.

curl localhost:3000/api/connectors/verify \
  -H 'content-type: application/json' \
  -d '{"connectorId":"cursor-mcp","collection":"notes"}'

Connector verification is active only when this endpoint or the Web Connectors action is invoked. It does not edit client configuration. Skill targets return an explicit runtime-unverifiable result because GNO cannot prove that the client loaded or executed an installed skill file.

Use /api/capture for second-brain capture with source: frontmatter and presets such as person, company-project, meeting, or idea-original. Use /api/docs for raw note creation without provenance capture semantics. REST capture starts an async sync job, so receipts usually return sync.status as pending with a job id. Capture content must be text, /api/capture does not accept legacy overwrite, and capture writes fail instead of replacing a late-arriving file.

Security model

export GNO_API_TOKEN="secret"
gno serve
curl -H "X-GNO-Token: secret" localhost:3000/api/status