Your corpus stays with its keeper.
Run a data node beside your agent: immutable records, content-addressed blobs, SQLite full-text search, provenance, and an append-only change feed. The base node reads local indexes only and advertises peer_sync: false; the optional explicit-pull wrapper advertises only its bounded agent-data-sync/v1 profile.
AgentTool may help an agent find or call a node. It does not have to own the raw bytes.
There is no hosted AgentTool data node in this release. Do not send these paths to api.agenttool.dev, and do not look for data.agenttool.dev. Each operator runs or selects a node and discovers it at that node's own /.well-known/agent-data. The default reference CLI binds to 127.0.0.1:7742.
Two related layers, two separate jobs
| Layer | What it does | What it does not do |
|---|---|---|
@agenttool/dataagent-data/v1 |
Collects bounded content into local collections, stores immutable envelopes and blobs, indexes text, queries, and emits resumable local changes. | No hosted storage, discovery, push, general federation, automatic memory projection, or general signature/schema enforcement. Optional sync is explicit bounded pull between configured peers. |
@agenttool/addsadds/v0.1 · experimental |
Encrypts immutable content-addressed Blocks and signs Manifests and direct read Grants for offline, provider-independent exchange. | No collection query API, peer discovery, global revocation, proof of storage, secure deletion, or provider durability guarantee. |
SDK at.data |
Calls a separately configured agent-data/v1 node from the TypeScript or Python AgentTool SDK. |
Does not discover a hosted node implicitly and never implicitly forwards the AgentTool project bearer as the node bearer. |
sources ──collect──> your @agenttool/data node
├── SQLite metadata + FTS
├── content-addressed local blobs
└── dedicated node bearer
optional @agenttool/adds ──> encrypted Blocks + signed control records
@agenttool/sdk at.data ──HTTP──> that node's URL
api.agenttool.dev ──X────> no implicit raw-data path
Run the local reference node
The reference node requires Bun because it uses bun:sqlite and Bun.serve. The CLI creates a default private collection and local .agent-data/ directory. Use a dedicated random node token. The SDK configures that token separately and never implicitly forwards AT_API_KEY; a caller can still explicitly supply the same value and should not do so.
bun add https://docs.agenttool.dev/packages/v1/@agenttool/data/0.3.0/agenttool-data-0.3.0.tgz
export AGENT_DATA_NODE_TOKEN='<dedicated-random-node-token>'
bunx --bun --no-install --package @agenttool/data agenttool-data --root=./.agent-data
# agent-data/v1 node ... listening at http://127.0.0.1:7742
Network boundary. Discovery and the capability manifest are public at the node. Every data route requires the dedicated node bearer. The CLI refuses a non-loopback bind unless that bearer is configured. TLS, firewalling, backups, and remote exposure remain operator responsibilities.
Check a node with the executable profile
agenttool-data doctor, introduced in @agenttool/data@0.2.0 and included in 0.3.0, is a bounded black-box runner for agent-data/v1-slice1-http. Its JSON report follows the public conformance report schema and validates only the observed HTTP profile at that target and time; it is not a security certification, durability proof, or secure-erasure claim.
# Public discovery and synthetic auth-boundary probes bunx --bun --no-install --package @agenttool/data agenttool-data \ doctor http://127.0.0.1:7742 --profile public # Supply a dedicated node bearer through stdin, never argv printf '%s' "$AGENT_DATA_NODE_TOKEN" | \ bunx --bun --no-install --package @agenttool/data agenttool-data \ doctor http://127.0.0.1:7742 --profile read --token-stdin
Mutation is opt-in. The full slice1 lifecycle requires an expected node ID, a dedicated scratch collection, and explicit acknowledgement that immutable records, change events, and tombstones can remain. The runner never auto-selects a collector or claims physical cleanup.
Discover, collect, and query
# Public capability truth curl http://127.0.0.1:7742/.well-known/agent-data # Collect one local text item curl -X POST http://127.0.0.1:7742/v1/data/collect \ -H "Authorization: Bearer $AGENT_DATA_NODE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "collection_id": "default", "collector_id": "text", "input": { "text": "Local-first agents keep their corpus close." } }' # Query the node-local FTS index curl -X POST http://127.0.0.1:7742/v1/data/query \ -H "Authorization: Bearer $AGENT_DATA_NODE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "collections": ["default"], "text": "corpus", "consistency": "local" }'
Use the optional encrypted-object plane
@agenttool/adds is the experimental reference implementation of the separate adds/v0.1 working draft. It can encrypt, address, sign, store, and share exact objects offline through memory, filesystem, or caller-provided stores. A CID and signature prove bytes and key control; they do not prove a claim is true or that a provider will retain the object.
bun add https://docs.agenttool.dev/packages/v1/@agenttool/adds/0.2.0/agenttool-adds-0.2.0.tgz import { AgentData, MemoryBlockStore, generateIdentity } from "@agenttool/adds"; const data = new AgentData({ identity: generateIdentity("did:example:agent"), store: new MemoryBlockStore(), }); const published = await data.put("private agent context", { mediaType: "text/plain; charset=utf-8", }); console.log(published.ref); // ciphertext/control-document CID reference
Two protocols, no sleight of hand. agent-data/v1 is the higher collection/query contract. adds/v0.1 is an optional lower encrypted-object plane. Implementations must not validate one protocol under the other's signing domains or claim ADDS peer discovery that does not exist.
Pull encrypted pages from an explicit peer
@agenttool/data-sync composes the data node and ADDS packages. It discovers no peers and accepts no caller-supplied peer URL or credential: the operator configures the exact origin, source node and publisher keys, page-only bearer, collection allow-list, and recipient key. Verified records are retained in the destination node for offline query.
bun add https://docs.agenttool.dev/packages/v1/@agenttool/data-sync/0.1.0/agenttool-data-sync-0.1.0.tgz import { DataSyncService } from "@agenttool/data-sync";
Bounded profile, not global replication. The bridge is pull-only, pins the exact origin/node/publisher/feed checkpoint identity, separates page authority from local admin authority, and exposes no raw cursor through the SDK. It does not provide discovery, push, consensus, multi-master conflict resolution, CAR transport, or a hosted sync service.
Use at.data with separate configuration
The SDK integration has two independent configuration fields. apiKey authorizes the hosted AgentTool project. dataNode.token authorizes the node you selected. The SDK never implicitly substitutes or forwards one as the other.
import { AgentTool } from "@agenttool/sdk"; const at = new AgentTool({ apiKey: process.env.AT_API_KEY, dataNode: { baseUrl: "http://127.0.0.1:7742", token: process.env.AGENT_DATA_NODE_TOKEN, }, }); const hits = await at.data.query({ collections: ["default"], text: "local-first", consistency: "local", });
from agenttool import AgentTool import os at = AgentTool( api_key=os.environ["AT_API_KEY"], data_node_url="http://127.0.0.1:7742", data_node_token=os.environ["AGENT_DATA_NODE_TOKEN"], ) hits = at.data.query( collections=["default"], text="local-first", consistency="local", )
For data-only use with no AgentTool account, instantiate the exported TypeScript or Python DataClient directly with the node URL and token. It does not require AT_API_KEY.
Reference node HTTP surface
| Method | Path | Authority | Purpose |
|---|---|---|---|
| GET | /.well-known/agent-data | Public | Discover this node's exact capabilities and peer_sync: false status. |
| GET | /v1/data/manifest | Public | Same node capability manifest. |
| GET | /v1/data/collections | Node bearer | List locally configured collections. |
| POST | /v1/data/collect | Node bearer | Run a registered bounded collector. |
| POST | /v1/data/query | Node bearer | Query local materialized indexes. |
| GET | /v1/data/records/:id | Node bearer | Resolve one immutable record and its verified local content. |
| GET | /v1/data/changes | Node bearer | Read the append-only change feed with an opaque cursor. |
| POST | /v1/data/records/:id/tombstone | Node bearer | Append a tombstone; this is not physical blob erasure. |
Slice 1 capability truth
| Capability | Status | Boundary |
|---|---|---|
| Immutable records, SHA-256 blobs, SQLite FTS5, change cursors | Implemented | Local reference node. |
| Text, local-file, and bounded HTTP collectors | Implemented | File paths become provenance and may be sensitive. HTTP SSRF checks are best-effort, not a network sandbox. |
| Collection size and media-type policy | Enforced | Node-wide limits may be stricter. |
| JSON Schema, visibility, TTL, retention, DID ACL, supplied signatures | Stored declarations | Not enforced or verified by Slice 1. |
| Explicit encrypted peer pull | Optional profile | The base node remains peer_sync: false. @agenttool/data-sync advertises true only when its bounded configured-peer wrapper is installed. |
| Hosted AgentTool storage or automatic memory projection | Not implemented | Projection into AgentTool memory must be an explicit caller action. |
| ADDS encrypted Blocks, signed Manifests, direct read Grants, and offline vectors | Experimental package | Separate adds/v0.1 layer; provider records, Heads, and Receipts are specified but the reference package intentionally exposes only its strict first profile. |
Protocol and wire references
AGENT-DATA-PROTOCOL.md— normativeagent-data/v1collection, record, query, and change contract.ADDS-0.1-DRAFT.md— experimental encrypted-object working draft, with a machine-readable schema and pinned vectors.- Memory — hosted, project-bearer-gated memory records; a separate surface from raw local corpora.