Skip to main content

Cerebral Python SDK

Python SDK for the Cerebral data versioning API.

Installation

pip install cerebral-sdk

Or with uv:

uv add cerebral-sdk

Quick Start

Using environment variables (simplest)

export CEREBRAL_API_KEY="your-api-key"
import cerebral

repo = cerebral.repository("my-org/my-repo")
print(repo.description)  # lazy-loaded on first access

with repo.session() as session:
    session.objects.put("data/example.csv", b"col1,col2\na,b\n")
    session.commit("added example csv")

Explicit configuration

import cerebral

cerebral.configure(api_key="your-api-key", endpoint_url="https://custom.endpoint")
repo = cerebral.repository("my-org/my-repo")

Explicit client (most flexible)

from cerebral import Client

with Client(api_key="your-api-key") as client:
    repo = client.repository("my-org/my-repo")
    with repo.session() as session:
        session.objects.put("data/file.csv", b"content")
        session.commit("update data")

Configuration

Option Environment Variable Default
api_key CEREBRAL_API_KEY required
endpoint_url CEREBRAL_ENDPOINT_URL https://cerebral.storage

Resolution order: explicit parameter > environment variable > default.

A missing API key is not an error at construction time; a ConfigurationError is raised when the first request is made.

Usage

Repositories

repo = cerebral.repository("my-org/my-repo")

# Lazy-loaded properties
print(repo.id, repo.description, repo.visibility)

# Update
repo.update(description="New description", visibility="public")

# Delete
repo.delete()

Sessions

Sessions are the primary way to read and write objects. They act like transactions: stage changes, then commit or rollback.

# Context manager (recommended) — rolls back on error
with repo.session() as session:
    objects = session.objects.list(prefix="data/", delimiter="/")
    session.objects.put("data/report.csv", b"content")
    session.commit("update CSV files")

# Explicit control
session = repo.session()
print(session.session_id)
session.objects.put("data/file.csv", b"content")
session.commit("modifying data in parallel")
# or: session.rollback()

Attaching to an Existing Session

Resume a session from another thread, process, or machine:

# In another thread/process/machine:
session = repo.attach(session_id)
session.objects.put("data/file2.csv", b"more content")
session.commit("finishing work")

Objects

with repo.session() as session:
    # Upload
    session.objects.put("data/file.csv", b"content")

    # Download (streaming)
    with session.objects.get("data/file.csv") as f:
        data = f.read()

    # Read a specific byte range (e.g., first 1 KB)
    with session.objects.get("data/file.parquet", byte_range=(0, 1023)) as f:
        header = f.read()

    # Stream large objects without caching
    with session.objects.get("data/large.bin", cache=False) as f:
        for chunk in f.iter_bytes(chunk_size=8192):
            process(chunk)

    # List (auto-paginating, with directory grouping)
    for entry in session.objects.list(prefix="data/", delimiter="/"):
        print(entry.path, entry.type)  # type is "object" or "prefix"

    # Check metadata
    meta = session.objects.head("data/file.csv")
    print(meta.etag, meta.content_type, meta.content_length)

    # Delete
    session.objects.delete("data/file.csv")

    session.commit("object operations")

Uncommitted Changes

session = repo.session()
session.objects.put("data/new.csv", b"content")

for entry in session.uncommitted():
    print(entry.path)

Timeline (Commit History)

for commit in repo.timeline():
    print(commit.id, commit.message)

    # View changes introduced by this commit
    for change in commit.diff():
        print(f"object {change.path} was {change.status} in this commit!")

Organizations

orgs = cerebral.Client(api_key="key").organizations

# Create
org = orgs.create("my-org", "My Organization")

# List
for org in orgs.list():
    print(org.name)

# Members
for member in orgs.members("my-org").list():
    print(member.username, member.role)

orgs.members("my-org").add(user_id="user-uuid", role="member")

Agents

Manage agents and their API keys using the fluent organization resource:

org = cerebral.organization("my-org")

# Create an agent
agent = org.agents.create("my-agent", description="CI bot", metadata={"env": "prod"})
print(agent.name, agent.id)

# List agents
for agent in org.agents.list():
    print(agent.name)

# Get a specific agent
agent = org.agents.get("my-agent")

# Update an agent
agent = org.agents.update("my-agent", description="Updated description")

# Delete an agent
org.agents.delete("my-agent")

Agent API Keys

agent = org.agents.get("my-agent")

# Create a key (token is only shown once)
created = agent.api_keys.create("dev-key")
print(created.token)  # cak-... full token

# List keys
for key in agent.api_keys.list():
    print(key.name, key.token_hint)

# Get by ID and revoke a key
key = agent.api_keys.get(key_id)
key.revoke()

Organization Sub-resources

The organization resource also provides access to repositories, members, groups, policies, and connectors:

org = cerebral.organization("my-org")

for repo in org.repositories.list():
    print(repo.name)

for member in org.members.list():
    print(member.username, member.role)

Groups

groups = client.organizations.groups("my-org")

group = groups.create("engineers", description="Engineering team")
detail = groups.get(group.id)  # includes members and attachments

groups.add_member(group.id, "user", "user-uuid")
groups.remove_member(group.id, "user", "user-uuid")

Policies

policies = client.organizations.policies("my-org")

# Create and validate
result = policies.validate("package cerebral.authz\ndefault allow = true")
policy = policies.create("allow-all", rego="...", description="Allow everything")

