Skip to main content

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

  1. A task arrives via webhook or direct API call
  2. The API stores the task and publishes it to a message queue
  3. A worker picks up the task, clones your repo into a temporary workspace
  4. OpenCode runs against the cloned repo using your configured LLM
  5. If changes are made, they are committed and pushed to a new branch (maur/<task-id>)
  6. 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 work
  • maur_code_subscriber — NATS subscriber that processes tasks one at a time using OpenCode

Prerequisites

  • Python ≥ 3.10
  • takk for 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. takk default 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

maur-0.1.0.tar.gz (12.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

maur-0.1.0-py3-none-any.whl (16.1 kB view details)

Uploaded Python 3

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

Hashes for maur-0.1.0.tar.gz
Algorithm Hash digest
SHA256 fe37add72510260495b0124f126b3d4640f720ddea39392faffd51a00bbb17f8
MD5 4b53f2622e104bbdaf30310a5592f6df
BLAKE2b-256 a16daae38ec0163e0d3dd63651aec79c23d7a708f54539e00c5dce8efd90ddab

See more details on using hashes here.

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

Hashes for maur-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4b40a160d89e5b77d78d0de2c847cffc9325a95b31ff0c4d3cbb5d0942f9fbd4
MD5 7fbc3db6e30259385cfc668a4ca6ae65
BLAKE2b-256 423fb5e897f77524487f2b5cc0792c1aa63e66929061db0687f27f45347b2055

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page