Busabase

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 range

POST /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

SourceText used by grep
FilesThe Asset's searchable text slot
DocsThe current Doc body
RecordsThe 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:

StatusMeaningNext action
missingNo searchable text has been suppliedSupply text or mark the file as having no extractable text
presentCurrent searchable text is availableGrep or read it; replace it when a better extraction is available
staleThe source file changed after text was suppliedSupply text derived from the new file
noneThe file is intentionally marked as having no extractable textSupply 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:

  1. Request a temporary upload URL with POST /api/v1/assets/text/upload-urls.
  2. PUT the UTF-8 .txt bytes to the returned uploadUrl.
  3. Bind the returned storageKey with PUT /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:

OperationChangesSource fileReview
assets.putTextDisposable, derived text used by grep and ranged readsUnchangedDirect and audit-logged
assets.editContentThe canonical bytes of one mounted Drive or Skill text fileChanged after mergeCreates 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

On this page