Search Everything
Supply searchable file text, grep files, Docs, and records, then read only the matching range.
Search Everything
Busabase provides one exact-search loop for people and AI agents:
supply searchable text -> grep -> read the matching line rangePOST /api/v1/grep searches files, Doc bodies, and the canonical approved values in Base records. Results include the source, line, column, and nearby context, so a caller can locate evidence before reading more.
What is searchable
| Source | Text used by grep |
|---|---|
| Files | The Asset's searchable text slot |
| Docs | The current Doc body |
| Records | The current approved record fields |
Text files such as Markdown, JSON, CSV, logs, and source code use their own UTF-8 bytes as searchable text. Binary files such as PDFs, office documents, audio, video, or images need an external tool or agent to extract or transcribe text and supply it to the Asset.
Busabase stores and searches supplied text, but does not run bundled OCR, transcription, or document parsers.
Supply searchable text for a file
An Asset reports one of four textStatus values:
| Status | Meaning | Next action |
|---|---|---|
missing | No searchable text has been supplied | Supply text or mark the file as having no extractable text |
present | Current searchable text is available | Grep or read it; replace it when a better extraction is available |
stale | The source file changed after text was supplied | Supply text derived from the new file |
none | The file is intentionally marked as having no extractable text | Supply text later if OCR or transcription becomes available |
The Asset detail page exposes the same supply, replace, and preview actions. API and agent clients have three write methods.
Small text: write inline
Use putText directly for UTF-8 text up to 1 MB:
curl -X PUT "$BUSABASE_BASE_URL/api/v1/assets/$ASSET_ID/text" \
-H "Authorization: Bearer $BUSABASE_API_KEY" \
-H "Content-Type: application/json" \
--data '{"text":"Extracted contract text\nTermination clause..."}'The response reports the persisted status and counts:
{
"assetId": "asset_contract_pdf",
"textStatus": "present",
"lineCount": 84,
"charCount": 4921,
"byteCount": 4937
}Large text: upload, then bind
For text larger than 1 MB, keep the write streaming-safe:
- Request a temporary upload URL with
POST /api/v1/assets/text/upload-urls. PUTthe UTF-8.txtbytes to the returneduploadUrl.- Bind the returned
storageKeywithPUT /api/v1/assets/{assetId}/text.
SIZE_BYTES=$(wc -c < extracted.txt | tr -d ' ')
curl -X POST "$BUSABASE_BASE_URL/api/v1/assets/text/upload-urls" \
-H "Authorization: Bearer $BUSABASE_API_KEY" \
-H "Content-Type: application/json" \
--data "{\"assetId\":\"$ASSET_ID\",\"sizeBytes\":$SIZE_BYTES}"
# -> { "uploadUrl": "...", "storageKey": "...", "expiresIn": 900 }
curl -X PUT "<uploadUrl>" \
-H "Content-Type: text/plain; charset=utf-8" \
--data-binary @extracted.txt
curl -X PUT "$BUSABASE_BASE_URL/api/v1/assets/$ASSET_ID/text" \
-H "Authorization: Bearer $BUSABASE_API_KEY" \
-H "Content-Type: application/json" \
--data '{"storageKey":"<storageKey>"}'The final bind verifies the uploaded bytes, validates UTF-8, and makes the text searchable. Supplying text again replaces the previous searchable text.
No extractable text: mark none
For an image-only or otherwise unextractable file, mark the text slot explicitly:
curl -X PUT "$BUSABASE_BASE_URL/api/v1/assets/$ASSET_ID/text" \
-H "Authorization: Bearer $BUSABASE_API_KEY" \
-H "Content-Type: application/json" \
--data '{"none":true}'Grep then counts the Asset as unsearchable instead of repeatedly reporting it as missing. You can reverse this later by supplying text.
Grep across files, Docs, and records
Omit sources to search all three sources, or select the ones you need:
curl -X POST "$BUSABASE_BASE_URL/api/v1/grep" \
-H "Authorization: Bearer $BUSABASE_API_KEY" \
-H "Content-Type: application/json" \
--data '{
"pattern":"termination",
"flags":"i",
"sources":["files","docs","records"],
"contextLines":2
}'pattern uses JavaScript regular-expression syntax. A plain word is also a valid pattern. Use scope.files, scope.docs, or scope.records to narrow a large search.
{
"matches": [
{
"source": "files",
"assetId": "asset_contract_pdf",
"fileName": "contract.pdf",
"drivePath": "legal/contract.pdf",
"line": 118,
"column": 1,
"text": "Termination requires 30 days notice.",
"before": ["..."],
"after": ["..."]
}
],
"coverage": {
"files": { "scanned": 24, "missing": [], "stale": [], "unsearchable": 1, "errored": [], "notReached": 0 },
"docs": { "scanned": 12, "errored": [], "notReached": 0 },
"records": { "scanned": 178, "errored": [], "notReached": 0 }
},
"truncated": false
}Always inspect coverage before treating no matches as "not found." missing, stale, errored, notReached, or truncated: true means the search was not complete. Missing or stale files need new searchable text; notReached or truncation usually means the caller should narrow the scope or pattern.
Read only the matching range
After a file match at line 118, read a bounded window instead of downloading the whole extraction:
curl "$BUSABASE_BASE_URL/api/v1/assets/$ASSET_ID/text/lines?startLine=113&endLine=123" \
-H "Authorization: Bearer $BUSABASE_API_KEY"For a Doc match, use its nodeId with the equivalent Doc endpoint:
curl "$BUSABASE_BASE_URL/api/v1/docs/$NODE_ID/lines?startLine=113&endLine=123" \
-H "Authorization: Bearer $BUSABASE_API_KEY"Asset reads are capped at 2,000 lines and use ranged storage reads, so this grep-then-read pattern remains suitable for very large supplied text.
putText is not editContent
These operations change different things and have different review rules:
| Operation | Changes | Source file | Review |
|---|---|---|---|
assets.putText | Disposable, derived text used by grep and ranged reads | Unchanged | Direct and audit-logged |
assets.editContent | The canonical bytes of one mounted Drive or Skill text file | Changed after merge | Creates a ChangeRequest for human review |
Do not use putText to edit a PDF, document, or mounted text file. Use it only to supply the representation that grep reads. Use editContent when the actual file must change.
There is deliberately no inline asset.text field in Asset responses. Large text remains outside AssetVO; inspect asset.textStatus, write with putText, search with grep, and read bounded ranges with readTextLines.
See also: REST API · MCP Integration · Core Concepts