Bonfÿre DocumentationContact

Build with Bonfÿre

Local-first applications

Build software that works with local data, does its computing on the device and can later connect to external systems. Bonfÿre's storage, indexing, model, context and protocol components can be used independently or composed into a customer-facing application.

Search three local notes

This example creates a SQLite index, finds a bicycle repair note from a question, updates the note and removes it. Each command opens the same file in a new process.

You need bonfyre-embed, bonfyre-vec, ONNX Runtime, the sqlite-vec extension and the installed nomic-embed-text-onnx model. Embed reads its vocab.txt and an ONNX model under ~/.cache/bonfyre/models/nomic-embed-text-onnx/onnx/. It recognizes model_qint8_arm64.onnx, model_O4.onnx or model.onnx. Model setup is a prerequisite; the commands below make no model downloads.

From a configured source checkout, build the commands and select those binaries:

Terminal
make -C cmd/BonfyreEmbed
make -C cmd/BonfyreVec
export PATH="$PWD/cmd/BonfyreEmbed:$PWD/cmd/BonfyreVec:$PATH"

Keep the following commands in the same shell so they share the workspace path. A fresh directory keeps repeat runs independent.

Terminal
bonfyre_example=$(mktemp -d "${TMPDIR:-/tmp}/bonfyre-local-notes.XXXXXX")
printf '%s\n' "$bonfyre_example"

cat > "$bonfyre_example/notes.jsonl" <<'NOTES'
{"id":"flat-tire","text":"For a flat bicycle tire, remove the wheel, lift the tire bead with a tire lever, replace the inner tube and inflate the tire."}
{"id":"pottery","text":"The pottery workshop teaches clay shaping, glazing and kiln firing. Aprons and tools are supplied."}
{"id":"bakery","text":"The bakery accepts orders for sourdough bread and birthday cakes. Collect bread from the counter in the morning."}
NOTES

bonfyre-embed --input-jsonl "$bonfyre_example/notes.jsonl" \
  --model nomic-embed-text-onnx \
  --insert-db "$bonfyre_example/vector.sqlite"
bonfyre-vec count "$bonfyre_example/vector.sqlite"

The batch result should report stored: 3, dims: 768, failed: 0, not_stored: 0 and degraded: 0. The count should read artifacts: 3, vectors: 3. Embed creates the database at the model's actual width. bonfyre-vec init creates a 384-dimensional store, so leave initialization to Embed for this 768-dimensional model.

Ask a question

Use the same model for documents and questions. Generate the query file before searching:

Terminal
printf '%s\n' 'How do I repair a punctured bicycle tire?' \
  > "$bonfyre_example/question.txt"
bonfyre-embed --text "$bonfyre_example/question.txt" \
  --model nomic-embed-text-onnx \
  --out "$bonfyre_example/question.json"
bonfyre-vec search "$bonfyre_example/vector.sqlite" \
  "$bonfyre_example/question.json" --top 3
bonfyre-vec search "$bonfyre_example/vector.sqlite" \
  "$bonfyre_example/question.json" --exact --top 3

Both searches should put flat-tire first. The default search includes the saved text, so an application can show the passage beside its ID. --exact scans stored vectors with cosine similarity. The default sqlite-vec store uses Euclidean distance; compare the returned IDs rather than treating the two distance values as the same metric. These search results identify passages; they do not generate a written answer.

Change a note without adding a duplicate

Keep the same document ID when replacing its content:

Terminal
printf '%s\n' \
  'For a punctured bicycle tire, inspect the tire for glass before fitting the replacement inner tube. Inflate it and check for leaks.' \
  > "$bonfyre_example/revised-note.txt"
bonfyre-embed --text "$bonfyre_example/revised-note.txt" \
  --model nomic-embed-text-onnx --doc-id flat-tire \
  --insert-db "$bonfyre_example/vector.sqlite"
bonfyre-vec count "$bonfyre_example/vector.sqlite"
bonfyre-vec search "$bonfyre_example/vector.sqlite" \
  "$bonfyre_example/question.json" --top 3

The count stays at three. The first result should contain the revised instruction about glass. Since the writer has exited before the next search starts, this also checks that the replacement survived reopening the database.

Remove a note

Delete its exact ID, then search again through both paths:

Terminal
bonfyre-vec delete "$bonfyre_example/vector.sqlite" flat-tire
bonfyre-vec count "$bonfyre_example/vector.sqlite"
bonfyre-vec search "$bonfyre_example/vector.sqlite" \
  "$bonfyre_example/question.json" --top 3
bonfyre-vec search "$bonfyre_example/vector.sqlite" \
  "$bonfyre_example/question.json" --exact --top 3
bonfyre-vec delete "$bonfyre_example/vector.sqlite" flat-tire

The first delete reports one vector and one artifact removed. The count becomes two, and neither search returns flat-tire. Repeating the delete reports zero removed. The source files remain in the example directory. A document indexed as several passages requires deleting each passage ID.

The remaining notes still appear in nearest-neighbor results, even though neither answers the bicycle question. Choose a relevance policy for your application before showing a result as an answer.

Resolve setup errors

ResultNext step
Model or vocabulary cannot be loadedCheck the installed model directory and ONNX file. Keep the document and query models identical.
sqlite-vec cannot be loadedPoint BONFYRE_VEC_EXT at the installed extension compatible with your SQLite build.
Store and query widths differCreate a fresh index from the source notes with the chosen model, then regenerate the query.
stored is less than the source countRead the batch's failure and vocabulary counters before querying.
A search returns unrelated notesInspect the source text and model coverage; nearest-neighbor search always ranks the available material.

For your own corpus, retain stable IDs and the source text needed to rebuild the index. Changing embedding models requires re-embedding both documents and questions, even when both models happen to produce the same number of dimensions.

Compose the application

An application may have several interfaces over its local state:

InterfaceImplementation role
C libraryStorage, model and representation operations at the source
BunDevelopment, integration and user-facing application tooling
WasmThe same compiled code, callable from a browser where supported
SQLite and vector indexesLocal records and retrieval
Arrow / ParquetPortable analytical representations and bulk material
WebAddressCustomer-specific pages, content and MCP endpoints
External API or FrappeOptional interoperability, not a requirement for keeping your own data

An application that runs in the browser should continue its permitted local work offline. Synchronization and remote execution can arrive later through typed changes and permission checks rather than silently replacing the local store.

One set of permissions across interfaces

The same person may use the application in a browser, invoke a CLI command or call an MCP tool. A customer may act on their own records, not on every record reachable by the runtime.

Preserve the source identity, customer scope, operation type, time and evidence as work crosses interfaces. A partner can deploy the same application for multiple organizations without granting cross-customer data access.

A component is also a product

Bonfÿre libraries should expose small stable interfaces when they solve independently useful problems: typed contracts, sqlite-vec and local storage, compression and model representations, audio pipelines, rendering, protocols, scheduling, finance and source-linked reconciliation.

The developer should not need the entire Aurekai deployment to use one library. A complete Aurekai operation can then combine those libraries with its customers, approvals, provider routes and commercial rules.

Ship a working result

Use this checklist to complete a local-first example:

  • Create a real local database and a real record.
  • Run an operation through the actual component.
  • Restart and prove the record and its identity survive.
  • Render the result in a web, terminal or application view.
  • Refuse a request made with a different customer's credentials.
  • Record which external services, if any, were called.
  • Verify the artifact's source, build and API version.

The example should include the minimal runnable source, dependency contracts and a clean start-to-finish session. Once that exists, the documentation can show its code, command output, WebAddress view and MCP interface from the same operation.

Continue with models and compression for running tensors directly, integration and migration for external databases, or white-label delivery for partner-operated applications.