imbi-assistant
HTTP backend for the AI assistant embedded in the Imbi DevOps service management platform. It manages chat conversations and streams responses from Anthropic's Claude over Server-Sent Events, giving Claude live access to Imbi data and actions through tools.
How It Works
The service exposes a small REST API for conversation CRUD plus a streaming chat endpoint. When a user sends a message, the assistant:
- Loads the conversation history from the graph and replays it to Claude.
- Builds the tool set (see below) and a per-user system prompt.
- Streams Claude's response as SSE events, running any tool calls in a loop
(up to
max_tool_rounds) until Claude stops requesting tools. - Persists each assistant/tool-result round to the graph, and generates a short title for the first exchange.
The assistant's tools come from four sources, combined into a single list on every turn:
- Imbi API (OpenAPI). At startup an in-process
FastMCP server is built from the Imbi
API's
openapi.json(auth/MFA/status/thumbnail routes excluded). The caller's bearer token is forwarded per request so API calls run with the user's permissions. - External MCP servers.
MCPServernodes configured in the graph are connected over streamable HTTP; their tools are namespaced (mcp_<prefix>_…) and merged in. Supports static-header and OAuth client-credentials auth, with secrets decrypted at connect time. A bad server is logged and skipped, never fatal. - Client-side tools.
navigate_toandrefresh_datadon't run on the server — they emit aclient_actionSSE event the UI executes (browser navigation, cache invalidation after a mutation). - Refresh tool.
refresh_openapi_specre-fetches the OpenAPI spec and reconnects every external MCP server mid-conversation, so newly deployed tools become available without a restart.
Conversations and messages are stored as nodes in the Apache AGE graph (via
imbi-common's Graph client) and scoped to the authenticated user.
Authentication
Every assistant endpoint requires a bearer JWT access token. Tokens are
verified locally using the shared IMBI_AUTH_JWT_SECRET; the subject is
looked up as a User node and its permissions resolved from the graph. The
same token is forwarded to the Imbi API when executing OpenAPI-backed tools.
API
All routes are served under the path component of IMBI_ASSISTANT_URL
(e.g. /assistant), so they match the ingress prefix.
| Method | Path | Description |
|---|---|---|
POST |
/conversations |
Create a conversation |
GET |
/conversations |
List the user's conversations |
GET |
/conversations/{id} |
Get a conversation with its messages |
PATCH |
/conversations/{id} |
Rename or archive a conversation |
DELETE |
/conversations/{id} |
Delete a conversation and its messages |
POST |
/conversations/{id}/messages |
Send a message; streams the reply as SSE |
GET |
/status |
Operational status (unprefixed) |
Requirements
- Python 3.14+
- A running imbi-api instance
- An Anthropic API key
- PostgreSQL with Apache AGE (shared with the rest of the Imbi stack)
Quick Start
This project uses uv for project management and moon as its task runner. Install moon before contributing.
moon run root:setup # Sync dependencies and install pre-commit hooks
moon run root:services # Boot backing services (writes .env.test)
uv run --env-file .env.test imbi-assistant serve # Run the service in the foreground
moon run assistant:test # Run the test suite
moon run assistant:lint assistant:typecheck assistant:format # ruff + basedpyright + format check
Run moon query tasks for all available commands.
Configuration
Settings are read from the environment (prefix IMBI_ASSISTANT_). The service
auto-enables when ANTHROPIC_API_KEY is present.
| Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY |
(none) | Anthropic API key; enables the assistant when set |
IMBI_ASSISTANT_ENABLED |
false |
Force-enable/disable independent of the API key |
IMBI_ASSISTANT_MODEL |
claude-sonnet-4-6 |
Default model for new conversations |
IMBI_ASSISTANT_MAX_TOKENS |
16384 |
Max output tokens per response |
IMBI_ASSISTANT_MAX_TOOL_ROUNDS |
10 |
Max tool-use rounds per message |
IMBI_ASSISTANT_MAX_CONVERSATION_TURNS |
100 |
Max messages before a conversation is closed |
IMBI_ASSISTANT_SYSTEM_PROMPT |
(bundled template) | Override for the system prompt template |
IMBI_ASSISTANT_URL |
(none) | Public URL; its path becomes the route prefix |
IMBI_INTERNAL_API_URL |
http://localhost:8000 |
In-cluster address of the Imbi API for service-to-service calls |
IMBI_UI_URL |
(none) | Public base URL of the Imbi UI, used to build deep links |
IMBI_INTERNAL_UI_URL |
(falls back to IMBI_UI_URL) |
In-cluster UI address for fetching llms.txt (e.g. the Caddy frontend) |
IMBI_AUTH_JWT_SECRET |
(required) | Shared secret for verifying access tokens (via imbi-common) |
POSTGRES_URL |
(required) | DSN for the AGE graph (via imbi-common) |
Docker
docker build -t imbi-assistant .
docker run -p 8002:8002 \
-e ANTHROPIC_API_KEY=sk-ant-... \
-e IMBI_INTERNAL_API_URL=http://imbi-api:8000 \
imbi-assistant
The image runs imbi-assistant serve --host 0.0.0.0 --port 8002.
Code Formatting
Formatting is handled by automated tooling and is the sole authority on style:
Ruff for Python, Tombi for TOML, run via pre-commit hooks. Don't format
manually — use uv run pre-commit run --all-files (or --files <paths>) and moon run assistant:lint.
Release files for imbi-assistant 2.29.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| imbi_assistant-2.29.1.tar.gz | 49.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| imbi_assistant-2.29.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 87.0 kB
Release files / imbi_assistant-2.29.1.tar.gz
| Download URL | imbi_assistant-2.29.1.tar.gz |
|---|---|
| Size | 49.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4252cf2b37fb219896c00778b3014c445907546f36233c0c8e25019a010045c5
|
|
BLAKE2b-256 checksum How to use checksums |
40eafc2330d55a9436f41165fdc396b19fc30e3900cbb3321e9253cd5f58683d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 22, 2026.
Transparency logRelease files / imbi_assistant-2.29.1-py3-none-any.whl
| Download URL | imbi_assistant-2.29.1-py3-none-any.whl |
|---|---|
| Size | 37.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
06a9a329d99f8ecf51fa1641d7e7a1499a889b4512ac8b709952d9b2fa8ed1e0
|
|
BLAKE2b-256 checksum How to use checksums |
0eabcfa06a928e0e7f4895516e4994f7fe04337b656085eb395f99b672e8527b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 22, 2026.
Transparency log