Skip to main content

matilda-client

Public Python client SDK for the Matilda API — the Python port of @maincode-ai/matilda-client-sdk. OAuth login (PKCE + device flow) with managed token refresh, streaming chat with typed events, grammar-constrained structured output, robust chunked parallel file uploads, conversations, feedback, and API-key management. Async-first, minimal dependencies: httpx + stdlib only (per ADR-025 SDK-boundary rule).

Install

pip install matilda-client

Authentication

Two managed login flows (core-auth is an OAuth facade over FusionAuth; endpoints are discovered via RFC 8414 metadata). On success the client is auto-wired with a TokenManager — every request carries a managed access token, refreshed automatically (single-flight) before expiry and once on a 401:

async with MatildaClient(base_url="https://matilda.maincode.com/api") as client:
    # Headless (servers, CI, SSH): prints a URL + user code, polls until approved
    tokens = await client.auth.login_with_device_flow(client_id="matilda-code")

    # Desktop: opens the browser, receives the callback on 127.0.0.1 (RFC 8252)
    tokens = await client.auth.login_with_browser(
        client_id="matilda-code", open_browser=lambda url: webbrowser.open(url)
    )

# Persist the session across runs (0600 JSON file + cross-process refresh lock):
from matilda_client import create_file_token_store
store = create_file_token_store("~/.matilda/tokens.json")
await client.auth.login_with_device_flow(
    client_id="matilda-code", token_store=store.store, token_lock=store.lock
)

await client.auth.get_tokens()  # current TokenSet or None
await client.auth.logout()      # clears the session + detaches the provider

Or skip the flows and bring your own token:

MatildaClient(token="eyJ...")                      # static JWT
MatildaClient(get_token=my_async_token_provider)   # provider, 401→refresh→retry

The lower-level protocol is exported too (fetch_auth_server_metadata, create_pkce_pair, begin_login/complete_login for web BFF redirects, request_device_code/poll_device_token, TokenManager, StorageAdapter) — mirror of the TS SDK's auth-core/auth-node split.

matilda-key CLI

matilda-key create-api-key --name "ci-runner" [--scopes api:code,api:chat] [--expires-at 2026-12-31T23:59:59Z]

Runs a device-flow login, mints an API key, and prints the secret to stdout (pipeable) with all metadata on stderr.

Quick start

import asyncio
from matilda_client import MatildaClient

async def main():
    # Token comes from the matilda-code OAuth/PKCE flow (a FusionAuth Bearer JWT).
    async with MatildaClient(token="eyJ...", base_url="https://matilda.maincode.com/api") as client:
        response = await client.chat.create(input="G'day")
        print(response.output_text)

asyncio.run(main())

Chat

stream yields the full typed event stream; create accumulates one turn; stream_text / create_text are the text-only conveniences.

# Full typed events
async for event in client.chat.stream(input="Summarise this", file_ids=["f_..."]):
    if event.type == "response.output_text.delta":
        print(event.delta, end="")

# Just the text, raising on stream errors
text = await client.chat.create_text(input="Hello")

# Multi-turn: thread the conversation id you want to continue. Omitting it
# starts a NEW conversation, and the response does not return the auto-created
# id — so hold the id yourself (from conversations.list or your own store).
await client.chat.create(input="Hi", conversation_id="conv_...")
await client.chat.create(input="And a follow-up", conversation_id="conv_...")

Events mirror the TS SDK union: ResponseCreated, OutputTextDelta, OutputTextReplace, StatusEvent / QueuedEvent, ToolCall*, GenerationStatus, UsageEvent, CursorEvent, Truncated, Completed, ResponseError.

Structured output

