Quickstart
From token to bundle
Ten minutes, one small repository, and whatever embedding model you already have wired up.
1. Get a token
Take one from the home page. It is generated in your browser and shown once, so put it somewhere before you close the tab.
export RP_TOKEN=rp_...
Fresh tokens go through an activation queue and normally start working within 24 hours. Until then every call answers 401 — that is the queue, not a mistake on your side.
2. Create a collection
One collection per body of work. Set dims to your model's output width; it cannot be changed afterwards.
curl -X POST https://rebornpad.dev/api/v1/collections \
-H "Authorization: Bearer $RP_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"monorepo/api","dims":1024,"metric":"cosine"}'
{"id":"col_9fK2mQ","name":"monorepo/api","chunks":0,"dims":1024}
Repeating this call with the same name returns the existing collection rather than creating a second one, so it is safe to run from a script that does not track state.
3. Chunk and embed
We do not chunk or embed for you. Whatever splitter and model your agent already uses will do — the only requirement is that every vector in a collection has the same width.
A workable default: split on syntactic boundaries, cap chunks at roughly 400 tokens, and keep the file path and revision in metadata so retrieved context can be traced back to source.
import os, json, hashlib
def records(paths, embed):
for path in paths:
src = open(path, encoding="utf-8").read()
for start, end, text in split(src): # your splitter
yield {
"path": path,
"span": [start, end],
"text": text,
"vector": embed(text), # your model
"meta": {
"lang": os.path.splitext(path)[1].lstrip("."),
"rev": revision,
},
}
4. Ingest
Stream the records as newline-delimited JSON over a single connection. Opening a new request per batch is the most common reason a first ingest crawls.
import requests
def stream(recs):
for r in recs:
yield (json.dumps(r) + "\n").encode()
resp = requests.post(
"https://rebornpad.dev/api/v1/ingest",
headers={
"Authorization": f"Bearer {os.environ['RP_TOKEN']}",
"Content-Type": "application/x-ndjson",
"X-Collection": "col_9fK2mQ",
},
data=stream(records(paths, embed)),
stream=True,
)
for line in resp.iter_lines():
if line:
print(json.loads(line)) # {"ack": 512, "accepted": 512, "rejected": 0}
Acknowledgements come back while you are still writing, so you can slow down or stop early instead of buffering the whole repository in memory.
Expect a few hundred megabytes and several minutes for a mid-sized repository. Large monorepos run into the gigabytes and can take an hour — that is the shape of the workload, not a stall.
5. Retrieve
Search returns a handle. Fetching the handle returns the bundle.
r = requests.post(
"https://rebornpad.dev/api/v1/search",
headers={"Authorization": f"Bearer {token}"},
json={"collection": "col_9fK2mQ", "vector": embed(question), "k": 24},
)
handle = r.json()["bundle"]
raw = requests.get(
f"https://rebornpad.dev/api/v1/query/{handle}",
headers={"Authorization": f"Bearer {token}"},
).text
import base64, zlib
bundle = json.loads(zlib.decompress(base64.b64decode(raw)))
for chunk in bundle["chunks"]:
print(chunk["path"], round(chunk["score"], 3))
The bundle arrives deflated and base64-encoded rather than as JSON. It is one line of text that can be cached, piped, or handed to a context loader without a parser in the middle.
Where to go next
- Keep a connection open with /stream if the agent runs for a long stretch — you get context updates without polling.
- Read connection handling before you put a proxy or a short idle timeout in front of any of this.
- Check the beta limits if you are about to index something large.