brick-example — the starter brick
A working brick to copy: quotes with lines, sent and accepted. Rename it (brick_example → brick_<name>,
Brick("example"), the quote_ table prefix) and replace the domain with yours. Every file shows the
rule it is there for.
src/brick_example/
domain/ the business rules — plain Python, no database, no HTTP
application/ the use cases — each declared once, served as an API route AND an MCP tool
infrastructure/ the tables, and the repository that loads/saves an aggregate whole
app.py the ASGI app: routes, /mcp, and the sign-in metadata for agents
schema.sql the brick's tables — every one prefixed, every one with a primary key
tests/ rules without a database; both doors without a bucket
Where things go. A rule ("a sent quote cannot change") lives in domain/. Who may do it and which
rows they may see live in application/. Nothing in domain/ imports SQLAlchemy, FastAPI or MCP — that
is what lets the rules run in milliseconds and be read by someone who is not a programmer.
Run it.
pip install -e '.[test]'
pytest -q # no bucket needed
BUCKET=my-bucket erp-migrate --schema src/brick_example/schema.sql --brick quote=0.1.0
BUCKET=my-bucket DEV_ALLOW_ANON=1 DEV_USER_PERMISSIONS=example:quote:send,example:quote:accept \
uvicorn brick_example.app:app # API at /docs, agents at /mcp
Asking another brick to act (optional). If quotes had to be emailed to the customer, the brick would
not learn Gmail: it would hold SEND = CapabilitySeam("mail.send") and call it. With a mail provider in
the composition the email goes out; with none, the call returns a ManualTask — the exact message a
person sends by hand — and the use case stores it as a task. See "Capabilities" in the platform's
BRICKS.md. Most bricks need none; this one has none.
Deployed behind the gateway with DODIL_USER_POOL=<org>/<pool>, a person connecting Claude.ai or
ChatGPT to /mcp is sent to that pool to sign in, and their agent sees exactly the quotes they see.