Grammar-constrained generation from a JSON-schema dict or a pydantic model class (duck-typed — pydantic is not a dependency; local $ref/$defs are inlined before sending since the server's grammar compiler does not resolve pointers):

schema = {
    "type": "object",
    "properties": {"name": {"type": "string"}, "age": {"type": "integer"}},
    "required": ["name"],
}
result = await client.chat.create_object(schema, input="Extract a person from 'Ada, 36'")
print(result.object)  # {'name': 'Ada', 'age': 36} — MatildaObjectParseError on failure

Resume a detached stream

active = await client.chat.active_stream(conversation_id)
if active.get("streamId"):
    async for event in client.chat.resume(active["streamId"], last_event_id=cursor):
        ...

Files

Chunked parallel uploads (OpenAI-shaped, S3-multipart-backed), auto-selecting single-shot vs chunked per file.

result = await client.files.upload("dataset.jsonl", on_progress=lambda pct: print(f"{pct}%"))
results = await client.files.upload_many(["a.jsonl", "b.jsonl"], file_concurrency=3)
  • Small files (< chunked_threshold, default 16 MiB): single-shot POST /files/upload.
  • Large files: create session → upload parts in parallel (default 4 concurrent) with per-part exponential-backoff retry (default 3) → complete (assembles S3 object + runs scan/extract). A dropped chunk just retries.

Conversations, feedback, API keys

conversations = await client.conversations.list(limit=20)
await client.conversations.update(conv_id, title="Quarterly report")
await client.conversations.set_message_feedback(conv_id, msg_id, "positive")

await client.feedback.report(message_id=msg_id, conversation_id=conv_id, reason="inaccurate")
await client.feedback.report_bug(title="SDK crash on resume", description="...")

key = await client.api_keys.create(name="ci")   # secret returned exactly once
await client.api_keys.revoke(key_id)

api_keys hits core-auth at {origin}/api/auth/api-keys — the origin is derived from base_url, so a base_url of https://host/api works as-is.

Errors

MatildaError is the base class. Non-2xx responses raise MatildaAPIError (QuotaExceededError on 429 with a structured quota body). Stream errors are ResponseError events on stream/create, and raise as MatildaStreamError on the text/object paths; SafetyReplaceError fires there when the server replaces in-flight output. Uploads raise UploadError after retries are exhausted.

If config.get_token (an async token provider) is configured, a 401 triggers one automatic retry with a force-refreshed token.

Configuration

Parameter Default Notes
chunk_size 8 MiB Part size (server is authoritative)
chunked_threshold 16 MiB Files ≥ this use chunked
part_concurrency 4 Parallel parts per file
max_part_retries 3 Per-part retry count
timeout 120 s httpx request timeout
api_version 2026-06-23 Sent as X-Matilda-API-Version

Development

python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest tests   # includes a contract-drift guard against @matilda/contracts
.venv/bin/ruff check src tests

Metadata

Release files for matilda-client 0.4.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 matilda-client 0.4.0
File Size Uploaded Provenance Actions
matilda_client-0.4.0.tar.gz 44.1 kB With provenance Details for matilda_client-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for matilda-client 0.4.0
File Interpreter ABI Platform Actions
matilda_client-0.4.0-py3-none-any.whl Python 3 none any Details for matilda_client-0.4.0-py3-none-any.whl

Total release size: 93.5 kB

Release files / matilda_client-0.4.0.tar.gz

Download URL matilda_client-0.4.0.tar.gz
Size 44.1 kB
Tags Source
SHA-256 checksum
How to use checksums
8ac442a8681cd222cfaf9e50c5128a81a08cd73477d1335d35b40948178fb6c0
BLAKE2b-256 checksum
How to use checksums
03170b6d0d657444e6c85cf5673fb5b62595762cb739bd911cc867c0ea382855
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 16, 2026.

Transparency log

Release files / matilda_client-0.4.0-py3-none-any.whl

Download URL matilda_client-0.4.0-py3-none-any.whl
Size 49.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
befb6f19149b7b2c942b4573087104bd49cf5bb98c3f6d54a33cabc3e37a9c8d
BLAKE2b-256 checksum
How to use checksums
fc3e9cfd981160ae6c9e352ca62613b0397f508a4394767d0585c3e71ddda724
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

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 16, 2026.

Transparency log

Security for matilda-client 0.4.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.

Select from 2 files

Attestation for matilda_client-0.4.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 16, 2026.

Transparency log

A 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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files Full provenance

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