Skip to content

Architecture diagrams

Five pictures that between them explain what MechCrate is. Each one is embedded elsewhere in the docs next to the prose it belongs to; this page collects them so you can see the whole system at once.

They are authored as Mermaid in src/components/diagrams/sources/ and rendered to static SVG ahead of the build, so there is no diagramming JavaScript on this page. The pictures are in the HTML, which is also what llms-full.txt and any scraper sees.

The problem MechCrate starts from: you need three services from one repo and one from another, not all fourteen. One Traefik router runs per workstation. Projects attach to the shared devmesh-traefik network and declare a Host() rule in their compose labels, so a service is reachable at a hostname the moment it is up, and costs nothing when it is not.

MechCrate ecosystem topologyA browser reaches hostnames such as api.localhost and mechcrate.localhost. One workstation-wide Traefik router, installed by mx router install, reads Host rules from container labels on the shared devmesh-traefik Docker network and forwards each hostname to the running container that claims it. Several mx projects attach to that same network, and only the subset of services you started is up.

devmesh-traefik — shared external Docker network

mx router — one per workstation

project: mech-crate/site

project: acme

Host match

Host match

Host match

project: legacy-shop

every service
not started

Browser
api.localhost · admin.localhost · mechcrate.localhost

Traefik
:80 · Host() rules read from container labels

api
Host: api.localhost

admin
Host: admin.localhost

worker
not started

site
Host: mechcrate.localhost

db · redis
not started

MechCrate ecosystem topologyA browser reaches hostnames such as api.localhost and mechcrate.localhost. One workstation-wide Traefik router, installed by mx router install, reads Host rules from container labels on the shared devmesh-traefik Docker network and forwards each hostname to the running container that claims it. Several mx projects attach to that same network, and only the subset of services you started is up.

devmesh-traefik — shared external Docker network

mx router — one per workstation

project: mech-crate/site

project: acme

Host match

Host match

Host match

project: legacy-shop

every service
not started

Browser
api.localhost · admin.localhost · mechcrate.localhost

Traefik
:80 · Host() rules read from container labels

api
Host: api.localhost

admin
Host: admin.localhost

worker
not started

site
Host: mechcrate.localhost

db · redis
not started

One router per workstation. Every project attaches to the same devmesh-traefik network, Traefik reads Host() rules off container labels, and only the services you started are up.

