Build & tooling commands¶
just-makeit build [dir]¶
Build the C extensions and package a wheel.
Configures CMake (if not already done), builds the C extensions, then runs
pip wheel via just-buildit.
Must be run from a project directory containing pyproject.toml.
just-makeit test¶
Build (if needed), then run all tests.
- CTest runs the C tests in each object's
tests/directory. - pytest (or
unittest, depending on how the project was scaffolded) runs the Python tests insrc/.
just-makeit dry-run¶
Show what would be compiled and packaged without running any build steps.
Output includes the list of C source files and the full cmake configure
command that just-makeit build would invoke.
make coverage¶
Generate C and Python coverage HTML reports. Run from the project root after scaffolding with just-makeit.
Requires lcov/genhtml for the C side and pytest-cov for Python:
sudo apt-get install lcov # Debian/Ubuntu
brew install lcov # macOS
sudo pacman -S lcov # Arch/CachyOS
uv add --dev pytest-cov
What it does:
- Compiles a separate
build/cov/tree with-DCMAKE_C_FLAGS="--coverage -O0"— the Release build inbuild/is untouched. - Runs CTest against the coverage binary.
- Collects
.gcdafiles withlcov --capture, strips system and test paths, and rendersdocs/coverage/c/index.htmlviagenhtml. - Runs
pytest --cov=<package> --cov-report=html:docs/coverage/python.
Both reports land under docs/ (already in .gitignore).
make docs¶
Build both C and Python API documentation. Run from the project root.
Requires doxygen for the C side and zensical + mkdocstrings-python for Python:
sudo apt-get install doxygen # Debian/Ubuntu
brew install doxygen # macOS
uv add --dev zensical mkdocstrings-python
C API — Doxygen
Reads Doxyfile (generated by just-makeit, edit freely) and produces
docs/doxygen/html/index.html. Covers every *.h and *.c under
native/inc/ and native/src/. JavaDoc-style /** @brief ... */ comments
in your C source appear automatically.
Python API — Zensical + mkdocstrings
Reads zensical.toml (generated by just-makeit) and produces site/index.html.
The generated docs/api.md page uses a single mkdocstrings directive:
mkdocstrings introspects the compiled extension and renders docstrings from
PyDoc_STR(...) in the C binding.
Serve live with hot-reload:
just-makeit perf¶
Upgrade an existing project to use performance annotations without overwriting any user code. Must be run from the project root.
Writes native/inc/jm_perf.h, adds #include "jm_perf.h" to each object
header, and replaces static inline with JM_FORCEINLINE JM_HOT on step().
Records perf = true in just-makeit.toml so future object and add
commands inherit it. Safe to run on a project with a filled-in step().
Idempotent.
See Performance annotations for the full macro reference and
JM_DEFINE_STEPS documentation.
just-makeit apply¶
Reconcile the generated files with just-makeit.toml. Use this after
hand-editing the manifest, after git pull, or to materialize any files
missing from a checkout. Must be run from the project root.
apply follows the sacred / glue contract:
| File | On every apply |
|---|---|
<comp>_ext.c |
Glue — fully regenerated from the manifest. |
src/<pkg>/<comp>.pyi |
Glue — fully regenerated. |
CMakeLists.txt |
Glue — fully regenerated. |
<comp>_core.h |
Mixed — a missing method/property declaration is injected; the inline step() body and the state struct are sacred and never re-rendered. |
<comp>_core.c |
Sacred — never spliced or re-rendered once it exists. steps()/lifecycle bodies are yours. |
So editing the manifest always propagates to the glue, and apply injects any
missing method/property declaration into _core.h. The struct and inline
step() stay sacred. Changing a signature in TOML — or adding a state
field — is structural: rebuild the body from the manifest with
jm regenerate (or jm add, which is regenerate specialized for state). A
new method or computed property is additive instead — jm method /
jm property inject a declaration and append a fresh stub.
just-makeit regenerate <component>¶
The deliberate-refresh half of the sacred/glue contract. Deletes every file
the component owns, then re-runs jm apply to rebuild them all from the
manifest. The manifest itself is left untouched (unlike jm remove). Works
for standalone and module objects. Must be run from the project root.
git stash # regenerate discards hand-written bodies
just-makeit regenerate engine
just-makeit regenerate engine --force # skip the confirmation
Because the rebuilt _core.c comes straight from the manifest, any
hand-written body in <comp>_core.c is discarded — git stash or commit
first. A single confirmation guards the deletion; --force skips it.
| Flag | Description |
|---|---|
--force |
Skip the deletion confirmation. |
just-makeit ci [--provider NAME]¶
Generate a continuous-integration workflow that builds the project and runs
its tests (make && make test), so a scaffolded project is CI-green as fast
as it builds and tests locally. Must be run from the project root.
just-makeit ci # GitHub Actions: .github/workflows/ci.yml
just-makeit ci --provider woodpecker # Woodpecker: .woodpecker.yml
just-makeit ci --force # overwrite an existing workflow file
The generated workflow installs the build dependencies and runs the same
build-and-test the test target drives locally. If the
project enabled pytest, the dependency step also installs the Python test
requirements; otherwise it stays C-only.
| Flag | Description |
|---|---|
--provider NAME |
github (default → .github/workflows/ci.yml) or woodpecker (→ .woodpecker.yml). |
--force |
Overwrite the workflow file if it already exists. |
just-makeit config [key value]¶
Show or edit the project configuration stored in just-makeit.toml.
Must be run from the project root.
Example output
project: my_project
version: 0.1.0
engine:
rate: double = 1.0
order: int = 4
parser:
depth: int = 8
strict: int = 1
Supported keys
| Key | Description |
|---|---|
version |
Project version string stored in just-makeit.toml. |
just-makeit bind <component>¶
Synthesise <comp>_ext.c and <comp>.pyi by reading <comp>_core.h directly,
without consulting just-makeit.toml. This is the "point at your C and get
Python" path. Must be run from the project root.
just-makeit bind engine # synthesise engine_ext.c from engine_core.h
just-makeit bind engine --check # exit 1 if the generated binding differs from the file on disk
jm bind parses the header for the standard just-makeit naming conventions
(<comp>_state_t, <comp>_create, <comp>_step, scalar field defaults from
the reset body) and renders the binding from the same context builders the
manifest-driven flow uses — so a bound _ext.c is byte-identical to a
scaffolded one.
Current scope: the simple processor shape — a state struct with scalar
fields, a <comp>_create() taking those fields in order, and a scalar-in /
scalar-out inline step(). If the header doesn't match that shape the parser
raises an error before touching any files.
--check as a CI gate: run jm bind <comp> --check in CI to ensure
the committed _ext.c never silently drifts from the header it was generated
from. Green means byte-identical; non-zero exit means regenerate and commit.
Shapes not yet supported (see roadmap): methods, init_params, opaque state, variable-output, result-structs.
| Flag | Description |
|---|---|
--check |
Diff the synthesised binding against the file on disk; exit 1 if they differ. |
just-makeit status¶
Show which files in the project tree have drifted from what jm apply would
generate — a read-only drift report. Must be run from the project root.
Prints a table of files with one of three states:
| Status | Meaning |
|---|---|
OK |
File matches what the manifest would generate. |
MISSING |
File is declared in the manifest but does not exist on disk. |
STALE |
File exists but differs from the manifest-generated content. |
status never writes anything; it is always safe to run. Use it to confirm
that jm apply is a no-op before a release, or to see what changed after a
manual edit to just-makeit.toml.
just-makeit script¶
Print a shell script to stdout that fully reconstructs the current project from scratch via CLI commands. Must be run from the project root.
Reads just-makeit.toml and emits one command per scaffold step in the
correct order: new → module → object → method → property →
function. The output is a valid shell script that, when run from the
parent directory, produces an identical just-makeit.toml.
Note: --impl / --replace are not stored in just-makeit.toml (the
lifted body is patched directly into the generated files), so they are not
reproduced. Implemented function and step bodies are preserved in your C
source files and are unaffected.
Example
Given a project with two objects, just-makeit.toml looks like:
[project]
name = "dsp_toolkit"
version = "0.1.0"
build = "cmake"
[gain]
arg_type = "float"
return_type = "float"
[[gain.state]]
name = "gain"
type = "float"
default = "1.0"
[ema]
arg_type = "float"
return_type = "float"
[[ema.state]]
name = "alpha"
type = "double"
default = "0.1"
[[ema.state]]
name = "prev"
type = "float"
default = "0.0"
just-makeit script produces:
#!/usr/bin/env sh
# Reconstructed from just-makeit.toml
just-makeit new dsp_toolkit
cd dsp_toolkit
just-makeit object gain \
--state gain:float:1.0 \
--arg-type float
just-makeit object ema \
--state alpha:double:0.1 \
--state prev:float:0.0 \
--arg-type float
Running that script from the parent directory recreates the project structure
and an identical just-makeit.toml.