busabase — the Busabase Python SDK
The official Python client for the Busabase REST API: Bases and records, Docs, files, skills, search, and the Change Requests every write goes through. One client works against Busabase Cloud and any self-hosted Busabase server.
- Typed models for every endpoint, generated from the Busabase OpenAPI document with openapi-python-client.
- A small hand-written layer on top: configuration from the same environment variables as the
Busabase CLI,
bb.<group>.<operation>(...)calls, and a typedBusabaseErrorfor every failed request instead of a silentNone. - Sync and async. Python 3.11+.
Install
pip install busabase
# or
uv add busabase
Quick start
from busabase import Busabase
bb = Busabase(api_key="bb_...") # or set BUSABASE_API_KEY
for base in bb.bases.list():
print(base.slug, base.name)
record = bb.records.get(record_id="rec_...")
print(record.head_commit.payload.to_dict()) # the record's field values
Busabase Cloud or self-hosted
| Busabase Cloud | Self-hosted server | |
|---|---|---|
base_url / BUSABASE_BASE_URL |
https://busabase.com (the default) |
your server, e.g. http://localhost:15419 |
api_key / BUSABASE_API_KEY |
required — create one in the dashboard | not needed for a local server |
space / BUSABASE_SPACE_ID |
needed when your key belongs to more than one space | usually not needed |
bb = Busabase() # everything from the environment
bb = Busabase(base_url="http://localhost:15419") # a local `busabase server`
bb = Busabase(api_key="bb_...", space="spc_...") # a specific Cloud space
base_url may include /api/v1 or not. These are the same variables the Busabase CLI and the
TypeScript SDK (busabase-sdk) read.
Cloud-only endpoints. The SDK covers the full public API. A few groups exist only on Busabase
Cloud and return 404 from a self-hosted server: system (health, meta), users.me, and
agent_tasks.
Writing: Change Requests
Every write in Busabase is a Change Request. When your key has write access it merges in the same call and you get the materialized object back; otherwise it waits for a person to review it. Check which one you got:
from busabase.generated.models import MaterializedRecord, PendingChangeRequest
result = bb.bases.create_change_request(
base_id="bas_...",
body={"fields": {"company": "Acme", "score": 7}, "message": "Add Acme — inbound lead"},
)
if isinstance(result, MaterializedRecord):
print("merged:", result.id)
elif isinstance(result, PendingChangeRequest):
print("waiting for review:", result.id)
Don't pass autoMerge — let the server decide based on your permissions.
Calling operations
Operations are grouped the way the API is (bases, records, nodes, docs, file_trees,
change_requests, search, grep, …), with snake_case names. dir(bb) and dir(bb.records)
list them.
bb.bases.list()
bb.records.list(base_id="bas_...", limit=20)
bb.nodes.get("nod_...") # path parameters can be positional
bb.docs.create(body={"slug": "notes", "name": "Notes", "body": "# Hi"})
bb.grep(body={"pattern": "acme", "sources": ["records", "nodes"]})
bb.nodes.share.list() # nested groups
await bb.records.get.asyncio(record_id="rec_...") # async
Each one calls the generated function of the same name in busabase.generated.api and returns its
parsed model (from busabase.generated.models). A request body can be a plain dict or the
generated model. For full static typing, call the generated module directly with bb.client:
from busabase.generated.api.records import records_list
page = records_list.sync(client=bb.client, base_id="bas_...")
Errors
Any HTTP status of 400 or above raises BusabaseError — from bb.… calls and from the generated
functions alike — carrying the server's error envelope:
from busabase import BusabaseError
try:
bb.records.get(record_id="rec_missing")
except BusabaseError as error:
print(error.status, error.code, error.message) # 404 NOT_FOUND Record not found: rec_missing
code is the server's semantic outcome (NOT_FOUND, FORBIDDEN, BAD_REQUEST, CONFLICT, …).
For a validation failure message spells out each field (fields.0.slug: Invalid input: …) and data
holds the raw issues.
Configuration
Busabase(
api_key=None, # BUSABASE_API_KEY
base_url=None, # BUSABASE_BASE_URL, then https://busabase.com
space=None, # BUSABASE_SPACE_ID
timeout=30.0, # seconds, or an httpx.Timeout
headers=None, # extra headers on every request
httpx_args=None, # passed to httpx.Client / httpx.AsyncClient (proxy, verify, transport…)
)
Use it as a context manager (with Busabase() as bb:) or call bb.close() to release connections.
Development
uv sync # Python 3.11+, installs the pinned generator too
uv run pytest # unit tests + generated-code drift check
BUSABASE_TEST_BASE_URL=http://127.0.0.1:15419 uv run pytest -m integration # against a local server
src/busabase/generated/ is generated — never edit it by hand. It is produced from openapi.json
by scripts/generate.py, and tests/test_generated.py fails if the two disagree:
uv run python scripts/generate.py # regenerate after openapi.json changes
uv run python scripts/generate.py --check # what the test runs
License
MIT
Metadata
Release files for busabase 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| busabase-0.1.0.tar.gz | 259.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| busabase-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 981.6 kB
Release files / busabase-0.1.0.tar.gz
| Download URL | busabase-0.1.0.tar.gz |
|---|---|
| Size | 259.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
77a8dddc1a1ced989bae7f72e2c8b2407186e0b772ba2ccc8a78b305c40db9c6
|
|
BLAKE2b-256 checksum How to use checksums |
9bd201dc4a4e11c6651c541b18e28ade6088c140f3e75838f16975ebbbef0e62
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logRelease files / busabase-0.1.0-py3-none-any.whl
| Download URL | busabase-0.1.0-py3-none-any.whl |
|---|---|
| Size | 722.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fbef31a1872d4242972a11e09ede9fedce0bb29eef9439f2c26cdbccc371594f
|
|
BLAKE2b-256 checksum How to use checksums |
b7a4cd565ec9ba67a78b2dedaa9215eaa840419ab34fc59cebf5b0f2dccfc754
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logSecurity for busabase 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for busabase-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.