Atomic Microkernel Architecture optimized for AI-Driven Development
Project description
MicroCoreOS: The Architecture That Makes AI-Generated Code Maintainable
The current solution to AI coding mistakes is more context — .cursorrules, CLAUDE.md, skills, system prompts. The result: context windows full of instructions instead of code.
MicroCoreOS takes the opposite approach: an architecture where there's only one place to put things.
1 file = 1 feature. When AI makes a mistake, you find it in 30 seconds — not 30 minutes reviewing 8 files. The AI reads 2 files (the auto-generated system manifest + the plugin it's working on), follows one pattern, and produces clean, isolated code.
The Elastic Monolith
MicroCoreOS is an Elastic Monolith built on an Atomic Microkernel Architecture: a single process where business logic lives in atomic plugins (1 file = 1 feature) and every piece of infrastructure is a swappable Tool behind a written contract — in-process by default, distributed on demand.
Scaling is not a rewrite; it is a tool swap. The same plugins run unchanged whether the event bus is in-memory or Kafka, the state store is a dict or Redis, the database is SQLite or PostgreSQL. The kernel never knows which implementation is mounted — it only knows the contract. This is the difference from a modular monolith (modules, but fixed infrastructure) and from microservices (distributed from day one, whether you need it or not): an Elastic Monolith starts as the simplest possible system and stretches piece by piece, only where load demands it.
Proven today: SQLite ↔ PostgreSQL swap with identical plugin code, and a transport-driver
interface (EventBusDriver) where retries, DLQ, RPC and tracing are broker-agnostic —
Redis Streams, RabbitMQ, Kafka and a durable SQLite transport already shipped.
Quick Start
uv init my-app && cd my-app
uv add microcoreos
uv run microcoreos new . # materialize tools/, domains/, plans/ as YOUR source
uv run microcoreos # boot
# Visit http://localhost:5000/docs
Or clone the repo to work on the framework itself:
git clone https://github.com/theanibalos/MicroCoreOS.git
cd MicroCoreOS
cp .env.example .env
uv run main.py # or: uv run microcoreos
No configuration needed. SQLite is the default (zero setup). The Kernel discovers all plugins, injects dependencies, runs migrations, and starts the server.
Only the Kernel comes from the package. Tools and domains are copied into your project, because installing and swapping infrastructure here is file placement — and you cannot move files inside site-packages. Optional infrastructure travels as extras: uv add 'microcoreos[redis]', [postgres], [kafka], [rabbitmq], [s3], [scheduler], or [all].
One File = One Feature
This is a complete feature — schema, registration, logic, event publishing:
# domains/products/plugins/create_product_plugin.py
from pydantic import BaseModel, Field
from microcoreos import BasePlugin
class CreateProductRequest(BaseModel):
name: str = Field(min_length=1, max_length=200)
price: float = Field(gt=0)
class CreateProductPlugin(BasePlugin):
def __init__(self, http, db, event_bus, logger):
self.http = http
self.db = db
self.bus = event_bus
self.logger = logger
async def on_boot(self):
self.http.add_endpoint("/products", "POST", self.execute,
tags=["Products"], request_model=CreateProductRequest)
async def execute(self, data: dict, context=None):
try:
req = CreateProductRequest(**data)
product_id = await self.db.execute(
"INSERT INTO products (name, price) VALUES ($1, $2) RETURNING id",
[req.name, req.price]
)
await self.bus.publish("product.created", {"id": product_id})
return {"success": True, "data": {"id": product_id, "name": req.name}}
except Exception as e:
# Safe Error Reporting: log technically, respond safely.
self.logger.error(f"Failed to create product: {e}")
return {"success": False, "error": "Database operation failed"}
Drop this file in domains/products/plugins/, restart, and it works. No main.py edits, no route registration, no wiring.
What Makes It Different
~360 functional lines of kernel. Pure stdlib. No external dependencies in core.
The entire orchestration engine — DI, plugin discovery, tool lifecycle, fault tolerance — uses only Python's standard library.
DI by parameter name.
def __init__(self, db, http, logger): # These ARE the injected tools
No decorators, no configuration, no container setup. The Kernel inspects your constructor, matches names to tools, done.
AI_CONTEXT.md regenerates on every boot.
The system scans all tools, plugins, domains, events, and models — then writes a manifest with exact method signatures. Your AI always has current context, regardless of project size.
Tools are swappable. Plugins don't change.
A Tool is identified by its name property. The SQLite tool and the PostgreSQL tool both expose the same API (query, execute, transaction, health_check) and both use $1, $2 placeholders. To switch databases:
- Change
name = "db"in the SQLite tool toname = "sqlite" - Change
name = "postgresql"in the PostgreSQL tool toname = "db" - Plugins don't change a single line.
Migrations are the honest exception: the db tool is not an ORM — SQL files run
verbatim on the active engine (no dialect translation), so an engine swap includes
one review pass over your migration SQL. The full procedure is in
docs/ELASTIC_DEPLOYMENT.md (Stage 1).
This pattern works for any infrastructure: swap the event bus backend, the HTTP server, the auth mechanism — as long as the new tool has the same name and API, plugins keep working.
Additional tools (PostgreSQL, Redis state, chaos testing) are available in extras/available_tools/. To activate, move them into tools/ — and if the new tool reuses an existing name (e.g. redis_state registers as "state"), move the tool it replaces out of tools/ first: only one tool per name may be discovered.
The Redis state swap is verified by a parity suite (tests/tools/test_state_parity.py): the same contract battery runs against the in-memory reference and against a real Redis, so the replacement is proven equivalent, not assumed.
Honest Kernel & Smart Infrastructure.
The Kernel is "logic-free." ToolProxy observes and reports health but never retries automatically, ensuring data integrity. Resilience is handled where the knowledge is: in the Tools (e.g., SQLite lock retries) or the Plugins (explicit logic).
Built-in Observability (Zero Config)
Causal Event Tracing — Every event on the bus carries a parent_id. GET /system/traces/tree reconstructs the full causal chain. GET /system/traces/stream streams it live via SSE.
Tool Call Metrics — Every tool method call is automatically timed by ToolProxy. Access via registry.get_metrics() or attach a real-time sink.
OpenTelemetry (optional) — Set OTEL_ENABLED=true. Every tool call gets a span. Export to Jaeger, Grafana Tempo, Datadog. Zero changes to plugins.
Architecture
MicroCoreOS/
├── microcoreos/ # ~360 functional lines, zero external deps (the pip package)
│ ├── kernel.py # Discovery, DI, lifecycle
│ ├── container.py # DI container + ToolProxy (Health/Metrics)
│ ├── registry.py # Thread-safe system state
│ ├── context.py # causality & Identity context
│ ├── base_plugin.py # Plugin contract (11 lines)
│ ├── base_tool.py # Tool contract (24 lines)
│ └── cli.py # The `microcoreos` command
├── tools/ # Stateless, swappable infrastructure
│ ├── http_server/ # FastAPI (REST + WebSocket + SSE)
│ ├── sqlite/ # Relational DB — isolation + smart retries
│ ├── event_bus/ # TTL + Retries + DLQ + Causal tracing
│ ├── auth/ # JWT + bcrypt
│ ├── telemetry/ # OpenTelemetry (optional)
│ └── ... # logger, state, config, registry
├── domains/ # Business logic
│ ├── users/ # Full CRUD + auth + JWT + events
│ ├── system/ # Observability endpoints
│ └── {your_domain}/
└── AI_CONTEXT.md # Auto-generated on every boot
Problems It Addresses
| Problem | Approach |
|---|---|
| AI needs too many files for context | 2 files: AI_CONTEXT.md + the plugin. |
| Coupling between modules | Domains communicate via EventBus only, never direct imports. |
| Architecture erodes under pressure | Conventions are explicit and enforced. |
| Merge conflicts on shared files | Each feature is its own file. No shared business logic files. |
| One dependency failure cascades | ToolProxy contains failures per-tool automatically. |
| Changing databases takes weeks | Swap the tool file — same API, same placeholders — plus one review pass over migration SQL. |
| Background errors disappear | EventBus watchdog + DLQ + causality engine. |
| Slow developer onboarding | Read AI_CONTEXT.md + one plugin. |
| Sync/async mixing bugs | Kernel auto-detects def vs async def, offloads sync to thread pool. |
→ Deep dive: docs.microcoreos.com/guide/problems
Available Tools
| Tool | Description |
|---|---|
http |
FastAPI gateway — REST, WebSocket, SSE, auto-generated OpenAPI |
db |
SQLite (default) or PostgreSQL — same API, drop-in swap at the tool-API level |
event_bus |
Pub/sub + RPC + TTL + Retries + DLQ + causal tracing. Transports swap by env var: in-process (default), SQLite (durable, survives restarts), Redis Streams (distributed); RabbitMQ in extras |
auth |
JWT lifecycle + bcrypt password hashing |
logger |
Structured logging with sink pattern |
state |
Thread-safe in-memory key-value store |
registry |
Runtime introspection + metrics + health status |
telemetry |
OpenTelemetry — auto-instruments all tool calls |
config |
Environment variable validation for plugins |
Available in extras/available_tools/ (move to tools/ to activate):
| Tool | Description |
|---|---|
s3 |
AWS S3 object storage — private bucket + presigned URLs |
db |
PostgreSQL — same API and placeholders as SQLite; swap procedure in ELASTIC_DEPLOYMENT.md |
state |
Redis-backed state — drop-in swap for in-memory StateTool |
rabbitmq |
RabbitMQ driver for the Event Bus — transports swap by file, like tools: drop the *_driver.py into tools/event_bus/ and set EVENT_BUS_DRIVER=rabbitmq |
scheduler |
Cron jobs + in-memory one-shots (APScheduler) |
Tools and the domains that need them. The dependency runs one way — a plugin cannot exist without its tool, but a tool stands on its own. So the scheduler installs in two independent steps:
microcoreos add scheduler # dependency + both folders + .env, in one command
Or by hand, which is what that command does:
uv add 'microcoreos[scheduler]'
mv extras/available_tools/scheduler tools/ # cron + in-memory one-shots
mv extras/available_domains/scheduler domains/ # durable one-shots (needs the above)
The tool keeps one-shots in memory by design: an arbitrary callable cannot
survive a restart, and a tool never uses other tools. The optional domain
composes db + scheduler + event_bus in the plugin layer to get durability,
and exposes it to any domain over the bus as scheduler.one_shot.schedule /
scheduler.one_shot.cancel — events that fire hours later and survive a restart.
It is also the reference example of that composition rule
(.agent/workflows/new-tool.md). Installing the domain without the tool fails
at boot, loudly: Plugin scheduler.DurableOneShotsPlugin aborted: Missing tools: scheduler.
Working with AI
> Read AI_CONTEXT.md for available tools.
> Create a plugin in the orders domain that creates an order and publishes order.created.
The AI uses $1, $2 placeholders, registers via http, publishes via event_bus, places everything in one file.
For full domains: follow .agent/workflows/new-domain.md.
Testing
Constructor injection makes tests black-box: inject real in-memory tools
(SQLite :memory: with the domain migration applied, in-process event bus, real
auth) and mock only the tool whose failure you are forcing. A failing test then
pinpoints the plugin whose SQL or contract actually broke.
@pytest.mark.anyio
async def test_create_user_persists_and_publishes(db, bus, auth):
# db = SqliteTool on ":memory:" with the users migration applied
# bus = in-process EventBusTool; auth = real AuthTool
plugin = CreateUserPlugin(http=MagicMock(), db=db, event_bus=bus,
logger=MagicMock(), auth=auth)
result = await plugin.execute(
{"name": "Ana", "email": "ana@example.com", "password": "password123"}
)
assert result["success"] is True
row = await db.query_one("SELECT * FROM users WHERE id = $1", [result["data"]["id"]])
assert await auth.verify_password("password123", row["password_hash"]) # stored hashed, never plain
Complete examples — happy paths, ownership (403), login throttling, error paths
that never leak technical detail — live in tests/domains/users/.
Documentation
Full docs at docs.microcoreos.com: Quick Start · First Plugin Tutorial · Plugin Reference · Tools Reference · Observability · Philosophy
Roadmap
Two tracks — see ROADMAP.md for the full plan and decision log:
- Monolith track: route-collision & table-ownership linters, automatic test
generation,
uv add microcoreos(Core as an installable package) - Distributed track: event ACLs (Redis Streams, RabbitMQ, Kafka and the durable SQLite transport already shipped, all with crash-safe native delay via capability claims), runtime contracts via the schema catalog, distributed observability (export local, aggregate outside), transactional outbox (deferred until a real chain needs it)
- Tool distribution — tools are copied into your project, not installed into site-packages: you own them and can edit them, and swapping stays what it is today, moving a file. Only the Core travels in the package (ROADMAP Issue 39)
License
Anibal Fernandez (@theanibalos)
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 microcoreos-0.1.0.tar.gz.
File metadata
- Download URL: microcoreos-0.1.0.tar.gz
- Upload date:
- Size: 484.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c6009fea9c5097fb2e84c8f43a195e90ddb97f0c8848f43a7ff7d2163caafda
|
|
| MD5 |
5db74cc37291bb911d8ff09ef212ed88
|
|
| BLAKE2b-256 |
1cc668f5c7d74982e4f0982dd56d138d0c765c53b902b8d21eed9fed71cdf752
|
Provenance
The following attestation bundles were made for microcoreos-0.1.0.tar.gz:
Publisher:
release.yml on theanibalos/MicroCoreOS
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
microcoreos-0.1.0.tar.gz -
Subject digest:
1c6009fea9c5097fb2e84c8f43a195e90ddb97f0c8848f43a7ff7d2163caafda - Sigstore transparency entry: 2264948930
- Sigstore integration time:
-
Permalink:
theanibalos/MicroCoreOS@16c32c96ae6337ff95d4d0e47a831c77fd8bf5de -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/theanibalos
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@16c32c96ae6337ff95d4d0e47a831c77fd8bf5de -
Trigger Event:
push
-
Statement type:
File details
Details for the file microcoreos-0.1.0-py3-none-any.whl.
File metadata
- Download URL: microcoreos-0.1.0-py3-none-any.whl
- Upload date:
- Size: 315.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8cc2a455bfc2c123a53161af5517a44ed55e3000e70bfcfb358d7d372618b548
|
|
| MD5 |
98ee67cd6f5294d874f248848bdf4603
|
|
| BLAKE2b-256 |
096b37bea9be91f60a98d65bbacf5b9c41e02f5674d0243e7fd5e63e4155c7dc
|
Provenance
The following attestation bundles were made for microcoreos-0.1.0-py3-none-any.whl:
Publisher:
release.yml on theanibalos/MicroCoreOS
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
microcoreos-0.1.0-py3-none-any.whl -
Subject digest:
8cc2a455bfc2c123a53161af5517a44ed55e3000e70bfcfb358d7d372618b548 - Sigstore transparency entry: 2264949059
- Sigstore integration time:
-
Permalink:
theanibalos/MicroCoreOS@16c32c96ae6337ff95d4d0e47a831c77fd8bf5de -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/theanibalos
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@16c32c96ae6337ff95d4d0e47a831c77fd8bf5de -
Trigger Event:
push
-
Statement type: