Skip to content

Store app history in SQLite

Store the Bub application’s conversation history in a local SQLite database with bub-tapestore-sqlalchemy. The plugin replaces the app’s default file store; you can continue using ,tape.info and ,tape.search to inspect records.

This guide configures the plugin for the Bub CLI through BUB_* settings. In your own Python program, you can construct SQLAlchemyTapeStore and pass it directly to core.Agent; see Reuse plugins in your agent. Tape and context explains the shared storage behavior.

You need:

  • Bub installed and runnable with bub --help (see Install).
  • A workspace where bub run "What tools do you have?" can call your configured model.
  • The sqlite3 CLI for the optional database check.

Set BUB_HOME to an absolute path if you have not configured it already:

export BUB_HOME="${BUB_HOME:-$HOME/.bub}"
bub install bub-tapestore-sqlalchemy@main

Confirm Bub picked up the entry point:

bub hooks
provide_tape_store: builtin, tapestore-sqlalchemy

The plugin uses <BUB_HOME>/tapes.db by default. Override it for this tutorial so the database is easy to find and remove:

export BUB_TAPESTORE_SQLALCHEMY_URL="sqlite+pysqlite:///$PWD/bub-tapes.db"

This URL is passed to SQLAlchemy. The sqlite+pysqlite dialect uses Python’s standard SQLite driver, so no extra database driver is required.

Run a small natural-language task, then ask Bub to inspect the tape it just wrote:

bub run "Reply with one short sentence: hello from local SQLite."
bub run ",tape.info"
name: 86774b31b96845a4__0b871d5e50e7c192
entries: 9
anchors: 1
last_anchor: session/start
entries_since_last_anchor: 8
last_token_usage: 4106
last_token_cache_hit_rate: 72.50%

The exact tape name and counts depend on your workspace and model call, but the command should report a tape name, at least one anchor, and entries written after session/start.

Open the SQLite file with the standard CLI:

sqlite3 "$PWD/bub-tapes.db" "SELECT name, last_entry_id FROM tapes;"
86774b31b96845a4__0b871d5e50e7c192|9

The last_entry_id tracks the highest entry id written to each tape. Inspect the anchor rows as well:

sqlite3 "$PWD/bub-tapes.db" \
  "SELECT entry_id, anchor_name, entry_date FROM tape_entries WHERE kind = 'anchor';"
1|session/start|2026-05-15T01:27:57Z

Bub now writes the same tape entries to SQLite instead of the app’s default files.

bub-tapestore-sqlalchemy is configured with BUB_TAPESTORE_SQLALCHEMY_URL, so the same plugin can target another SQLAlchemy-supported database URL when the matching dialect and driver are installed in the environment that runs bub. Depending on the driver, you may need compatibility settings or driver-specific handling; validate the backend with this same ,tape.info flow before using it for long-lived tapes.

For a SQLite-focused store with vector-search support, see bub-tapestore-sqlite. It builds on sqlite-vec and can use embeddings for tape retrieval.

unset BUB_TAPESTORE_SQLALCHEMY_URL BUB_TAPESTORE_SQLALCHEMY_CONNECT_ARGS
rm -f "$PWD/bub-tapes.db"