# Arkivector

> Vector search for Arkiv. Arkivector runs pgvector's distance functions over entities stored on the Arkiv chain. Your embeddings are written on chain by your wallet, and you query them with one REST call, from Python or Node.js, or from an AI agent over MCP.

This file is the whole website (https://arkivector.dikshitrj.in) as Markdown, written for AI agents and LLMs. It is generated at build time from the same sources as the site. All documentation on one page: [https://arkivector.dikshitrj.in/docs.md](https://arkivector.dikshitrj.in/docs.md). Index in the llms.txt format: [https://arkivector.dikshitrj.in/llms.txt](https://arkivector.dikshitrj.in/llms.txt).

- Current release: **v1.2.0** (always at https://github.com/DikshitRJ/arkivector/releases/latest)
- Source: <https://github.com/DikshitRJ/arkivector>
- Install guide: [https://arkivector.dikshitrj.in/docs/install](https://arkivector.dikshitrj.in/docs/install) (Markdown: [https://arkivector.dikshitrj.in/docs/install.md](https://arkivector.dikshitrj.in/docs/install.md))
- License: MIT. The copied pgvector code keeps its PostgreSQL License.

## Quick facts for agents

- **What it is.** `arkivectord` is a daemon written in C11 that contains pgvector 0.8.7's own code. It syncs entities from the Arkiv chain into a local index (LMDB rows, mmap vector segments, roaring-bitmap filters, HNSW graphs) and serves REST on port 8080. It writes by building, signing and sending Arkiv transactions.
- **Clients.** A Python SDK (`pip install arkivector`), a Node.js SDK (`@dikshitrj/arkivector` on GitHub Packages), plain HTTP (`curl`), and an MCP server at `/mcp` for AI agents (Claude Code: `claude mcp add --transport http arkivector http://127.0.0.1:8080/mcp`).
- **Run it.** `docker run -d -p 127.0.0.1:8080:8080 -v arkivector-data:/data -e ARKIVECTOR_ARKIV_ACCESS_KEY=... -e ARKIV_PRIVATE_KEY ghcr.io/dikshitrj/arkivectord:latest`. Without `ARKIV_PRIVATE_KEY` (or an encrypted keystore or remote signer, `[write.signer]`) the daemon can't sign, but it still relays writes signed by your users' own wallets.
- **Vector types** (same as pgvector): `vector`, `halfvec`, `sparsevec`, `bit`.
- **Distance operators:** `<->` L2, `<#>` negative inner product, `<=>` cosine, `<+>` L1, `<~>` Hamming, `<%>` Jaccard.
- **Indexes:** `hnsw` (pgvector's graph) or `none` (exact scan). The planner picks HNSW for large candidate sets and an exact scan for small or very selective ones. Every hit is rescored with the real operator. `"exact": true` forces a full scan.
- **Collections need `writers`.** A collection only indexes entities created by the wallets in its `writers` list. Put the daemon's own wallet address there (and your users' addresses if they sign with their own wallets), or your writes land on chain but never show up in search.
- **Chain:** Arkiv Rabdi testnet, chain id 7794095, 2 s blocks, RPC `https://rpc.rabdi.db-chain.testnet.arkiv.network`.

## Home

### Why it exists

**pgvector made retrieval boring.** pgvector is the Postgres extension that turned "where do I keep my embeddings?" into `ORDER BY embedding <=> $1 LIMIT 5`. It has more than 23,000 GitHub stars and sits under a large share of RAG and agent stacks, because it adds vector search to a database people already run.

**Arkiv had no vector search.** Arkiv is a chain built for data: entities with typed attributes, an owner, and an expiry block, queried with a filter language. You could store an embedding there as bytes, but you could not ask which entities are closest to it. Arkivector adds that, using pgvector's own C code for the math.

### Search is geometry

An embedding model places texts with similar meaning close together. A query becomes a vector too, and search asks which stored vectors point in nearly the same direction. Cosine distance is `d = 1 − cos θ`; with `k = 2` the two smallest distances are returned. Real embeddings have hundreds of dimensions, so the angle is computed over all of them, but the arithmetic is the same.

### Numbers we can back up

| Number | Meaning |
| :--- | :--- |
| 97 | Parity tests against pgvector 0.8.7 running in Postgres. Every distance is bit-identical or within float32 rounding |
| 4 | Vector types, same as pgvector: vector, halfvec, sparsevec, bit |
| 6 | Distance operators: `<->` L2, `<#>` negative inner product, `<=>` cosine, `<+>` L1, `<~>` Hamming, `<%>` Jaccard |
| < 3 s | From upsert to mined transaction on the Arkiv Rabdi testnet in our end-to-end run |
| 18 MB | Container image. One daemon, written in C11, plus thin Python and Node.js SDKs |

### Store, then search

```python
from arkivector import Client, EntityInput, F

client = Client(session_consistency=True)
client.upsert("agent.memory", [
    EntityInput(id="cat", vector=[1, 0, 0, 0], document="Cats purr.", attributes={"topic": "pets"}),
], wait="receipt")      # signed, sent to Arkiv, mined
res = client.search("agent.memory", vector=[1, 0.05, 0, 0], k=2, filter=F.eq("topic", "pets"))
print([(h.id, h.distance) for h in res.hits])
```

The daemon builds the Arkiv transaction, signs it, waits for it to be mined, and indexes the entity once it reads it back from the chain. With `session_consistency`, the search waits for that block, so you always see your own write.

## Architecture

Page: [https://arkivector.dikshitrj.in/architecture](https://arkivector.dikshitrj.in/architecture). A write, a sync and a search followed through the daemon, then the math that ranks the results.

### The big picture

Your code talks to `arkivectord` through an SDK, curl or MCP. The daemon writes to Arkiv with signed transactions and reads entities back into its local index. Search never leaves the daemon. The chain is the source of truth.

| Component | Role |
| :--- | :--- |
| HTTP | REST and MCP on a libuv event loop, port 8080 |
| writer | Encodes Arkiv operations (ABI), signs with secp256k1, sends transactions to the Arkiv contract (`execute(ops)`) |
| planner | Chooses HNSW or an exact scan and runs pgvector's distance kernels |
| filters | Attribute filters as roaring bitmaps |
| store | LMDB for rows, mmap'd vector segments |
| syncer | Follows the chain (`arkiv_query`, `eth_getLogs`), handles reorgs and expiry |

### The story of one entity

1. **The parts.** SDK, daemon, chain.
2. **A write.** The vector becomes VectorBytes inside an Arkiv CREATE operation. For `halfvec [1, 0, 0, 0]` the bytes are `41 56 12 00 04 00 00 00 00 3c 00 00 00 00 00 00`: `'AV'`, type 2 = halfvec, dimension 4, then 1.0 as IEEE binary16.
3. **Signed and sent.** The transaction is signed with secp256k1 and mined in a block.
4. **Synced back.** The syncer reads the entity back from the chain, then indexes it. Every response carries `as_of_block`.
5. **A search.** Filter bitmap AND live bitmap, score the survivors with the operator (e.g. `<=>` cosine), keep the best k.
6. **The arithmetic.** For `q = [1, 0.05, 0, 0]`, `cat = [1, 0, 0, 0]` gives `d = 1 − 1/1.00125 = 0.00125`, and `dog = [0.9, 0.1, 0, 0]` gives `d = 1 − 0.905/(0.9055·1.00125) = 0.00184`. L2 gives the same order (cat 0.050, dog 0.112).
7. **16 bits per number.** `halfvec` stores 0.1 as binary16 `0 01011 1001100110` = `2^(11−15) · (1 + 614/1024)` = 0.0999755859375, 0.024% off float32 with half the bytes, rounded half to even with pgvector's own conversion code.
8. **Exact scan and HNSW.** An exact scan computes n distances and keeps a top-k heap (O(n log k)). HNSW (M = 16 links, `ef_search` = 40 by default) descends the graph layers (`ℓ = ⌊−ln U · m_L⌋`, `m_L = 1 / ln M`) and visits a small fraction of the nodes. Since v1.1.0 every `hnsw` collection searches a real pgvector graph.
9. **Expiry.** When the chain passes an entity's expiry block, the entity leaves the index.

## Build artifacts

Page: [https://arkivector.dikshitrj.in/build](https://arkivector.dikshitrj.in/build). Where every piece is published.

### How a release is made

One workflow, `.github/workflows/release.yml`, runs on every `v*` tag (or a manual dispatch): build (binary, image, wheel, npm package), smoke test (the binary and image report the version), publish (GitHub Release, GHCR, PyPI, GitHub npm). PyPI uses trusted publishing, so there is no token in the repository.

### Artifacts

**Python SDK** ([pypi.org/project/arkivector](https://pypi.org/project/arkivector/)). Pure Python, no dependencies. Wheel and sdist are also attached to every GitHub release.

```bash
pip install arkivector
```

**Node.js SDK** (GitHub Packages, `@dikshitrj/arkivector`). ESM, TypeScript types, zero runtime dependencies. GitHub Packages asks for a token with `read:packages`; the tarball is also attached to each release.

```bash
echo "@dikshitrj:registry=https://npm.pkg.github.com" >> .npmrc
npm install @dikshitrj/arkivector
```

**Daemon, container image** (`ghcr.io/dikshitrj/arkivectord`). 18 MB Alpine image, linux/amd64, runs as a non-root user, index in the `/data` volume. Tags `:latest`, `:1`, `:<version>`.

```bash
docker run -d -p 127.0.0.1:8080:8080 -v arkivector-data:/data \
  -e ARKIVECTOR_ARKIV_ACCESS_KEY=... -e ARKIV_PRIVATE_KEY \
  ghcr.io/dikshitrj/arkivectord:latest
```

**Daemon, Linux binary** (GitHub Releases). x86_64 glibc build with libcurl bundled; needs libuv and OpenSSL 3 from the OS.

```bash
VERSION=$(curl -fsSLI -o /dev/null -w '%{url_effective}' https://github.com/DikshitRJ/arkivector/releases/latest | sed 's|.*/tag/v||')   # latest release
curl -LO https://github.com/DikshitRJ/arkivector/releases/download/v${VERSION}/arkivectord-${VERSION}-linux-x86_64.tar.gz
curl -LO https://github.com/DikshitRJ/arkivector/releases/download/v${VERSION}/SHA256SUMS
sha256sum -c --ignore-missing SHA256SUMS
tar xzf arkivectord-${VERSION}-linux-x86_64.tar.gz
```

**Arkiv Rabdi testnet** (not something we ship: the chain the daemon reads from and writes to). Chain id 7794095 (`0x76edaf`), 2 s blocks, RPC `https://rpc.rabdi.db-chain.testnet.arkiv.network`. Test GLM from the faucet at <https://hub.arkiv.network/faucet>.

## Roadmap

Tracked on GitHub: <https://github.com/DikshitRJ/arkivector/issues/19>. Everything in the install guide works and was tested end to end, including on the Rabdi testnet. These are the parts that are not finished yet.

| Limitation | Today | Plan | Issue |
| :--- | :--- | :--- | :--- |
| Tested on the Rabdi testnet only | Mainnet is configurable but untried | Run the sync and write suites on mainnet and measure gas reservations there | [#16](https://github.com/DikshitRJ/arkivector/issues/16) |
| Linux and Docker only | macOS and Windows use the container | Port the glibc-specific calls | [#17](https://github.com/DikshitRJ/arkivector/issues/17) |
| Two SDK languages | SDKs for Python and Node.js | C, C++ and Rust SDKs | [#18](https://github.com/DikshitRJ/arkivector/issues/18) |

Done in v1.2.0:

| Fixed | What changed | Issue |
| :--- | :--- | :--- |
| HNSW graphs survive restarts | Graphs are saved per expiry band under `data_dir/segments` and loaded at startup (only changes since the save are indexed); rebuilds run on a background thread while sync continues; expired bands are dropped whole; corrupt files are rejected and rebuilt | [#11](https://github.com/DikshitRJ/arkivector/issues/11) |
| Entity keys follow the wallet's on-chain nonce | Writes read `entityNonce` before predicting keys and take final keys from the `EntityCreated` receipt logs; `entities:prepare` uses the wallet's real nonces | [#13](https://github.com/DikshitRJ/arkivector/issues/13) |
| Dynamic gas fees | Fees from `eth_feeHistory` (then `eth_gasPrice`, then config) with a cap; gas limit = estimate + margin; stuck transactions are resent with bumped fees | [#14](https://github.com/DikshitRJ/arkivector/issues/14) |
| Qdrant writes are real | Upserts and deletes go through the REST writer, searches return payloads, a daemon without a signer refuses writes | [#15](https://github.com/DikshitRJ/arkivector/issues/15) |
| Sign with your own wallet, keystores and remote signers | `entities:prepare` returns transactions ready to sign; the new `entities:submit` broadcasts what the user's wallet signed (or waits for what it broadcast) and returns the mined keys; the SDKs do prepare → sign → submit with MetaMask, viem, ethers or `eth_account`; the daemon's own signer can be an encrypted keystore or a Web3Signer/Clef remote signer; `/v1/version` reports the signer kind | [#12](https://github.com/DikshitRJ/arkivector/issues/12) |

## Team

Page: [https://arkivector.dikshitrj.in/team](https://arkivector.dikshitrj.in/team). One person built Arkivector for ETHGlobal Mumbai 2026: Dikshit Rishi Jain (NITK Surathkal), <https://github.com/DikshitRJ>. Questions, bugs or ideas: open a GitHub issue at <https://github.com/DikshitRJ/arkivector/issues>.

## Documentation index

Every page also exists as Markdown: add `.md` to its URL (the docs home is `/docs/index.md`). All of them together: [https://arkivector.dikshitrj.in/docs.md](https://arkivector.dikshitrj.in/docs.md).

### Start here

- [Arkivector documentation](https://arkivector.dikshitrj.in/docs) ([Markdown](https://arkivector.dikshitrj.in/docs/index.md)): Arkivector is pgvector for Arkiv. A small daemon, arkivectord, syncs entities from the Arkiv chain, indexes their vectors with pgvector's own code (exact…
- [Install and get started](https://arkivector.dikshitrj.in/docs/install) ([Markdown](https://arkivector.dikshitrj.in/docs/install.md)): Everything you need to go from nothing to a working vector search on Arkiv: the daemon, an Arkiv wallet and access key, and an SDK. It takes about ten…

### Getting started

- [Quick start](https://arkivector.dikshitrj.in/docs/getting-started/quickstart) ([Markdown](https://arkivector.dikshitrj.in/docs/getting-started/quickstart.md)): Your first collection, writes and searches. This page assumes the daemon is running with a wallet key and you know the wallet's address: if not, do…
- [Concepts](https://arkivector.dikshitrj.in/docs/getting-started/concepts) ([Markdown](https://arkivector.dikshitrj.in/docs/getting-started/concepts.md)): A collection is the Arkivector equivalent of a pgvector table plus its index: It has a column (vector type and dimension), an index (hnsw or none, plus an…
- [Configuration](https://arkivector.dikshitrj.in/docs/getting-started/configuration) ([Markdown](https://arkivector.dikshitrj.in/docs/getting-started/configuration.md)): The daemon reads an optional TOML file (arkivectord --config ). Every key can be overridden with an environment variable named ARKIVECTOR__, and the…
- [Signing writes](https://arkivector.dikshitrj.in/docs/getting-started/signing) ([Markdown](https://arkivector.dikshitrj.in/docs/getting-started/signing.md)): Every write is an Arkiv transaction, and someone has to sign it. Arkivector gives you two places to do that, and you can mix them per request:

### REST API

- [REST API](https://arkivector.dikshitrj.in/docs/api) ([Markdown](https://arkivector.dikshitrj.in/docs/api.md)): Everything Arkivector does is a JSON-over-HTTP call to the daemon, so any language (or a shell) can use it without an SDK. These pages document every…
- [Health and version](https://arkivector.dikshitrj.in/docs/api/health) ([Markdown](https://arkivector.dikshitrj.in/docs/api/health.md)): Operational endpoints. /healthz, /readyz, /v1/version and /metrics never need an API key.
- [Collections](https://arkivector.dikshitrj.in/docs/api/collections) ([Markdown](https://arkivector.dikshitrj.in/docs/api/collections.md)): A collection binds a pgvector-style column and index to an Arkiv schema tag and a set of writers. The daemon syncs every matching entity from the chain…
- [Upsert entities](https://arkivector.dikshitrj.in/docs/api/entities-upsert) ([Markdown](https://arkivector.dikshitrj.in/docs/api/entities-upsert.md)): POST /v1/collections/{name}/entities writes entities to the Arkiv chain through the daemon's wallet. Needs a signer (writes_enabled: true, otherwise 403…
- [Get an entity](https://arkivector.dikshitrj.in/docs/api/entities-get) ([Markdown](https://arkivector.dikshitrj.in/docs/api/entities-get.md)): GET /v1/collections/{name}/entities/{ref} reads one live entity by its id or Arkiv key. Only entities that are live at as_of_block are returned. Expired…
- [Delete and extend](https://arkivector.dikshitrj.in/docs/api/entities-delete-extend) ([Markdown](https://arkivector.dikshitrj.in/docs/api/entities-delete-extend.md)): Remove entities from the chain, or extend their lifetime. Both send Arkiv transactions, so they need a signer and the write scope. Only entities owned by…
- [Prepare (sign with your own wallet)](https://arkivector.dikshitrj.in/docs/api/entities-prepare) ([Markdown](https://arkivector.dikshitrj.in/docs/api/entities-prepare.md)): POST /v1/collections/{name}/entities:prepare builds the Arkiv transactions for an upsert without sending them, so a browser wallet, a hardware wallet, a…
- [Submit (signed by your wallet)](https://arkivector.dikshitrj.in/docs/api/entities-submit) ([Markdown](https://arkivector.dikshitrj.in/docs/api/entities-submit.md)): POST /v1/collections/{name}/entities:submit is the second half of signing with your own wallet: it takes back the transactions prepare built, after you…
- [Search](https://arkivector.dikshitrj.in/docs/api/search) ([Markdown](https://arkivector.dikshitrj.in/docs/api/search.md)): POST /v1/collections/{name}/search returns the k live entities nearest to a query vector, optionally restricted by a filter.
- [Batch search](https://arkivector.dikshitrj.in/docs/api/search-batch) ([Markdown](https://arkivector.dikshitrj.in/docs/api/search-batch.md)): POST /v1/collections/{name}/search:batch runs up to 64 searches against the same snapshot (one as_of_block).
- [Scroll](https://arkivector.dikshitrj.in/docs/api/scroll) ([Markdown](https://arkivector.dikshitrj.in/docs/api/scroll.md)): POST /v1/collections/{name}/scroll pages through live entities that match an optional filter, in ascending key order. Use it to export a collection or…
- [Count](https://arkivector.dikshitrj.in/docs/api/count) ([Markdown](https://arkivector.dikshitrj.in/docs/api/count.md)): POST /v1/collections/{name}/count returns the exact number of live entities, optionally only those matching a filter.
- [Filters](https://arkivector.dikshitrj.in/docs/api/filters) ([Markdown](https://arkivector.dikshitrj.in/docs/api/filters.md)): Search, scroll, count and the filter-based delete and extend endpoints accept at most one of:
- [Vectors](https://arkivector.dikshitrj.in/docs/api/vectors) ([Markdown](https://arkivector.dikshitrj.in/docs/api/vectors.md)): halfvec is recommended for embeddings: half the bytes and gas of vector, with almost no loss in recall. Values are rounded from float32 with…
- [Consistency](https://arkivector.dikshitrj.in/docs/api/consistency) ([Markdown](https://arkivector.dikshitrj.in/docs/api/consistency.md)): The daemon applies the chain block by block and publishes each block atomically. Every data response reflects exactly one block, as_of_block (also in the…
- [Errors](https://arkivector.dikshitrj.in/docs/api/errors) ([Markdown](https://arkivector.dikshitrj.in/docs/api/errors.md)): Every error is an RFC 9457 problem document (application/problem+json). Branch on code, never on detail.
- [Qdrant compatibility](https://arkivector.dikshitrj.in/docs/api/qdrant) ([Markdown](https://arkivector.dikshitrj.in/docs/api/qdrant.md)): The daemon serves a subset of the Qdrant REST API under /qdrant, so tools that already speak Qdrant (LangChain and LlamaIndex Qdrant stores, Dify…

### Python SDK

- [Python SDK](https://arkivector.dikshitrj.in/docs/python) ([Markdown](https://arkivector.dikshitrj.in/docs/python.md)): arkivector is a typed client for the Arkivector daemon: stdlib only (no runtime dependencies), Python 3.9+, thread-safe, with adapters for LangChain and…
- [Client](https://arkivector.dikshitrj.in/docs/python/client) ([Markdown](https://arkivector.dikshitrj.in/docs/python/client.md)): The client is thread-safe and reuses HTTP connections. Close it when done, or use it as a context manager:
- [Collections](https://arkivector.dikshitrj.in/docs/python/collections) ([Markdown](https://arkivector.dikshitrj.in/docs/python/collections.md)): Opclasses by column type are listed in the Collections API.
- [Writing](https://arkivector.dikshitrj.in/docs/python/writing) ([Markdown](https://arkivector.dikshitrj.in/docs/python/writing.md)): upsert, extend and delete go on chain through the daemon's wallet, so the daemon needs a signer (client.version().writes_enabled). To have each user sign…
- [Searching](https://arkivector.dikshitrj.in/docs/python/searching) ([Markdown](https://arkivector.dikshitrj.in/docs/python/searching.md)): The query vector can be a list of floats, a pgvector literal ("[1,0,0,0]"), or a typed vector (Vector, HalfVector, SparseVector, Bit).
- [Reading](https://arkivector.dikshitrj.in/docs/python/reading) ([Markdown](https://arkivector.dikshitrj.in/docs/python/reading.md)): Point reads, counts and scans that don't need a query vector. ref is an id or a key. A missing, expired or deleted entity raises NotFoundError…
- [Filters](https://arkivector.dikshitrj.in/docs/python/filters) ([Markdown](https://arkivector.dikshitrj.in/docs/python/filters.md)): F builds the JSON filter tree (Filters API). Combine with & (and), | (or) and ~ (not):
- [Types](https://arkivector.dikshitrj.in/docs/python/types) ([Markdown](https://arkivector.dikshitrj.in/docs/python/types.md)): The pgvector types, usable as query vectors, in EntityInput.vector, and returned as hit.vector / entity.vector when you include vectors.
- [Errors](https://arkivector.dikshitrj.in/docs/python/errors) ([Markdown](https://arkivector.dikshitrj.in/docs/python/errors.md)): Every API error is an ApiError subclass carrying the daemon's problem document:
- [LangChain and LlamaIndex](https://arkivector.dikshitrj.in/docs/python/integrations) ([Markdown](https://arkivector.dikshitrj.in/docs/python/integrations.md)): The SDK ships vector store adapters. Install the framework yourself; arkivector does not depend on it.

### Node.js SDK

- [Node.js / TypeScript SDK](https://arkivector.dikshitrj.in/docs/node) ([Markdown](https://arkivector.dikshitrj.in/docs/node.md)): @dikshitrj/arkivector is a typed client for the Arkivector daemon: ESM, zero runtime dependencies, Node 18+ (and any runtime with fetch), with a…
- [Client](https://arkivector.dikshitrj.in/docs/node/client) ([Markdown](https://arkivector.dikshitrj.in/docs/node/client.md)): Arkivector is the Node.js client: one instance per daemon, with retries, timeouts, idempotent writes and optional read-your-writes consistency.
- [Collections](https://arkivector.dikshitrj.in/docs/node/collections) ([Markdown](https://arkivector.dikshitrj.in/docs/node/collections.md)): Create, list, follow and delete collections from Node.js. A collection is a vector column, an index and the wallets whose entities it indexes.
- [Writing](https://arkivector.dikshitrj.in/docs/node/writing) ([Markdown](https://arkivector.dikshitrj.in/docs/node/writing.md)): upsert, extend and delete go on chain through the daemon's wallet; the daemon needs a signer ((await client.version()).writesEnabled). To have each user…
- [Searching](https://arkivector.dikshitrj.in/docs/node/searching) ([Markdown](https://arkivector.dikshitrj.in/docs/node/searching.md)): distance is pgvector's distance for the operator; score is 1 − distance for cosine and −distance otherwise (Search API).
- [Reading](https://arkivector.dikshitrj.in/docs/node/reading) ([Markdown](https://arkivector.dikshitrj.in/docs/node/reading.md)): Options: include, verify, minBlock, timeoutMs. ref is an id or a key; a missing entity throws NotFoundError.
- [Filters](https://arkivector.dikshitrj.in/docs/node/filters) ([Markdown](https://arkivector.dikshitrj.in/docs/node/filters.md)): F builds the JSON filter tree (Filters API): F.and and F.or also take an array. Plain values are typed from the collection's declared attributes; use T…
- [Types](https://arkivector.dikshitrj.in/docs/node/types) ([Markdown](https://arkivector.dikshitrj.in/docs/node/types.md)): Plain arrays and Float32Array work everywhere; the SDK casts them to the column type. Attributes come back as TypedValue { type, value }…
- [Errors](https://arkivector.dikshitrj.in/docs/node/errors) ([Markdown](https://arkivector.dikshitrj.in/docs/node/errors.md)): All API errors extend ApiError, which carries the daemon's problem document:
- [LangChain.js](https://arkivector.dikshitrj.in/docs/node/integrations) ([Markdown](https://arkivector.dikshitrj.in/docs/node/integrations.md)): The package exports a LangChain.js-compatible vector store from @dikshitrj/arkivector/langchain. It works with any embeddings object that has…

### MCP server

- [MCP server](https://arkivector.dikshitrj.in/docs/mcp) ([Markdown](https://arkivector.dikshitrj.in/docs/mcp.md)): arkivectord is a Model Context Protocol server. AI agents (Claude Code, Claude Desktop, Cursor, and any MCP client) can list your collections, run vector…
- [Connect a client](https://arkivector.dikshitrj.in/docs/mcp/setup) ([Markdown](https://arkivector.dikshitrj.in/docs/mcp/setup.md)): The daemon must be running (Installation). The MCP URL is the daemon URL plus /mcp, e.g. http://127.0.0.1:8080/mcp. If the daemon uses API keys, give the…
- [Tools](https://arkivector.dikshitrj.in/docs/mcp/tools) ([Markdown](https://arkivector.dikshitrj.in/docs/mcp/tools.md)): Every tool result has content (one text block), isError, and on success structuredContent holding the response of the matching REST endpoint. Errors carry…

### Architecture

- [Architecture](https://arkivector.dikshitrj.in/docs/architecture) ([Markdown](https://arkivector.dikshitrj.in/docs/architecture.md)): Arkivector is a co-processor next to the Arkiv chain. The chain stays the source of truth; the daemon keeps a local index it can always rebuild from…
- [Chain sync](https://arkivector.dikshitrj.in/docs/architecture/sync) ([Markdown](https://arkivector.dikshitrj.in/docs/architecture/sync.md)): The sync engine keeps, for every collection, an exact copy of the entities that belong to it at the last applied block. One sync thread serves all…
- [Storage](https://arkivector.dikshitrj.in/docs/architecture/storage) ([Markdown](https://arkivector.dikshitrj.in/docs/architecture/storage.md)): Everything the daemon stores locally can be rebuilt from the chain (--resync). It lives in storage.data_dir.
- [Search and HNSW](https://arkivector.dikshitrj.in/docs/architecture/search) ([Markdown](https://arkivector.dikshitrj.in/docs/architecture/search.md)): Exact selectivity is free here because filters are bitmaps; pgvector itself has to estimate it. Small candidate sets are always faster to scan exactly…
- [Write path](https://arkivector.dikshitrj.in/docs/architecture/write-path) ([Markdown](https://arkivector.dikshitrj.in/docs/architecture/write-path.md)): The daemon never indexes a write optimistically. An entity appears in search only after it has been read back from the chain, so the index cannot drift…
- [pgvector inside the daemon](https://arkivector.dikshitrj.in/docs/architecture/pgvector) ([Markdown](https://arkivector.dikshitrj.in/docs/architecture/pgvector.md)): The goal was to run pgvector's actual math, not a reimplementation, so results match pgvector by construction. pgvector is a PostgreSQL extension written…
- [VectorBytes](https://arkivector.dikshitrj.in/docs/architecture/vectorbytes) ([Markdown](https://arkivector.dikshitrj.in/docs/architecture/vectorbytes.md)): The format of the vector stored on chain in the av.vec attribute, also accepted and returned by the API as base64 vector_bytes. The idea: make the…

### Operations

- [Deployment](https://arkivector.dikshitrj.in/docs/operations/deployment) ([Markdown](https://arkivector.dikshitrj.in/docs/operations/deployment.md)): The image runs as a non-root user and keeps state in /data. :latest follows the latest release; to pin, use :1 (latest 1.x) or an exact : from the…
- [Security](https://arkivector.dikshitrj.in/docs/operations/security) ([Markdown](https://arkivector.dikshitrj.in/docs/operations/security.md)): By default the daemon listens on 127.0.0.1:8080 with no authentication: anyone who can reach the port can read every collection and, with a managed…
- [Monitoring](https://arkivector.dikshitrj.in/docs/operations/monitoring) ([Markdown](https://arkivector.dikshitrj.in/docs/operations/monitoring.md)): Useful alerts: readiness false for more than a few minutes, lag_blocks growing in /v1/sync, a rising rate of 5xx responses, p99 search latency.
- [Troubleshooting](https://arkivector.dikshitrj.in/docs/operations/troubleshooting) ([Markdown](https://arkivector.dikshitrj.in/docs/operations/troubleshooting.md)): The collection only indexes entities created by its writers. Check that the daemon wallet's address is in the list:

### Development

- [Contributing](https://arkivector.dikshitrj.in/docs/development) ([Markdown](https://arkivector.dikshitrj.in/docs/development.md)): Process documents: AGENTS.md (workflow, ownership, coding standards), CODEBASE.md (file map), ARCHITECTURE.md (design).
- [Testing](https://arkivector.dikshitrj.in/docs/development/testing) ([Markdown](https://arkivector.dikshitrj.in/docs/development/testing.md)): golden_check verifies the VectorBytes codec against the 29 golden vectors offline, and with ARKIVECTOR_URL set, the demo-dataset queries against a live…
- [Releasing](https://arkivector.dikshitrj.in/docs/development/releasing) ([Markdown](https://arkivector.dikshitrj.in/docs/development/releasing.md)): Releases are cut from main by pushing a version tag: The release workflow then builds and publishes:
