Files
soleprint/docs/data/en/export.md
2026-08-11 07:30:27 -03:00

5.5 KiB

Export / Compile

Soleprint's source tree is not what runs. build.py compiles the framework plus a room's configuration into a self-contained instance under gen/<room>/, and that directory is what a container boots, what deploy.sh rsyncs, and what the cluster manifests point at.

Everything below is a make target, and every target is one script in ctrl/. The logic lives in the scripts, never in the Makefile.

make build            # cfg/standalone -> gen/standalone
make build sample     # cfg/sample     -> gen/sample
make start            # run it

The targets

Command Runs Does
make build [<room>|all|models] ctrl/build.sh compile a room into gen/
make dist [<room>] ctrl/dist.sh compile just the plexus UIs to single files
make docs [serve|graphs] ctrl/docs.sh serve the docs, or re-render the diagrams
make start [<room>] [-d] ctrl/start.sh run a built room's compose stack
make stop [<room>] ctrl/stop.sh stop it
make cluster [up|down|status] ctrl/cluster.sh the shared kind cluster
make component [list|publish|sync|watch|diff] ctrl/spr.py publish a distributable component
make deploy ctrl/deploy.sh rsync gen/standalone to the server and restart

Bare words pass straight through, so make build sample becomes ctrl/build.sh sample. Anything starting with a dash would be eaten by make itself, so those go through ARGS:

make deploy    ARGS="--build"
make component ARGS="publish soleprint-ui /tmp/out --dist"

What a build does

python build.py --cfg <room> runs these in order:

  1. Clean gen/<room>/. A build is not incremental — a stale file left behind is worse than a slow build.
  2. Copy the framework. main.py, run.py, index.html, Dockerfile, requirements.txt, dataloader/, common/, and the three systems (artery/, atlas/, station/).
  3. Merge the room (copy_cfg). cfg/<room>/config.json lands in cfg/, data/*.json in data/, and anything under cfg/<room>/soleprint/artery|atlas|station/ is merged over the framework copy — which is how a room adds its own vein, shunt, tool or generator without forking the tree.
  4. Compose cabinets. The dependency containers the room declared in data/cabinets.json are merged into its docker-compose.yml. See Cabinets.
  5. Export plexuses. Each plexus the room declared in data/plexuses.json is compiled to a single self-contained index.html — theme, data and diagrams inlined, so it opens with no server. See Plexuses.
  6. Generate models. modelgen reads the room's config.json and writes models/pydantic/__init__.py.
  7. Render k8s (optional). When the room's config enables it, soleprint/ctrl/k8s/ writes manifests and lifecycle scripts.

What comes out

A standalone room is a flat instance:

gen/standalone/
  run.py  main.py  Dockerfile  docker-compose.yml
  artery/  atlas/  station/  common/
  cfg/config.json
  data/*.json
  models/pydantic/
  plexuses/<name>/index.html    # one file each, opens with no server

A managed room — one that wraps an existing application — is three folders instead, because soleprint sits beside the app rather than containing it:

gen/<room>/
  <app>/        the application's repos, plus its ctrl scripts
  link/         bridge code between the two
  soleprint/    the instance, exactly as above

build.py picks between them on whether the room's config.json has a managed block. gen/ is gitignored in full: it is an artifact, and the way to change it is to change cfg/<room>/ and rebuild.

Distributing components

Rooms are compiled; components are published. registry.json lists what can be shipped out of this repo on its own:

make component                                            # list
make component ARGS="publish soleprint-ui /tmp/out --dist"
make component ARGS="watch soleprint-ui ../unt/ui/framework"

--dist copies only the built bundle — dist/** plus package.json, README.md and LICENSE — rather than the source. It refuses to publish an empty dist/, because a component whose bundle was never built is the failure that shows up later as a container that starts and renders nothing:

no build at soleprint/common/ui
build it first: cd soleprint/common/ui && pnpm build

Each publish leaves a .spr stamp in the destination recording name, version, type, source and mode, so a copy can say where it came from.

Deploying

make deploy ARGS="--build"      # rebuild, sync, restart
make deploy ARGS="--sync-only"  # sync, leave it running

deploy.sh rsyncs gen/standalone/ and runs docker compose up -d --build on the far side. .env is excluded, so server secrets stay on the server.

Running without building

python run.py from soleprint/ serves every subsystem on one port (12000 by default) straight from the source tree. It is for developing the framework itself; a room's cfg/config.json does not exist there, so the landing pages fall back to their defaults. Rooms use docker.

Diagrams

The .dot sources under docs/graphs/ carry structure; the palette lives in docs/graphs/themes/*.gvpr and is applied at render time, so one source renders in every theme.

make docs graphs           # every graph, every theme
make docs graphs lucid     # one theme

<name>.svg is the dark default the docs link to; other themes write <name>.<theme>.svg. See Themes.