# Attach/detach
policies.attach(policy.id, "group", "group-uuid")
policies.detach(policy.id, "group", "group-uuid")

# Effective policies for a user
for ep in policies.effective_policies("user-uuid"):
    print(ep.policy_name, ep.source)

Connectors and Imports

# Org-level connectors
connectors = client.organizations.connectors("my-org")
conn = connectors.create("my-s3", "s3", {"bucket": "my-bucket", "region": "us-east-1"})

# Attach to repo
repo.connectors.attach(conn.id)

# Import
job_id = repo.imports.start(
    connector_id=conn.id,
    source_path="s3://my-bucket/data/",
    destination_path="imported/",
)
status = repo.imports.status(job_id)
print(status.status, status.objects_imported)

Error Handling

All SDK exceptions inherit from CerebralError:

CerebralError                        # base for all SDK errors
+-- ConfigurationError               # missing API key, bad endpoint
+-- TransportError                   # network failures, DNS, timeouts
+-- SerializationError               # invalid JSON in response
+-- APIError                         # base for HTTP API errors
    +-- BadRequestError              # 400
    +-- AuthenticationError          # 401
    +-- ForbiddenError               # 403
    +-- NotFoundError                # 404
    +-- ConflictError                # 409
    +-- GoneError                    # 410
    +-- PreconditionFailedError      # 412
    +-- LockedError                  # 423
    +-- ServerError                  # 5xx

APIError includes status_code, message, code, request_id, method, url, and response_text for debugging.

from cerebral import NotFoundError, CerebralError

try:
    with repo.session() as session:
        with session.objects.get("nonexistent") as f:
            f.read()
except NotFoundError as e:
    print(f"Not found: {e.message} (request_id={e.request_id})")
except CerebralError as e:
    print(f"SDK error: {e}")

Large Object Handling

By default, objects.get() caches the full object in memory on .read(). For large objects, disable caching and stream:

with repo.session() as session:
    with session.objects.get("large-file.bin", cache=False) as f:
        for chunk in f.iter_bytes(chunk_size=1024 * 1024):
            output.write(chunk)

Byte Range Requests

Use byte_range to read only a portion of an object without downloading the full content. This is useful for reading file headers, tailing logs, or formats like Parquet that support random access.

# Read the first 4 bytes (e.g., a magic number)
with repo.objects.get("data/file.parquet", byte_range=(0, 3)) as f:
    magic = f.read()

# Read from offset 1024 to end of file
with repo.objects.get("data/file.parquet", byte_range=(1024, None)) as f:
    tail = f.read()

The reader exposes the content_range property with the server's Content-Range header value (e.g., "bytes 0-3/49152"):

with repo.objects.get("data/file.parquet", byte_range=(0, 1023)) as f:
    data = f.read()
    print(f.content_range)   # "bytes 0-1023/49152"
    print(f.content_length)  # 1024

MCP Server

The SDK includes an MCP server that exposes Cerebral operations as tools for AI agents. The API key must be an agent key (prefix cak-).

Running

# Via uvx
uvx --from cerebral-sdk cerebral-mcp

# Or as a Python module
CEREBRAL_API_KEY=cak-... python -m cerebral.mcp

Available Tools

Tool Description
create_session Create a new editing session on a repository.
list_objects List objects and prefixes with metadata (size, content type, etc.).
head_object Get an object's size and content type without downloading it.
get_object Download an object's content (UTF-8 text or base64-encoded binary).
put_object Upload an object (UTF-8 text or base64-encoded binary).
delete_object Delete an object from a session.
commit_session Commit a session (returns approval URL if review is required).
close_session Roll back and close a session.

Configuration

The server reads CEREBRAL_API_KEY from the environment on every tool call. Only agent keys (cak- prefix) are accepted.

Documentation

Full documentation is available at https://docs.cerebral.storage/python-sdk/.

Development

# Install dev dependencies
uv sync --all-extras

# Run tests
uv run pytest

# Lint and format
uv run ruff check src/ tests/
uv run ruff format src/ tests/

# Type check
uv run mypy src/cerebral/

# Build
uv build

License

Apache 2.0

Metadata

Release files for cerebral-sdk 0.8.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cerebral-sdk 0.8.0
File Size Uploaded
cerebral_sdk-0.8.0.tar.gz 197.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cerebral-sdk 0.8.0
File Interpreter ABI Platform
cerebral_sdk-0.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 249.3 kB

Release files / cerebral_sdk-0.8.0.tar.gz

Download URL cerebral_sdk-0.8.0.tar.gz
Size 197.6 kB
Tags Source
SHA-256 checksum
How to use checksums
ef56be2d21cf45dae69c3c29b4b7d119f4d9fac03b5436c7bf8c9a445ab191bd
BLAKE2b-256 checksum
How to use checksums
8bd0f48557a6dd11d111917fa5579ae48807360d066ac67e02ab7823b18ce95c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.3 {"installer":{"name":"uv","version":"0.10.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / cerebral_sdk-0.8.0-py3-none-any.whl

Download URL cerebral_sdk-0.8.0-py3-none-any.whl
Size 51.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
576c53bb93f3ef75a42dfe1b1be27b948b6bb891661ca9e306c75897e9047965
BLAKE2b-256 checksum
How to use checksums
786bb99ab687aa3efa6b4d7cc9d61ea2400da63a2c9b4f4a82a5b9f6c598ab9b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.3 {"installer":{"name":"uv","version":"0.10.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.8.0 This release

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page