Skip to main content

Modus

Modus Python SDK

PyPI Python versions License: MIT

Official Python client for Modus — your organization's context layer for AI.

What is Modus?

Modus is your organization's context layer: it connects assistants to curated knowledge about your data, systems, and workflows so answers use org-specific context instead of generic guesses.

  • Modus — your org-wide assistant (same capability as the Modus home page)
  • Scopes — published assistants you chat with, each with its own context and tools
  • Workflows — automations that run on a schedule or trigger
  • Context items — curated knowledge Modus composes at runtime when answering

Two clients in one package

modus.Modus() is what most people need. Use it to chat with Modus, run scopes, browse context, upload ingested data, and inspect workflow runs — the same things you do in the Modus app day to day.

modus.management.ModusManagement() is for org setup: create, update, and deploy scopes, workflows, and context — the CRUD operations you would use in the Modus UI as an admin.

If you are getting started, use Modus() only. Reach for ModusManagement() when you are automating configuration.

Async variants: AsyncModus and AsyncModusManagement.

Installation

pip install modus-sdk

Requires Python 3.10+.

Getting started

import modus

# Reads MODUS_API_KEY env var, or pass api_key= explicitly
client = modus.Modus()

for scope in client.scopes.list():
    print(scope.name, scope.status)

scope = client.scopes.get("revenue-analysis")
print(scope.name, scope.description)

for item in client.context.items.list():
    print(item.uid, item.context_type, modus.context_item_label(item))

Authentication

Create an API token in the Modus app (Settings → API Tokens on your Modus home page). Prefer an environment variable over hardcoding keys in source:

export MODUS_API_KEY=modus_xxx
client = modus.Modus(api_key="modus_xxx")

Using Modus

Modus vs scopes

Surface SDK Use when
Modus (org-wide) client.modus.* Full-environment assistant — same as the Modus home page
Scope client.scopes.* A specific published scope and its configured context/tools

Use client.modus.chat() for native Modus — not scopes.chat(0) or any other scope id shortcut.

Org-wide Modus assistant

MODEL = "claude-sonnet-5"

result = client.modus.chat("What were our top revenue drivers last quarter?", model=MODEL)
print(result.content, result.thread_id)

follow_up = client.modus.chat(
    "Break that down by region.",
    model=MODEL,
    thread_id=result.thread_id,
)
print(follow_up.content)

with client.modus.chat_stream("Summarize this week", model=MODEL) as stream:
    for chunk in stream.text_stream:
        print(chunk, end="")

ctx = client.modus.get_context("What tables describe customer churn?", limit=10)
print(ctx.original_count, ctx.session_id)

for row in client.modus.conversations.list(kind="modus", page_size=10):
    print(row.thread_id, row.first_message)

Scopes

MODEL = "claude-sonnet-5"

result = client.scopes.chat(scope_id, "Hello", model=MODEL)
print(result.content, result.thread_id)

with client.scopes.chat_stream(scope_id, "Hi", model=MODEL) as stream:
    for chunk in stream.text_stream:
        print(chunk, end="")

Context

for item in client.context.items.list():
    print(item.uid, modus.context_item_label(item))

Connections

list_selections returns one page of the units a scope can select on a connection (ConnectionSelection: path, object_type, display_name); iter_selections follows every page:

connection = client.connections.find(name="GitHub")  # None when no connection has that name
if connection is not None:
    for unit in client.connections.iter_selections(connection.id):
        print(unit.object_type, unit.display_name, unit.path)

Ingested data

Upload the exact SQL request and CSV response through the regular Modus client. The organization comes from the configured MODUS_API_KEY:

import modus

client = modus.Modus()  # reads MODUS_API_KEY
stored = client.ingested_data.upload(
    integration_type="postgresql",
    request={"type": "sql", "query": "SELECT id, name FROM customers"},
    response={"format": "csv", "content": "id,name\n1,Ada\n"},
)
print(stored.checksum)

The token must include the context:write permission.

Workflows

workflow = client.workflows.get(workflow_id)
for run in client.workflows.runs.list(workflow_id, page_size=20):
    print(run.id, run.status)

Workflow chat is not on the public PAT surface. Use client.modus.chat() for org-wide conversation or client.scopes.chat() for a published scope.

Managing your org

from modus.management import ModusManagement

mgmt = ModusManagement()  # reads MODUS_API_KEY
scope = mgmt.scopes.create(name="Analyst", model="claude-sonnet-5")
mgmt.scopes.deploy(scope.id)

# Create returns context_item_id (also available as .uid); list/get use .uid
note = mgmt.context.create_note("Title", "Body")
related_note = mgmt.context.create_note("Related title", "Related body")
print(note.context_item_id, note.uid)  # same UUID

upload = mgmt.context.files.upload("report.pdf")
print(upload.upload_id, upload.status)

result = mgmt.context.files.upload_dir("./reports", folder_path="finance")
print(len(result.uploaded), len(result.failed))
file = mgmt.context.files.get(upload.upload_id)
files = mgmt.context.files.list()
print(file.status, len(files.items))

root_folders = mgmt.context.items.list(
    connection_ids=["files"],
    context_type="file_folder_metadata",
    parent_uids=[],
)
print(len(root_folders.items))

moved = mgmt.context.items.move(
    root_folders.items[0].uid,
    destination_folder_uid=None,
)
print(moved.moved_items)

upserted = mgmt.context.custom_items.create_relations([
    {
        "from_uid": note.uid,
        "to_uid": related_note.uid,
        "relation_type": "depends_on",
    }
])
print(upserted)

Requires a token with write access to scopes, workflows, and context (same as the Modus UI). Custom context items and relations need the context:write permission.

Pagination

List endpoints return a Page[T]. Iterate the current page, or use .auto_paging_iter() for all pages:

for scope in client.scopes.list().auto_paging_iter():
    print(scope.name)

client.modus.conversations.list() accepts kind="modus", "skills", or "all" (default).

Async

import asyncio
import modus

async def main():
    async with modus.AsyncModus() as client:
        result = await client.modus.chat("Hello", model="claude-sonnet-5")
        print(result.content)

        async for scope in client.scopes.list().auto_paging_iter():
            print(scope.name)

asyncio.run(main())

Error handling

try:
    scope = client.scopes.get(999)
except modus.NotFoundError:
    print("Scope not found")
except modus.AuthenticationError:
    print("Check your MODUS_API_KEY")
except modus.RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except modus.ModusError as e:
    print(f"API error {e.status_code}: {e.message}")

Examples

Runnable scripts ship with the package:

  • examples/scripts/quickstart.py — list scopes and context (Modus)
  • examples/scripts/modus_chat.py — buffered and streaming Modus chat, context compose, conversations
  • examples/scripts/chat.py — buffered scope chat with thread follow-up
  • examples/scripts/manage_skill.py — create and deploy a scope (ModusManagement, --write optional)

Optional Streamlit demo: examples/apps/modus_skill_chat/ (streaming vs buffered scope chat side by side).

Docs

Full guides: docs.getmodus.com/guides/sdk (Python page: sdk-python).

Metadata

Release files for modus-sdk 0.9.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 modus-sdk 0.9.0
File Size Uploaded Provenance
modus_sdk-0.9.0.tar.gz 242.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for modus-sdk 0.9.0
File Interpreter ABI Platform
modus_sdk-0.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 439.6 kB

Release files / modus_sdk-0.9.0.tar.gz

Download URL modus_sdk-0.9.0.tar.gz
Size 242.4 kB
Tags Source
SHA-256 checksum
How to use checksums
dfcba5598c0f1b59ce8d1e78b765ad5be9c8b8c4064b1fd1b718f6696ea9d9c6
BLAKE2b-256 checksum
How to use checksums
2152ebf1060ea1196d4feb2020540577af0371deac60e1d42120be231f6bdfc5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / modus_sdk-0.9.0-py3-none-any.whl

Download URL modus_sdk-0.9.0-py3-none-any.whl
Size 197.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8baff54c9b800ed5463a6022cbba7ccad7ce6259ab070c5303f4d9c3fea5efd5
BLAKE2b-256 checksum
How to use checksums
6456b136ed20e8ea863de4d0ed93a00f92d43bfccf0aa60b4e33984656983e91
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for modus-sdk 0.9.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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

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