Every mx project has the same shape. That is what lets make dev mean the same thing in a Rust API, an Astro site and a Laravel app: the verbs live in make/*.mk and scripts/*.sh, which mx owns and can upgrade, while apps/ and docker/system/ stay yours.

The mx folder contractAn mx project root contains a thin Makefile dispatcher, a make directory with one include per verb, a scripts directory holding the actual bash, an apps directory with one directory per service that mx never edits, and a docker directory split into dot-config for env files, compose for the baseline and dev override, system for infrastructure you own, and dockerfiles for per-service build files.

myproject/
an mx project root

Makefile
thin dispatcher — make dev · up · build · logs

make/
one .mk include per verb
dev.mk · build.mk · logs.mk · …

scripts/
the actual bash
dev.sh · build.sh · doctor.sh · …

apps/

docker/

{service}/
your application source
mx scaffolds it, then never edits it

.config/
.env.shared · .env.{service}
.env.secrets (gitignored)

compose/
{service}.yml — baseline
{service}.dev.yml — dev override

system/
infrastructure you own
proxies, certs, seed data

dockerfiles/
{service}/app — dev target
{service}/app.prod — release target

The mx folder contractAn mx project root contains a thin Makefile dispatcher, a make directory with one include per verb, a scripts directory holding the actual bash, an apps directory with one directory per service that mx never edits, and a docker directory split into dot-config for env files, compose for the baseline and dev override, system for infrastructure you own, and dockerfiles for per-service build files.

myproject/
an mx project root

Makefile
thin dispatcher — make dev · up · build · logs

make/
one .mk include per verb
dev.mk · build.mk · logs.mk · …

scripts/
the actual bash
dev.sh · build.sh · doctor.sh · …

apps/

docker/

{service}/
your application source
mx scaffolds it, then never edits it

.config/
.env.shared · .env.{service}
.env.secrets (gitignored)

compose/
{service}.yml — baseline
{service}.dev.yml — dev override

system/
infrastructure you own
proxies, certs, seed data

dockerfiles/
{service}/app — dev target
{service}/app.prod — release target

Every mx project has the same shape, so every project answers to the same verbs. mx owns the contract; you own apps/{service} and docker/system.

There is one compose file per service describing what it is, and a .dev.yml override describing what it needs while you are working on it: the source mount, the HMR port, a healthcheck with room to boot. make dev merges both; make up uses the baseline alone, which is the same file that ships.

Compose layering, baseline plus dev overrideThe baseline compose file for a service defines the release build target, env files, healthcheck, Traefik routing labels and networks. The dev override file re-targets the build at the development stage, bind-mounts the source for hot reload, masks node_modules with anonymous volumes, publishes the Vite HMR port and relaxes the healthcheck start period. Docker Compose merges the two files, and make dev brings up the merged result, reachable through the router.

docker/compose/site.yml
baseline — same everywhere
build target: runner
env_file: .env.secrets · .env.shared · .env.site
healthcheck: curl /api/health
labels: Host(mechcrate.localhost) → port 4321
networks: default + devmesh-traefik

docker/compose/site.dev.yml
dev override — merged on top
build target: development
volumes: ../../apps/site:/app
masks /app/node_modules and /app/.astro
ports: 24678 (Vite HMR)
NODE_ENV=development
healthcheck start_period: 30s

docker compose
-f site.yml -f site.dev.yml

effective dev stack
container site-dev
source mounted · hot reload on
db and redis ports published locally

http://mechcrate.localhost
via the mx router — no port juggling

make up / release
baseline only — no override

Compose layering, baseline plus dev overrideThe baseline compose file for a service defines the release build target, env files, healthcheck, Traefik routing labels and networks. The dev override file re-targets the build at the development stage, bind-mounts the source for hot reload, masks node_modules with anonymous volumes, publishes the Vite HMR port and relaxes the healthcheck start period. Docker Compose merges the two files, and make dev brings up the merged result, reachable through the router.

docker/compose/site.yml
baseline — same everywhere
build target: runner
env_file: .env.secrets · .env.shared · .env.site
healthcheck: curl /api/health
labels: Host(mechcrate.localhost) → port 4321
networks: default + devmesh-traefik

docker/compose/site.dev.yml
dev override — merged on top
build target: development
volumes: ../../apps/site:/app
masks /app/node_modules and /app/.astro
ports: 24678 (Vite HMR)
NODE_ENV=development
healthcheck start_period: 30s

docker compose
-f site.yml -f site.dev.yml

effective dev stack
container site-dev
source mounted · hot reload on
db and redis ports published locally

http://mechcrate.localhost
via the mx router — no port juggling

make up / release
baseline only — no override

A baseline compose file describes the service everywhere; a dev override adds the source mount, the HMR port and a relaxed healthcheck. make dev merges the two, make up uses the baseline alone.

The techniques corpus is a Postgres + pgvector store that agents query through the MCP server’s rag_context tool. What fills it is a research pipeline that opens a pull request, so the corpus only ever learns things a human agreed to merge. The same markdown is published here under Techniques Corpus.

The MechCrate AI loopA coding agent calls the mx MCP server, whose rag_context tool embeds the query and searches a pgvector store hosted on Neon or a local Postgres. The store is filled by mx rag ingest from the sixty-seven markdown docs under docs/development. Those docs are written and revised by a weekly research pipeline that opens a pull request; a human reviews and merges it, and only merged docs are ingested. The same docs are published to this site.

growth — weekly, and PR-gated

retrieval — every agent turn

tool call

rejected

vector search

ranked passages

merged

mx rag ingest

corpus loader

Coding agent
any MCP client

mx MCP server
mx_· make_· project_· rag_

rag_context
embed query → top-k

techniques corpus
Postgres + pgvector · Neon or local

docs/development/*.md
67 frontmatter-typed docs

Weekly run
or /technique-research

Research pass
coverage → sources → draft

Pull request
branch research/{slug}

Human review

mechcrate.dev/docs/corpus
the same docs, for humans

The MechCrate AI loopA coding agent calls the mx MCP server, whose rag_context tool embeds the query and searches a pgvector store hosted on Neon or a local Postgres. The store is filled by mx rag ingest from the sixty-seven markdown docs under docs/development. Those docs are written and revised by a weekly research pipeline that opens a pull request; a human reviews and merges it, and only merged docs are ingested. The same docs are published to this site.

growth — weekly, and PR-gated

retrieval — every agent turn

tool call

rejected

vector search

ranked passages

merged

mx rag ingest

corpus loader

Coding agent
any MCP client

mx MCP server
mx_· make_· project_· rag_

rag_context
embed query → top-k

techniques corpus
Postgres + pgvector · Neon or local

docs/development/*.md
67 frontmatter-typed docs

Weekly run
or /technique-research

Research pass
coverage → sources → draft

Pull request
branch research/{slug}

Human review

mechcrate.dev/docs/corpus
the same docs, for humans

Agents read the corpus through the MCP rag_context tool. The research pipeline writes to it, but only through a pull request a human merges, so the corpus grows on purpose.

mx add is not a file copier. A recipe manifest declares options, placeholders, directories, an optional framework scaffold command and a set of templates; mx resolves them in order, lands the compose files, dockerfiles and env file, writes the Traefik labels for your domain, and hands you a make dev that works.

Recipe install flowRunning mx add site with the astro recipe loads that recipe's manifest, resolves its options and expands its placeholders, optionally runs the recipe's init command to scaffold the framework app and create the declared directories, renders the template files into the project as the app source, the compose baseline and dev override, the dockerfiles and the service env file, writes Traefik routing labels for the chosen domain, and prints next steps ending in make dev, which brings the service up behind the router.

files landed

apps/site/**
app source
+ health route

docker/compose/
site.yml
site.dev.yml

docker/dockerfiles/site/
app
app.prod

docker/.config/
.env.site

mx add site --recipe astro --domain mechcrate.localhost

templates/recipes/astro/recipe.json
options · placeholders · init_app · directories · templates

resolve + expand
flags beat manifest defaults
SERVICE_NAME=site · DOMAIN=mechcrate.localhost

scaffold
init_app (skip_if_exists) · create declared directories

router labels written
traefik.enable · Host(mechcrate.localhost) → 4321 · devmesh-traefik

make dev s=site
baseline + dev override, up

http://mechcrate.localhost

Recipe install flowRunning mx add site with the astro recipe loads that recipe's manifest, resolves its options and expands its placeholders, optionally runs the recipe's init command to scaffold the framework app and create the declared directories, renders the template files into the project as the app source, the compose baseline and dev override, the dockerfiles and the service env file, writes Traefik routing labels for the chosen domain, and prints next steps ending in make dev, which brings the service up behind the router.

files landed

apps/site/**
app source
+ health route

docker/compose/
site.yml
site.dev.yml

docker/dockerfiles/site/
app
app.prod

docker/.config/
.env.site

mx add site --recipe astro --domain mechcrate.localhost

templates/recipes/astro/recipe.json
options · placeholders · init_app · directories · templates

resolve + expand
flags beat manifest defaults
SERVICE_NAME=site · DOMAIN=mechcrate.localhost

scaffold
init_app (skip_if_exists) · create declared directories

router labels written
traefik.enable · Host(mechcrate.localhost) → 4321 · devmesh-traefik

make dev s=site
baseline + dev override, up

http://mechcrate.localhost

mx add reads a recipe manifest, expands its placeholders, scaffolds the framework app, lands the compose, dockerfile and env files, and writes the router labels. Then make dev.

The sources are Mermaid flowcharts. Change one, then re-render and commit both:

Terminal window
cd site/apps/site
npm run diagrams # renders light + dark SVG pairs
npm test # fails if a source drifted from its rendering

Rendering needs a Chromium build (npx playwright install chromium); nothing else does. astro build only inlines the committed SVGs, so CI and the deploy never touch a browser.