Exaloop CLI
The exaloop CLI builds Codon projects, runs their tests, and packages applications
for deployment. It accepts Codon compiler commands and adds project configuration,
SDK selection, profiling, and optimization. Its Python environment is bundled with
the distribution; native applications do not require that environment to run.
For a first working project, follow the quickstart. Use this page to look up the compiler commands, SDK registration, project configuration, server builds, Python extensions, SDK tools, and testing and packaging.
Install
The installation guide covers the tarball supplied by Exaloop. Once installed, the CLI and its SDK registrations are ready to use:
exaloop --help
exaloop plugin list
Codon Compatibility
Replace codon with exaloop for ordinary compiler commands:
exaloop run -release program.codon argument1 argument2
exaloop build -release -o program program.codon
exaloop build -llvm program.codon
exaloop doc src/
exaloop jit
exaloop jupyter connection.json
Codon's -plugin and other compiler options remain available. Use
exaloop build --help for compiler help, or exaloop doctor to see which
compiler and SDKs will be used.
Wrapper options precede the command. Nothing following run is reparsed as
an Exaloop option, so application arguments such as --with remain intact.
exaloop --codon "$HOME/.codon/bin/codon" run program.codon
exaloop --with data --with kafka build -release processor.codon
exaloop --dry-run --with kafka build consumer.codon
--verbose prints the command before executing it. --dry-run prints the
planned commands without creating files or invoking the compiler. Avoid passing
credentials in command arguments, especially with verbose logging; use the
application's environment or a protected runtime configuration instead.
Register SDKs
Skip manual registration for SDKs supplied by your active all-SDK distribution.
Register trusted, built or installed SDK directories containing plugin.toml:
exaloop plugin add kafka --path /opt/exaloop/kafka
exaloop plugin add data --path /opt/exaloop/data
exaloop plugin list
exaloop plugin inspect kafka
exaloop plugin remove kafka
Registration gives an installed SDK a name; it does not download or copy it.
Select that name with --with or add it to a project's plugins list. Use
--replace to update a registration after moving an SDK. Removing a registration
leaves its files intact.
The CLI checks selected SDKs before compilation, but they must still come from
a trusted source and match your compiler. Run exaloop doctor after changing
your toolchain.
Application and Server Builds
exaloop --kind postgres-udf build -release functions.codon -o dist/functions.so
exaloop --kind duckdb-extension build functions.codon -o dist/functions.duckdb_extension
exaloop --kind redis-module build commands.codon -o dist/commands.so
exaloop --kind mysql-udf build functions.codon -o dist/functions.so
exaloop --kind kafka-consumer build -release consumer.codon -o dist/consumer
| Kind | Automatically selected SDK | Output |
|---|---|---|
native | None | Codon's selected output format |
python-extension | None | Importable CPython module; an installable wheel when packaged |
aws-lambda | aws-lambda | Native handler; Linux container build context and SAM template when packaged |
duckdb-extension | duckdb | DuckDB extension with native metadata |
postgres-udf | postgres | Shared library, SQL, and extension control file |
mysql-udf | mysql | Shared library, registration and removal SQL |
redis-module | redis | Redis-loadable module |
kafka-producer | kafka | Native executable |
kafka-consumer | kafka | Native executable |
kafka-processor | kafka | Native executable |
Server builds default to release mode and Python numerics. They accept -debug,
-release, -numerics=py|c, -o, and repeated -plugin arguments. Native and
Kafka builds keep Codon's defaults.
A successful server build produces a library, not a running service. Follow the database's guide to install the library and register its functions; the build command does not change a server.
For AWS Lambda, use a named aws-lambda target.
run event.json invokes a compiled handler locally; package requires a matching
Linux environment and bundles its runtime dependencies automatically.
Python Extensions
Exaloop compiles and links Codon modules for Python without a setup.py, Python
headers, or setuptools in the destination environment. Start with an exported,
typed add(left: int, right: int) -> int function:
exaloop init fastmath --kind python-extension --name fastmath
cd fastmath
python3 -m venv .venv
exaloop --target fastmath package --python .venv/bin/python
.venv/bin/python -m pip install packages/fastmath/*.whl
.venv/bin/python -c 'import fastmath; print(fastmath.add(20, 22))'
package builds the module, collects its non-system native runtime dependencies,
rewrites their loader paths, and writes a wheel under packages/NAME/. Runtime
bundling is automatic for Python extensions. Installing the wheel does not
require Exaloop or Codon. Each package destination must be new; use
--output packages/fastmath-v2 when packaging another version.
For development, build only the importable module:
exaloop --target fastmath build --python .venv/bin/python
PYTHONPATH=dist/fastmath .venv/bin/python -c 'import fastmath; print(fastmath.add(20, 22))'
Exaloop generates the interpreter's ABI filename, such as
fastmath.cpython-312-darwin.so. For this kind, output and build -o specify
an output directory, defaulting to dist/NAME/ for a named target and dist/
otherwise. Dotted modules such as acme.fastmath create matching namespace-package
directories. A standalone build is also supported:
exaloop --kind python-extension build fastmath.codon --python .venv/bin/python -o dist
Configure persistent module and wheel settings in the target:
[targets.fastmath]
kind = "python-extension"
source = "fastmath.codon"
codon_args = ["-release"]
[targets.fastmath.options]
module = "fastmath"
distribution = "fastmath"
version = "0.1.0"
python = ".venv/bin/python"
module defaults to the source basename, distribution to its top-level module,
and version to 0.1.0. python defaults to Exaloop's own interpreter, which may
be different from your application's Python. Both build --python and
package --python override it. Build accepts --module, -debug, -release,
-numerics=py|c, and repeated -plugin arguments. Project plugins and wrapper
--with selections work as usual. Use doctor with the target selected to check
the configured interpreter, linker, and Codon runtime.
Build separately for each GIL-enabled CPython version and architecture. Supported
hosts are macOS and Linux with CPython 3.9 or newer. Wheels are platform-specific,
not abi3, universal2, or manylinux wheels; the build host's OS/libc baseline and
SDK requirements still apply. Codon source is compiled for a generic CPU on the
host architecture. Native libraries loaded dynamically need an explicit
package --runtime-library PATH; Python dependencies and application data are
managed separately. Distribution license inventories are included when building
with an Exaloop distribution; review redistribution requirements for custom
toolchains and additional libraries. See production deployment.
Projects
Create a starter project, without overwriting existing files:
exaloop init events --kind kafka-consumer
exaloop --project events --target app build
exaloop --project events --target app run localhost:9092 readers events 1000
This creates a consumer project and runs it against the events topic until it
has processed 1,000 records. Create the topic first and adapt the connection
settings for your cluster. The Kafka guide explains
processing, commits, and recovery.
init supports every build kind in the table above. Use --name to choose the
target and source name; server targets need lowercase identifiers such as
scoring_udf.
Projects use exaloop.toml, discovered in the current directory or its ancestors:
[targets.scoring]
kind = "postgres-udf"
source = "scoring.codon"
plugins = ["data"]
codon_args = ["-release"]
[targets.scoring.options]
schema = "analytics"
version = "0.1.0"
[targets.events]
kind = "kafka-consumer"
source = "events.codon"
codon_args = ["-release"]
Use --project DIRECTORY_OR_FILE to select a project, or --no-project to
disable discovery. Targets are never selected implicitly. Relative project
paths are resolved from the manifest's directory; named-target commands run
there as well. Project plugin paths override user registrations.
Compiler selection is --codon, then project toolchain.codon, then
EXALOOP_CODON, then codon on PATH. --stdlib overrides toolchain.stdlib;
otherwise an inherited CODON_PATH remains intact. Always select a compiler,
standard library, and runtime from the same distribution.
Target output defaults to dist/NAME/NAME, with the appropriate server suffix.
Python extensions instead use the output-directory convention described above.
Set output in the target to override it. For build, command-line -o,
-debug/-release, and -numerics override their target defaults. Other Codon
flags follow Codon's own combination rules. For a named-target run, arguments
after run are application arguments; compiler flags belong in codon_args.
Host settings belong in the target's options table:
| Kind | Available settings |
|---|---|
| DuckDB | platform, version |
| PostgreSQL | schema, version |
| MySQL | mysql_config |
| Python extension | module, python, distribution, version |
These settings do not cross-compile code. In particular, DuckDB's platform
sets extension metadata; it must describe the platform actually being built.
PostgreSQL uses the matching host tooling recorded in its SDK.
SDK Tools
Run the SDK's generators and builders through the same CLI:
exaloop avrogen event.avsc event.codon
exaloop protoc -Ischemas --codon_out=generated schemas/event.proto
exaloop profdata -o merged.profdata capture.profraw
exaloop --with data --dry-run avrogen event.avsc event.codon
exaloop tool --list
exaloop --with data tool --list
Create Protobuf output directories before invoking protoc. The CLI locates
the generator and standard schemas in the Data SDK for you.
| Command | Default SDK | Standalone tool |
|---|---|---|
avrogen | data | bin/avrogen-codon |
protoc | data | Bundled protoc, with Codon plugin discovery |
protoc-gen-codon | data | Raw binary Protobuf generator protocol |
profdata | ext | exaloop-profdata |
duckdb-build | duckdb | Complete DuckDB build.py interface |
postgres-build | postgres | Complete PostgreSQL build.py interface |
mysql-build | mysql | Complete MySQL build.py interface |
redis-build | redis | Complete Redis build.py interface |
Use --with NAME to select another SDK alias. Arguments after the command belong
to that tool, including --help. The direct database builders use
--mode release; the higher-level --kind KIND build uses Codon's -release.
The generic dispatcher also runs tools included in a selected SDK or a tool specified by an explicit path:
exaloop --with data tool avrogen-codon event.avsc event.codon
exaloop --with redis tool build.py --help
exaloop tool /absolute/path/to/native-tool --help
Tools run from the project directory when a project is selected, or from the
current directory otherwise. Tool execution has the same permissions as the CLI;
--dry-run shows the planned command without executing it.
Diagnose, Test, Package
For function timings and memory measurements, see the
profiling guide. exaloop --profile run ... enables capture;
--profile=memory requests memory statistics without XRay.
exaloop doctor
exaloop --target scoring doctor --json
exaloop doctor --optimization --optimizer-sdk /path/to/sdk/ext --json
exaloop --target scoring test
exaloop --target scoring package --output packages/scoring-v1
doctor checks your compiler and SDKs, including the host tools needed by a
server target. Resolve its errors before building. For optimization, it also
compiles and runs a small PGO check; the PGO walkthrough
then takes you through optimizing your own program.
test first builds a named target, then runs its explicit test argument array
without a shell. For example, set test = ["python3", "tests/check.py"] inside the
target table. The command receives EXALOOP_ARTIFACT with the absolute output
path, and arguments after test -- are forwarded to it. Test commands are trusted
project code; no database or Kafka service is started automatically.
package builds a target and collects its output, checksums, and deployment notes
in a new directory. By default it includes build artifacts only, not their
runtime libraries. Review generated SQL before deployment; PostgreSQL's
unversioned SQL still refers to the local build path.
Python-extension targets are the exception: package produces an installable
wheel and always bundles its native runtime dependencies, as described
above.
For runtime-only packaging, request it explicitly:
exaloop --target events package --bundle-runtime --output packages/events-v1
This includes the native libraries needed by the application. The runtime-package guide explains target requirements and what you still need to supply. Packaging does not deploy the application or install database functions.
The distribution workflow also supports verified release installation, rollback, and project locks. Use a project lock when a team needs to build with the same distribution.
For installation or execution problems, see troubleshooting.