CQRS-URL Platform - Commands and Queries as URL-addressable resources
Project description
codot is CQRS-URL Platform
AI Cost Tracking
- ๐ค LLM usage: $1.9500 (13 commits)
- ๐ค Human dev: ~$620 (6.2h @ $100/h, 30min dedup)
Generated on 2026-04-23 using openrouter/qwen/qwen3-coder-next
Commands and Queries as URL-addressable resources. Operate on arbitrary data over pluggable protocols (http://, https://, file://, data:, โฆ), with runtime JSON-Schema validation and policy-based access control โ no DTOs, no codegen, no per-command type churn.
This is the reference implementation of the design discussed in the accompanying articles:
- CQRS decoupled from data models (bytes + Struct envelope)
- Command/Query as a URL resource (
PUT /commands/converttojson) - Required schemas at runtime (JSON Schema at
schema_uri) - Controlling who can do what on which URI (policy engine with URL globs)
Quick start
Full Docker stack
# 1. Build and run everything
make build
make up
# 2. Issue a token (admin)
make token
# 3. Open the playground
# โ http://localhost:8000
#
# Sign in with admin/admin, alice/alice (analyst), or bob/bob (user).
# Hit one of the preset buttons: CSV โ JSON, render posts, pipeline.
# 4. Smoke-test the API (14 tests: commands, queries, policy, agents)
make test
Local development (agents / MCP)
For agent execution with local MCP servers, run the API directly (outside Docker) so the spawned MCP subprocesses can access your filesystem:
# Start the API locally
cd api && python3 -m uvicorn main:app --host 0.0.0.0 --port 28080
# Run a standalone MCP agent
python3 codot_run.py examples/agent_mcp.json --url http://localhost:28080 --agent
# Run a workflow with an agent step
python3 codot_run.py examples/workflow_agent_mcp.json --url http://localhost:28080
# or simply:
make workflow
# Run the agent integration test suite
make test-agent
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
liveness probe |
| GET | /catalog |
public catalog of commands/queries/protocols/backends |
| POST | /auth/token |
issue a dev JWT |
| GET | /auth/me |
current principal |
| GET | /commands |
list commands (auth) |
| PUT | /commands/{name} |
run a command |
| GET | /queries |
list queries (auth) |
| POST | /queries/{name} |
run a query |
| POST | /agents/{agent_id}/run |
execute an agent (MCP, LiteLLM, Bash, etc.) |
| GET | /agents/backends |
list registered agent backends |
| GET | /docs |
OpenAPI / Swagger UI |
Bundled commands
| Name | Purpose |
|---|---|
fetch |
read a resource from any protocol and return its raw bytes (base64) |
converttojson |
fetch + transform CSV/text/XML to JSON (+ optional schema validation) |
converttoxml |
fetch JSON/CSV and emit XML |
converttocsv |
fetch JSON list-of-objects and emit CSV |
converttobase64 |
base64-encode any resource (useful for PDFs, images) |
render |
Jinja2 template โ HTML page (data from URI or inline) |
pipeline |
chain other commands; use "$previous.output" as a URI reference |
Adding your own command is three steps: subclass Command, register it, optionally add a policy rule.
Bundled queries
| Name | Purpose |
|---|---|
from-url |
fetch one or more URIs and return them in a list |
introspect |
list commands, queries, protocols |
Agent backends
The platform now supports autonomous agents via multiple communication backends. An agent is defined by a role, goal, tools, and a backend_config.
| Backend | Driver | Typical use |
|---|---|---|
mcp |
MCPStdioClient / MCPSseClient |
Any MCP-compatible server (JSON-RPC 2.0 over stdio or SSE) |
litellm |
httpx |
LLM inference via LiteLLM / OpenAI-compatible APIs |
bash_cli |
asyncio.create_subprocess_shell |
Shell scripts, local tools |
http_api |
httpx |
Generic REST / GraphQL endpoints |
websocket |
websockets |
Real-time streaming agents |
Agents can be invoked standalone (POST /agents/{id}/run) or embedded inside a pipeline step via the optional agent_node field. The pipeline automatically decodes data: URIs from $previous.output and injects them into the agent context.
CLI runner
Run workflows and agents from shell without writing curl:
# Standalone MCP agent
python3 codot_run.py examples/agent_mcp.json --url http://localhost:18080 --agent
# Workflow with an agent step
python3 codot_run.py examples/workflow_agent_mcp.json --url http://localhost:18080
Protocols
| Scheme | Notes |
|---|---|
http, https |
standard fetch via httpx, size-limited |
file:// |
local reads limited to ALLOWED_LOCAL_ROOTS (default: /data, /schemas) |
data: |
RFC 2397 inline payloads, base64 or percent-encoded |
Adding a new protocol (e.g. s3://, ftp://, sqlite://) is a matter of writing a class with a scheme attribute and an async fetch(uri) method, then registering it in protocols/__init__.py.
Policy
Policies are loaded from api/policy/rules.yaml at startup. Each rule matches by role and lists glob patterns of allowed command/query names, URIs and schema URIs. Reload without rebuild: edit the file and restart the container (make restart).
Three built-in roles:
- admin โ everything
- analyst โ all commands/queries, all
http(s)://andfile:///data,file:///schemas - user โ only
fetch,converttojson,converttobase64,renderand public queries, only againsthttp://cqrs-data/*,https://public-*,file:///data/public/*,data:*
See also: api/policy/__init__.py (the engine), api/auth/__init__.py (JWT issuance), api/main.py (enforcement point).
Layout
.
โโโ api/ FastAPI service
โ โโโ commands/ one file per command
โ โโโ queries/ one file per query
โ โโโ protocols/ pluggable URI fetchers
โ โโโ policy/ RBAC engine + rules.yaml
โ โโโ validators/ JSON Schema over arbitrary URIs
โ โโโ auth/ JWT issuance + FastAPI dependencies
โ โโโ agent.py multi-backend agent execution (MCP, LiteLLM, Bash, HTTP, WS)
โ โโโ mcp_client.py JSON-RPC 2.0 MCP client (stdio + SSE)
โ โโโ models.py envelope (CommandRequest/Response, AgentNode, AgentRequest)
โ โโโ config.py env-based settings
โ โโโ test_all_agents.py integration tests for all agent backends
โ โโโ main.py HTTP layer
โโโ codot_run.py CLI runner for workflows and agents
โโโ mcp_servers/ example MCP servers for local testing
โ โโโ summary_server.py
โโโ examples/ example workflow and agent JSONs
โ โโโ workflow_agent_mcp.json
โ โโโ agent_mcp.json
โโโ frontend/ nginx + static playground (HTML/CSS/JS)
โโโ schemas/ JSON Schemas served at http://schemas/
โโโ sample-data/ demo data served at http://cqrs-data/
โโโ tests/
โ โโโ smoke.sh curl-based end-to-end tests
โ โโโ test_policy.py pytest unit tests
โ โโโ test_protocols.py
โโโ cqrs-workflow-editor/ React + Vite visual workflow editor (@xyflow/react)
โโโ articles/ status articles (Markdown, for WordPress)
โโโ docker-compose.yml
โโโ Makefile
Adding a command
- Create
api/commands/my_thing.py:
from . import Command
from models import CommandRequest, CommandResponse
class MyThingCommand(Command):
name = "mything"
description = "Short sentence."
input_hint = {"input_uri": "...", "meta.foo": "..."}
async def execute(self, request: CommandRequest) -> CommandResponse:
# ... do work, return CommandResponse(payload_b64=..., mime=..., meta=...)
- Register it in
api/commands/__init__.py::register_default_commands. - Optionally add an entry in
rules.yamlif you want non-admins to call it.
That's the whole loop.
Environment
Copy .env.example โ .env and adjust. Key variables:
JWT_SECRETโ must be โฅ 32 chars in productionACCESS_TOKEN_EXPIRE_MINUTESโ default 60ALLOWED_LOCAL_ROOTSโ comma list, default/data,/schemasFETCH_MAX_BYTESโ size cap for fetched resources (default 50 MiB)
License
Licensed under Apache-2.0.
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 codot-0.1.12.tar.gz.
File metadata
- Download URL: codot-0.1.12.tar.gz
- Upload date:
- Size: 24.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea46b18b071f56e99959e91a363d84c400c76bbc4199b63e890e560110843397
|
|
| MD5 |
6aeb94320479f53639f040e6b8d39432
|
|
| BLAKE2b-256 |
8ea4cc90f05e96b8f9310dc7242ed937673d5bdd3e729153e42031e9d816144c
|
File details
Details for the file codot-0.1.12-py3-none-any.whl.
File metadata
- Download URL: codot-0.1.12-py3-none-any.whl
- Upload date:
- Size: 29.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
676951dd36d1783c52bece49987407fb16ad6b09de53351d7869dc213c3ad75e
|
|
| MD5 |
de9b70e0f82a4d8480a474411d8d9e1e
|
|
| BLAKE2b-256 |
46e48f866dc4681fe8d1e857a9bed6e166ad8a5902336d759cdb6a109d909974
|