Add your description here
Project description
Maur 🐜
Inspired by Strip's Minions. Maur (Norwegian for "ants") is an autonomous coding agent that integrates into your Python projects. It receives tasks from various sources — production error alerts, Slack, Linear issues, or direct API calls — clones your repo, runs an AI coding agent (OpenCode), and opens a pull/merge request with the fix.
How it works
- A task arrives via webhook or direct API call
- The API stores the task and publishes it to a message queue
- A worker picks up the task, clones your repo into a temporary workspace
- OpenCode runs against the cloned repo using your configured LLM
- If changes are made, they are committed and pushed to a new branch (
maur/<task-id>) - A pull request (GitHub) or merge request (GitLab) is opened automatically
Architecture
[Trigger source] [maur_api] [maur_code_subscriber]
Linear webhook ---> FastAPI app ---> Worker (OpenCode)
Exception alert stores task clones repo
Manual POST /tasks publishes msg runs agent
opens PR/MR
The two components are deployed separately via takk:
maur_api— lightweight FastAPI service that authenticates requests, persists tasks, and enqueues workmaur_code_subscriber— NATS subscriber that processes tasks one at a time using OpenCode
Prerequisites
- Python ≥ 3.10
takkfor infrastructure management- A NATS server (provisioned by
takk) - A PostgreSQL or MySQL database (provisioned by
takk) - An OpenAI-compatible LLM API (e.g. OpenRouter, a local Ollama instance, or any provider with an OpenAI-compatible endpoint.
takkdefault to using Ollama unless you overwrite the env vars.) - A GitHub or GitLab repository with a token that has push and PR/MR creation permissions
Installation
uv add maur
Basic usage
1. Add the infrastructure
Add both components to your project.py file:
from maur.components import maur_api, maur_code_subscriber
project = Project(
name="your-project",
# The API that authenticates and enqueues tasks
maur_api=maur_api(),
# The worker that clones the repo, runs OpenCode, and opens a PR/MR
# Pass secrets for any environment variables your target repo needs at build time
maur_coder=maur_code_subscriber(secrets=[...]),
)
2. Configure secrets
Run takk dotenv to regenerate your .env file, then fill in the required values:
| Variable | Required | Description |
|---|---|---|
DB_URI |
No | PostgreSQL (postgresql+asyncpg://...) or MySQL (mysql+aiomysql://...) connection URI |
NATS_URI |
No | NATS (nats://...) |
MAUR_BEARER_TOKEN |
Yes | Secret token used to authenticate API requests |
MAUR_LLM_TOKEN |
No | API key for your LLM provider |
MAUR_LLM_API |
No | Base URL of your OpenAI-compatible LLM API |
MAUR_LLM_MODEL |
No | Model to use (default: qwen3.5:4b) |
GITHUB_REPO_URL |
Yes* | HTTPS URL of the GitHub repo to clone and open PRs on |
GITHUB_TOKEN |
Yes* | GitHub personal access token with repo scope |
GITHUB_API_URL |
No | GitHub API base URL (default: https://api.github.com) |
GITLAB_REPO_URL |
Yes* | HTTPS URL of the GitLab repo |
GITLAB_TOKEN |
Yes* | GitLab personal access token with api scope |
GITLAB_URL |
No | GitLab instance URL (default: https://gitlab.com) |
* Provide either the GitHub or GitLab set of variables. GitLab takes precedence if both are set.
3. Start the system
takk up
Both the API and worker containers will be built and started.
API reference
All endpoints (except /health) require a Bearer token in the Authorization header matching MAUR_BEARER_TOKEN.
POST /tasks — Manual task
Send any arbitrary prompt to the agent.
curl -X POST http://localhost:8000/tasks \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Refactor the payment module to use the new Stripe SDK",
"source_id": "unique-identifier-for-dedup",
"repo_branch": "main"
}'
POST /webhooks/exception — Exception alert
Send a production error for the agent to fix. fingerprint is used for deduplication — tasks with the same fingerprint that are already pending or in progress are rejected.
curl -X POST http://localhost:8000/webhooks/exception \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"fingerprint": "KeyError-user-profile-views-42",
"title": "KeyError: '\''email'\'' in user_profile view",
"description": "Traceback (most recent call last):\n ...",
"repo_branch": "main",
"extra": {"environment": "production", "user_id": 123}
}'
POST /webhooks/linear — Linear webhook
Configure a Linear webhook to send issue events here. Maur extracts the issue title, description, and repository URL (must be attached to the issue) and opens a PR with the fix.
Set the webhook URL to: https://<your-api-host>/webhooks/linear
Optionally set LINEAR_WEBHOOK_SECRET in your environment to verify webhook signatures.
GET /tasks — List tasks
Returns the 50 most recent tasks.
GET /tasks/{task_id} — Get task
Returns the status and result of a specific task.
GET /health
Returns "ok". Used for health checks.
Customisation
Changing the LLM model
Set MAUR_LLM_MODEL to any model available through your MAUR_LLM_API provider. The worker uses OpenCode with an OpenAI-compatible provider, so any model exposed via that protocol works.
MAUR_LLM_MODEL=devstral-2-123b-instruct-2512
Adjusting worker compute resources
The default worker is allocated 3 GB of memory. Override this via the compute argument:
from takk.models import Compute
from maur.components import maur_code_subscriber
maur_coder=maur_code_subscriber(
compute=Compute(mb_memory_limit=1024 * 8) # 8 GB
)
Passing additional secrets to the worker
If your target repository requires environment variables at build or runtime (e.g. private package indexes), pass them through secrets:
from maur.components import maur_code_subscriber
from my_project.settings import MyPrivateRegistrySettings
maur_coder=maur_code_subscriber(
secrets=[MyPrivateRegistrySettings, ...]
)
Development
# Install dependencies
uv sync --all-groups
# Lint
uv run ruff check .
# Type check
uv run ty check
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file maur-0.1.0.tar.gz.
File metadata
- Download URL: maur-0.1.0.tar.gz
- Upload date:
- Size: 12.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe37add72510260495b0124f126b3d4640f720ddea39392faffd51a00bbb17f8
|
|
| MD5 |
4b53f2622e104bbdaf30310a5592f6df
|
|
| BLAKE2b-256 |
a16daae38ec0163e0d3dd63651aec79c23d7a708f54539e00c5dce8efd90ddab
|
File details
Details for the file maur-0.1.0-py3-none-any.whl.
File metadata
- Download URL: maur-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b40a160d89e5b77d78d0de2c847cffc9325a95b31ff0c4d3cbb5d0942f9fbd4
|
|
| MD5 |
7fbc3db6e30259385cfc668a4ca6ae65
|
|
| BLAKE2b-256 |
423fb5e897f77524487f2b5cc0792c1aa63e66929061db0687f27f45347b2055
|