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.
Before you begin
Section titled “Before you begin”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
sqlite3CLI for the optional database check.
1. Install the plugin
Section titled “1. Install the plugin”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
2. Point Bub at a local SQLite database
Section titled “2. Point Bub at a local SQLite database”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.
3. Run a turn
Section titled “3. Run a turn”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.
4. Inspect the database
Section titled “4. Inspect the database”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.
5. Extend the backend
Section titled “5. Extend the backend”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.
Clean up
Section titled “Clean up”unset BUB_TAPESTORE_SQLALCHEMY_URL BUB_TAPESTORE_SQLALCHEMY_CONNECT_ARGS
rm -f "$PWD/bub-tapes.db"
Next steps
Section titled “Next steps”- Observe Bub with tapes and Phoenix: pair the durable tape with GenAI telemetry.
- Tape and context: what Bub records and how context is rebuilt.
- Plugins: the plugin contract
bub-tapestore-sqlalchemyfollows.