Skip to content
grepvine.aiJoin preview

Concepts

Grepvine has four nouns: an organization owns indexes, an index holds documents, and a query returns every line in an index that matches a pattern. Everything else in the API decides who may do what to them.

Every client is a view of the same REST API at https://api.grepvine.ai/v1. The Python and TypeScript SDKs are generated from its OpenAPI spec, and gv and the web console call the same operations. The MCP server at https://api.grepvine.ai/mcp exposes seven tools built on them. Whichever client you use, a request gets the same roles, limits and audit trail.

flowchart LR
  py["Python SDK"] --> api["Grepvine API"]:::hl
  ts["TypeScript SDK"] --> api
  cli["gv CLI"] --> api
  mcp["MCP client"] --> api
  web["Web console"] --> api
  api --> idx["Your indexes"]
Every client reaches one API, which applies the same roles and limits to all of them.

The SDKs and gv handle the request mechanics that the REST API leaves to the caller. If you call the API directly, you do these yourself:

Mechanic What the SDKs and gv do
Authentication Send your API key as Authorization: Bearer gvk_….
Idempotency Give every write an Idempotency-Key of 16 to 128 characters and keep it the same across retries, so a retried write is applied once.
Slowing down On a 429, wait for the interval in Retry-After before trying again. The SDKs wait up to a minute at a time and ten minutes in total per request.
Transient failures The SDKs retry a 5xx answer or a dropped connection twice more with a short backoff.
Pagination Follow pagination.next_page_id while pagination.has_next is true. paginate in both SDKs does this for you.

An organization owns indexes and has members. Its name shares one namespace with user names, so no organization can take a name a user already has, and the other way round. Every organization has exactly one owner.

A member’s role sets what they can do in that organization:

Role Can
owner Everything, including transferring ownership and deleting the organization.
admin Manage members other than the owner, create, change and delete indexes, and read and write all data.
developer Read, write and delete documents, and search.
reader Read and list documents, and search.

An API key belongs to a user, not to an organization. A request made with it gets the user’s role in each organization it touches. gv login creates a key for you through a browser approval; the security page covers creating and revoking them.

An index is a search space named {organization}/{index}, such as acme/contracts. A name is ASCII letters, digits and hyphens, and starts with a letter. It keeps the case it was created with but is matched without regard to case: once acme/MyIndex exists, acme/myindex addresses it and acme/myindeX can’t be created.

An index also carries a Markdown description of up to 16,384 characters and up to 64 key/value tags. An update merges the tags you send into the ones it has. gv sync uses the git.commit and git.branch tags to record which commit an index mirrors.

An index is always in one of four states:

State Meaning
creating Just created. It is usually ready within a moment. wait_until_ready (Python) and waitUntilReady (TypeScript) wait for it.
ready Accepts reads, writes and queries.
deleting Deletion has started. The index no longer answers, and its storage is removed in the background.
delete_failed Deletion hit an error. Grepvine keeps retrying it, and you can ask for the deletion again.

Reading one index returns its current document_count and content_bytes. While the index is being optimized after a large write, the read also returns optimization_progress_percent. Storage and compute explains what that optimization does. A listing of indexes reports the same counts, but they can trail recent writes by a few seconds.

A document has four parts. You write the key, the content and the metadata; Grepvine assigns the revision. Here is a support ticket:

{
"key": "tickets/2026/10/48213.md",
"content": "# Refund stuck in pending\n\nThe customer was charged on 2026-10-21 ...",
"revision": "9f2c41d07a3e",
"metadata": {
"product": {"type": "string", "value": "checkout"},
"priority": {"type": "integer", "value": 2},
"sentiment": {"type": "number", "value": -0.62},
"opened_at": {"type": "timestamp", "value": "2026-10-21T09:14:00Z"},
"escalated": {"type": "boolean", "value": true}
}
}
Part What it is
key The document’s name: a UTF-8, POSIX-style path of up to 1,024 bytes, with no empty, . or .. components. Listings return keys in byte order and can fold them into prefixes at a delimiter, like a file tree.
content Up to 1 GiB. Content that is valid UTF-8 and at most 100 MiB is searchable. Anything else, such as an image a page links to, is stored, listed and served like the rest, but no query matches it, and a listing reports it with searchable: false.
revision An opaque value that changes on every write. Pass it back as If-Match to write only if nothing changed since you read the document, or send If-None-Match: * to write only if the key doesn’t exist yet.
metadata Up to 64 fields and 64 KiB encoded, for filtering searches. Fields have no schema, but every value has an explicit type: string, integer, number, timestamp or boolean.

The same field can hold different types in different documents, and a filter comparison only matches a value of a compatible type. The SDKs infer each type from your language’s values.

Filters read metadata only, never the key. So that you can filter by location, the SDKs’ batch helpers and gv copy each document’s key into a path field and its size in bytes into a size field, unless you set them yourself.

You write documents one at a time, or in NDJSON batches of up to 2,048 documents and 16 MiB of text. Each document in a batch succeeds or fails on its own; guarantees gives the exact rules.

A query runs one pattern against every searchable document in an index:

Field Meaning
pattern Up to 8 KiB of UTF-8.
mode regex (the default, RE2 syntax) or literal.
case_sensitive true by default.
whole_word Literal mode only. Letters, digits and underscore are word characters.
multiline false by default, so the pattern applies to one line at a time. With true, it applies to the whole document and a match can span lines.
filter An expression over metadata, up to 8 KiB, such as path STARTSWITH 'docs/' AND size < 102400.
lines_before, lines_after Context lines around each result, 0 to 20 each.

A result is one match, or several matches that share lines. It carries the document’s key and revision, the first and last line numbers it covers, up to 64 KiB of their text, the byte offset and length of each match, and any context lines you asked for. Results come back sorted by key, then line, then match offset, never by relevance.

Results arrive in pages of up to 200, 50 by default. A page can hold fewer results than you asked for, even none, while has_next is still true, so keep paging until it is false. Searching covers queries and filters in full.