The Python framework for building AI-native applications in production.
Project description
Ajolopy
The Python framework for building AI-native applications in production.
Documentation · Quickstart · Tutorial · Reference · Recipes
What Rails was for database-backed web apps and what NestJS is for enterprise Node services: the default choice when what you're building has LLMs, agents, tools, prompts, evals, streaming, and MCP as core ingredients — not as an addon.
Ajolopy does not compete with FastAPI or LangChain. It competes for the complete AI-native application framework category, which was empty in Python before v0.1.
Install
pip install ajolopy # or: uv pip install ajolopy
Requires Python 3.14+. Optional extras documented under Install:
otel, mcp, redis, postgres, mongo, qdrant, pgvector.
Why Python 3.14+
- PEP 649 — deferred evaluation of annotations is native, so
from __future__ import annotationsis forbidden in this codebase (it would hide real typing errors at runtime). - Pyright strict pays off — runtime introspection of type hints
(
inspect.get_annotations) works without the lazy-eval workarounds older Pythons need. - DI by type-hints — Ajolopy resolves
@Injectableproviders via real annotation objects; PEP 649 makes that cheap and correct. - Modern stdlib —
asyncio.TaskGroup, structural pattern matching, and the new error-message machinery are assumed everywhere.
The killer demo
Twelve real lines (plus imports). Each token has a job — see the Step 1 tutorial for the line-by-line breakdown.
from typing import Annotated
from pydantic import BaseModel
from ajolopy import Agent, Stream, Tool
from ajolopy.http import Body
class ChatRequest(BaseModel):
message: str
@Agent(
model="claude-opus-4-7",
system="You are Acme Support. Be concise, friendly, and accurate.",
fallback="claude-haiku-4-5",
)
class Support:
@Tool
async def lookup_order(self, order_id: str) -> dict[str, str]:
"""Look up an order's current state by id."""
return {"order_id": order_id, "status": "in_transit", "eta": "tomorrow"}
@Stream("/chat")
async def respond(self, body: Annotated[ChatRequest, Body()]):
async for chunk in self.stream(body.message):
yield chunk
Run it:
ajolopy new acme-support
cd acme-support
uv sync
ajolopy dev
curl -N -X POST http://127.0.0.1:8000/chat \
-H "Content-Type: application/json" \
-d '{"message": "Where is order 4392? Use the tool."}'
Token-by-token streaming response, function-calling loop, env-var
validation at boot, fallback to claude-haiku-4-5 on retriable
failure, OpenTelemetry spans for free. Twelve lines.
Why Ajolopy
The framework targets the seven production pains the wedge AI Engineer hits in week one:
- Env vars —
ajolopy devrefuses to boot with missing required variables. No more 2 a.m. discovery in staging. - Cost — every span carries
gen_ai.cost_usd. Sum by user / tenant / agent in one SQL query against your trace backend. - Evals as a CI gate —
ajolopy eval --ciblocks the PR when a metric regresses. The model upgrade that quietly broke safety is visible before a customer reports it. - SSE streaming with backpressure —
@Streamhandles disconnects, heartbeats, and cancellation. Not 30 lines of Starlette glue. - Cross-provider fallback —
fallback="claude-haiku-4-5"cuts in when Anthropic returns a retriable error. Switching providers is a kwarg, not a rewrite. - Diagnostics —
ajolopy doctorruns twelve health checks: Python version, env vars, deps, provider connectivity, etc. Lighthouse for AI apps. - Project layout —
ajolopy newscaffolds a NestJS-style module tree. Any senior backend dev reads it on first sight.
Read the long form for the full framing.
The 10 primitives
| AI (7) | Framework (3) |
|---|---|
@Agent, @Tool, @Stream, @Eval, @Metric, @Workflow, @MCP |
@Module, @Injectable, @Controller |
Every primitive ships with a magical default (covers the 90% case with zero ceremony) and an escape hatch (subclass or override) for the 10% that needs full control. The surface is locked at ten — anything that would require an eleventh decorator goes to v0.2+.
What's in the box (v0.1)
- Multi-provider LLM — Anthropic, OpenAI, Gemini, and a universal
OpenAI-compatible client that covers Ollama / Together / Groq /
Mistral / DeepSeek / OpenRouter, plus any other OpenAI-compatible
endpoint via the
base_urls=constructor escape hatch. ajolopy deploy <target>— generatesfly.toml,railway.json,render.yaml,vercel.json(with warnings), or a universalDockerfile.prodfor k8s / VPS / ECS.- Memory — five chat-history backends behind one
MemoryABC: in-memory, Redis, Postgres, Mongo, SQLite. - RAG —
RetrieverABC with Qdrant and pgvector backends. - MCP —
@MCPto consume external Model Context Protocol servers,@MCPServerto publish your own@Toolmethods as one. - Observability — OpenTelemetry on by default; five recipes for Langfuse, Sentry, Grafana, Honeycomb, and Datadog.
- Eval framework —
@Eval+@Metricwith built-in metrics (exact_match,json_match,llm_judge,contains,intent_match,tool_called) and regression detection. - CLI —
new,dev,doctor,env:show/validate/diff,generate,eval,deploy.
Examples
examples/support-agent/— runnable companion to the 3-step killer demo tutorial. Fork it, setANTHROPIC_API_KEY, runuv sync && ajolopy dev, and watch every primitive from@Agentthrough@Workflowand@MCPanswer real HTTP requests.examples/web-research/— the canonical "wire an external HTTP API as a@Tool" reference. AResearcheragent that calls the Tavily search API through one@Tool, composes a Markdown-cited answer through a second pure-Python@Tool, and streams the result over SSE. Ships with@Eval+ LLM-judge regression suite and pre-builtDockerfile.prod+fly.toml.examples/oncall-agent/— focused demo of the@MCPprimitive against a real external server. Spawns the canonicalgithub-mcp-serverover stdio so the on-call agent can search issues, PRs, and commits while triaging incidents. Pairs a local@Toolwith the MCP tools to show how Ajolopy resolves name collisions in favour of local code.examples/local-ollama/— the same@Agent+@Tool+@Streamshape running on a local Ollama server through Ajolopy's universal OpenAI-compatible provider. No API key required — install Ollama,ollama pull llama3.3,uv sync && ajolopy dev, and the streaming code reviewer answersPOST /chatentirely on your laptop.examples/memory-assistant/— persistent task tracker showing@Agent(memory="redis://...")end-to-end. AMemoryescape-hatch wrapper partitions chat history by a request-scopedsession_id, so two users hitting the same/chatendpoint see independent transcripts in Redis. Ships with adocker-compose.yml(app + Redis) and a 5-row eval suite whosememory_isolationmetric catches cross-session leaks.dogfood/docsbot/— Ajolopy's own docs bot, the first dogfood app. Live at https://ajolopy-docsbot.fly.dev. Answers questions about the framework using an in-memoryRetrieversubclass over the project's owndocs/tree. Exercises@Agent+@Tool+@Stream+@Eval+ cross-provider fallback end-to-end and ships pre-generatedDockerfile.prod+fly.tomlso it can be deployed in onefly deploy.examples/contextual-rag/— production-grade RAG agent with contextual chunking, hybrid retrieval, and citation-enforcing evals over a synthetic handbook. Builds ondogfood/docsbotwith header-based chunks, a 0.4 keyword- 0.6 semantic-hash hybrid scorer, and three eval metrics (one
LLM-as-judge, two deterministic) that fail when citations are
missing or point at the wrong section. Documents the upgrade path to
QdrantRetriever/PgvectorRetrieverfor real embeddings.
- 0.6 semantic-hash hybrid scorer, and three eval metrics (one
LLM-as-judge, two deterministic) that fail when citations are
missing or point at the wrong section. Documents the upgrade path to
Where to go next
- Quickstart —
five minutes from
pip installto a streaming agent. - Tutorial — the three-step killer demo arc (hello → evals → multi-agent + MCP) in ~55 lines.
- Reference — one page per primitive with every kwarg and the escape hatch.
- Observability recipes — Langfuse / Sentry / Grafana / Honeycomb / Datadog wired in via the standard OTel exporter.
Status
v0.1 — first public release. APIs are stable for the 10 primitives; expect additive changes in v0.1.x. Pin exact versions if you depend on the framework today.
The roadmap and current work are tracked in
board.json, validated against
.board-schema.json. Prose specs live in
specs/.
Contributing
Work is tracked on a PM-style board.
AGENTS.md documents the claim / branch / transition
protocol for both human and AI contributors. The
contributor release guide
covers how to cut a new version.
uv run python tools/board.py list # see what's open
uv run python tools/board.py next # see what to pick up next
File issues or open discussions at github.com/jcocano/Ajolopy.
License
MIT — see LICENSE.
The axolotl regenerates. So does Ajolopy.
Project details
Release history Release notifications | RSS feed
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 ajolopy-0.1.8.tar.gz.
File metadata
- Download URL: ajolopy-0.1.8.tar.gz
- Upload date:
- Size: 640.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f39a2496ade603d658478be9b4def7acf5b206a698e7d98abc2ee8f8bfb1248
|
|
| MD5 |
1cb1ac71f9c05d8ec23fc562ebd84c1b
|
|
| BLAKE2b-256 |
a77fa6fb4b3c70b305114ae09ab5aa8dd12b2ac3a10652080a16bc3b9ed313cb
|
Provenance
The following attestation bundles were made for ajolopy-0.1.8.tar.gz:
Publisher:
release.yml on jcocano/Ajolopy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ajolopy-0.1.8.tar.gz -
Subject digest:
4f39a2496ade603d658478be9b4def7acf5b206a698e7d98abc2ee8f8bfb1248 - Sigstore transparency entry: 1571052781
- Sigstore integration time:
-
Permalink:
jcocano/Ajolopy@b2f395976c1c9dd2355ae5de90f22d67999d9385 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/jcocano
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b2f395976c1c9dd2355ae5de90f22d67999d9385 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ajolopy-0.1.8-py3-none-any.whl.
File metadata
- Download URL: ajolopy-0.1.8-py3-none-any.whl
- Upload date:
- Size: 475.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e2c7962ec09e89bdf8c47b7a059df1e289a2cfc7f1d2236d2241bb8a92d0ff5
|
|
| MD5 |
ce30ae5f82166abfcca2f44778f12967
|
|
| BLAKE2b-256 |
ff7b57d394fdbdf4c656ebdce4f555fec658ef899e141d80db9d080459160959
|
Provenance
The following attestation bundles were made for ajolopy-0.1.8-py3-none-any.whl:
Publisher:
release.yml on jcocano/Ajolopy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ajolopy-0.1.8-py3-none-any.whl -
Subject digest:
3e2c7962ec09e89bdf8c47b7a059df1e289a2cfc7f1d2236d2241bb8a92d0ff5 - Sigstore transparency entry: 1571052822
- Sigstore integration time:
-
Permalink:
jcocano/Ajolopy@b2f395976c1c9dd2355ae5de90f22d67999d9385 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/jcocano
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b2f395976c1c9dd2355ae5de90f22d67999d9385 -
Trigger Event:
push
-
Statement type: