Skip to main content

CQRS-URL Platform - Commands and Queries as URL-addressable resources

Project description

codot is CQRS-URL Platform

AI Cost Tracking

PyPI Version Python License AI Cost Human Time Model

  • ๐Ÿค– LLM usage: $1.6500 (11 commits)
  • ๐Ÿ‘ค Human dev: ~$558 (5.6h @ $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):// and file:///data, file:///schemas
  • user โ€” only fetch, converttojson, converttobase64, render and public queries, only against http://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

  1. 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=...)
  1. Register it in api/commands/__init__.py::register_default_commands.
  2. Optionally add an entry in rules.yaml if 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 production
  • ACCESS_TOKEN_EXPIRE_MINUTES โ€” default 60
  • ALLOWED_LOCAL_ROOTS โ€” comma list, default /data,/schemas
  • FETCH_MAX_BYTES โ€” size cap for fetched resources (default 50 MiB)

License

Licensed under Apache-2.0.

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

codot-0.1.10.tar.gz (24.7 kB view details)

Uploaded Source

Built Distribution

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

codot-0.1.10-py3-none-any.whl (29.1 kB view details)

Uploaded Python 3

File details

Details for the file codot-0.1.10.tar.gz.

File metadata

  • Download URL: codot-0.1.10.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

Hashes for codot-0.1.10.tar.gz
Algorithm Hash digest
SHA256 88035f6f1edd6a16824ef616af9e1e40833b0a9efca347e280f4dcb63b5977c5
MD5 6b8dc75978059aa384350d713bc5528d
BLAKE2b-256 ad84785d914b7b9be2855fe4fba97c2e864fd2d9440683cef91b77751d77362a

See more details on using hashes here.

File details

Details for the file codot-0.1.10-py3-none-any.whl.

File metadata

  • Download URL: codot-0.1.10-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

Hashes for codot-0.1.10-py3-none-any.whl
Algorithm Hash digest
SHA256 95fda358f2f6e7987339c9ee86e9bdaf938174aee1a8b0176fbc01878d27d619
MD5 fd3dfaa58784b1bce234c06e7d0796e4
BLAKE2b-256 8d3616ee7719abdac2ffb0f80b42246dc73a8cea4ac2ba3e8938d24889e04d03

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