Skip to main content

xcl for Python

XCL, the declarative configuration language, for Python. The package drives the same engine Go programs use, bundled in the wheel as a small program that the package runs as a subprocess, the same way on every platform, Alpine included, with the same API and the same results everywhere. A Python program validates, diffs, applies, loads and destroys configuration exactly as a Go program does, uses the same Go plugins, and adds its own Python functions to configuration.

Install

pip install xcl-lang

The distribution is xcl-lang on PyPI and is imported as xcl. No Go toolchain and no C compiler are needed: each wheel bundles the engine program, xcl-core, for its platform, and contains no compiled extension, so one wheel per platform serves every CPython 3.10 and later. Wheels are published for

  • Linux x86-64 and arm64 on glibc 2.28 or later (manylinux_2_28);
  • Linux x86-64 and arm64 on musl (musllinux_1_2), Alpine included;
  • macOS 11 or later, x86-64 and arm64;
  • Windows x86-64 and arm64.

The engine runs as a subprocess on every platform. import xcl starts nothing: the engine starts the first time a configuration is used, is shared by every configuration in the process, and stops on its own when the last configuration is closed or the interpreter exits. It never outlives its host, even one that is killed, and its diagnostics go to your standard error. The package version is the xcl release it bundles, and it refuses to run against any other engine.

Getting started

A Python program describes its entity types as dataclasses, registers them and any plugins on a registry, and creates a configuration. This program uses the Docker example plugin, published as a signed GitHub release, to create a network and a container:

from dataclasses import dataclass

import xcl

# the jumppad-labs release key, from https://xcl.dev/keys/jumppad-labs-releases.asc
RELEASE_KEY = open("jumppad-labs-releases.asc").read()


@xcl.entity("settings")
@dataclass
class Settings(xcl.Resource):
    image: str
    replicas: int = 1


github = xcl.GitHubRegistry(trusted_keys=[RELEASE_KEY])
github.register_plugin("jumppad-labs/xcl-plugin-docker", "v0.2.0")

local = xcl.LocalRegistry()
local.register_type(Settings)

with xcl.Config(registries=[local, github], state_path=".xcl") as cfg:
    cfg.apply("./infra")

    settings = cfg.find(Settings, "settings.web")
    print(settings.image, settings.replicas)

    network = cfg.find(None, "docker.network.main")
    print(network.address, network.subnet, network.docker_id)

    cfg.destroy()

with the configuration in infra/main.xcl:

settings "web" {
  image = "nginx:1.27-alpine"
}

docker "network" "main" {
  subnet = "10.73.0.0/24"
}

docker "container" "web" {
  image = settings.web.image

  network {
    name = docker.network.main.meta.name
  }
}

apply runs to completion before returning; other Python threads keep running while it works. find returns an instance of the registered class for a type the program registered, and an xcl.Entity, a read-only mapping with .meta and .address, for a plugin's type: network.subnet and network["subnet"] both read an attribute.

Entity types

A dataclass decorated with @xcl.entity(type), or @xcl.entity(type, subtype) for a type written database "postgres" "main" {}, describes a block type through its annotations:

@dataclass
class Volume:
    source: str
    name: str = xcl.field(label=True, default="")   # the block's name, volume "data" {}


@dataclass
class Listener:
    port: int
    name: str = xcl.field(label=True, default="")


@xcl.entity("app")
@dataclass
class App(xcl.Resource):
    image: str                                       # required
    replicas: int = 2                                # optional, with a default
    region: str | None = None                        # optional
    password: xcl.Sensitive[str] | None = None       # sensitive: masked in events and state
    endpoint: xcl.Computed[str] = None               # set by the provider, never in configuration
    health: Health | None = None                     # a nested block
    volume: list[Volume] = xcl.field(default_factory=list)        # a list of blocks, in order
    listener: dict[str, Listener] = xcl.field(default_factory=dict)  # named blocks, keyed by name

Configuration is checked against the class as it is against a Go type: a missing required field, a computed field set in configuration or an unknown attribute is reported with its file and line. A looked-up Sensitive value prints as (sensitive) and reveal() returns None; real values never leave the engine through a lookup.

Functions

A Python function registered on a local registry is callable from configuration by name. Its annotations give its signature: str, bool, int and float parameters and result, and lists and dicts of those.

def slugify(title: str) -> str:
    return title.lower().replace(" ", "-")

local.register_function(slugify)
app "web" {
  name = slugify("My App")
}

The result is filled in exactly like a built-in function's, and a result computed from a sensitive argument is held as sensitive. A name a builtin or another function already uses raises xcl.FunctionNameClashError when the configuration is created.

Variables, state and events

cfg = xcl.Config(
    registries=[local],
    variables={"region": "us"},                # variable.region in configuration
    state_path="./.xcl",                        # or state_store=MyStore()
    state_mask=xcl.mask.aes256gcm(key),         # encrypt sensitive values in state
    on_event=lambda e: print(e.operation, e.phase, e.resource_id),
    event_data="processed",                     # carry the entity on events, masked
)

A custom state store is any object with load() -> list[bytes], save(records: list[bytes]), exists() -> bool and clear(); it receives each entity's JSON record. The engine's events arrive at on_event as xcl.Event, with the same data levels and masking a Go program has; event.entity() hydrates the entity an event carries.

Lookups: entities(), entity_count(), find(cls, address), find_by_type(cls, *path), find_one(cls, *path), all(cls), outputs() and encode_saved_entity(record). Pass None as the class to get the registered class, or an xcl.Entity for an unregistered type.

Asyncio

xcl.aio.Config offers every operation and lookup as an awaitable that never blocks the event loop. Registered functions, the event handler and the state store's methods may be async def:

import asyncio
import xcl.aio


async def slugify(title: str) -> str:
    return title.lower().replace(" ", "-")


async def main():
    local = xcl.LocalRegistry()
    local.register_type(App)
    local.register_function(slugify)

    async with xcl.aio.Config(registries=[local], state_path=".xcl", on_event=on_event) as cfg:
        await cfg.apply("./infra")
        web = await cfg.find(App, "app.web")
        print(web.name)


async def on_event(event):
    print(event.operation, event.phase, event.resource_id)


asyncio.run(main())

The engine is polled from a thread, and each task it posts runs as an asyncio task, so a web service keeps answering requests during a long apply. Cancelling the task that awaits an operation cancels the engine's work: no further provider call starts, the progress made is saved, and asyncio.CancelledError is raised once the engine has stopped.

Errors

Every failure is an exception under xcl.Error, one class per kind of error, carrying message, details and causes: xcl.NotFoundError, xcl.NotUniqueError, xcl.ConfigError (whose problems list each problem with its file, line and column), xcl.PluginVerificationError, xcl.FunctionNameClashError, xcl.CancelledError and so on. A plugin release whose signature does not verify against the trusted keys is refused.

Two errors concern the engine itself. xcl.EngineNotFoundError is raised on first use when the installed package does not hold its engine, and names where the engine program and the shared library were expected. xcl.EngineExitedError is raised by every call waiting on the engine if it exits unexpectedly, carrying its exit status, or the signal that ended it, in details and returncode. Your program carries on: the next configuration starts a new engine, and a configuration created before the exit raises xcl.EngineExitedError again.

Forking

A forked child creates its own configuration. import xcl starts nothing, so forking before using the package is unaffected, and a child forked after the parent used it simply creates a new xcl.Config, which starts the child's own engine. Using a configuration created before the fork raises xcl.ForkedProcessError in the child, since its engine belongs to the parent. With that one rule, gunicorn's preload_app, celery's prefork pool and multiprocessing with the fork start method all work.

Development

The package is built against a checkout of xcl, XCL_SRC (by default ../xcl): make protos generates the message classes from its proto/ with protoc, make engine builds the engine program into xcl/_bin with Go and no C compiler, make plugins builds the fixture plugins the integration tests use, and make test runs the suite.

The engine can also be built as a shared library and loaded into the Python process instead, which keeps the in-process route tested: make libxcl builds it into xcl/_lib with Go and a C compiler, pip install -e '.[test,inprocess]' adds cffi to load it (the standard library's ctypes is used without it), and XCL_TRANSPORT=inprocess selects it. Without the variable the engine program runs even when the library is present, and a missing engine is reported, never replaced by the other form. With the in-process route the forking rule is stricter, since the engine is a Go runtime in the process: use the spawn start method, or create the configuration after the fork, in gunicorn's post_fork hook or celery's worker_process_init signal. PARITY.md lists every Go operation and lookup with its Python equivalent. The distribution is published as xcl-lang, since the name xcl on PyPI belongs to another project; the import name is xcl.

Licence

Apache-2.0, as xcl.

Metadata

Release files for xcl-lang 0.5.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for xcl-lang 0.5.3
File Size Uploaded
xcl_lang-0.5.3.tar.gz 103.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for xcl-lang 0.5.3
File
xcl_lang-0.5.3-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
xcl_lang-0.5.3-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
xcl_lang-0.5.3-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details
xcl_lang-0.5.3-py3-none-musllinux_1_2_aarch64.whl Python 3 none Linux musl 1.2+ ARM64 Details
xcl_lang-0.5.3-py3-none-manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64 Details
xcl_lang-0.5.3-py3-none-manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64 Details
xcl_lang-0.5.3-py3-none-macosx_11_0_x86_64.whl Python 3 none macOS 11.0+ x86-64 Details
xcl_lang-0.5.3-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 59.4 MB

Release files / xcl_lang-0.5.3.tar.gz

Download URL xcl_lang-0.5.3.tar.gz
Size 103.0 kB
Tags Source
SHA-256 checksum
How to use checksums
c898efcb67f77d29c97ad732ca617bf993685ef4aa5280957e7171a8ce04d8f6
BLAKE2b-256 checksum
How to use checksums
eb5b9b8d70d4b4bdd2d8ab15036070a9a18c3a0a58489bc510f4b3e052578e1e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / xcl_lang-0.5.3-py3-none-win_arm64.whl

Download URL xcl_lang-0.5.3-py3-none-win_arm64.whl
Size 7.1 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
a80634433454412aaccdf4ad69fcb56d6c4f22ce82d8af460266180fe275ece9
BLAKE2b-256 checksum
How to use checksums
85e0f2a143d0b4f40a8726b77074540e426368c9617ef74f7fe2eb974e465c2a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / xcl_lang-0.5.3-py3-none-win_amd64.whl

Download URL xcl_lang-0.5.3-py3-none-win_amd64.whl
Size 8.0 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
bbcdfa10e0e900acb66d3dc1d1154c70e89baea7f75feeb69fa896e746169472
BLAKE2b-256 checksum
How to use checksums
412c34a7b23550bbb47699ed4d0cb56a1eeb5793ecf1f702e4190963fa187185
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / xcl_lang-0.5.3-py3-none-musllinux_1_2_x86_64.whl

Download URL xcl_lang-0.5.3-py3-none-musllinux_1_2_x86_64.whl
Size 7.7 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
8ec15ee5cfd8a57fe7448e76a96bb95a8e373b16b09504917cda2cabce69070e
BLAKE2b-256 checksum
How to use checksums
7bc1db6575d9b6ffcff8fe3c5959123bc2a4617a4e430e88719df0040a99bea5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / xcl_lang-0.5.3-py3-none-musllinux_1_2_aarch64.whl

Download URL xcl_lang-0.5.3-py3-none-musllinux_1_2_aarch64.whl
Size 6.9 MB
Tags Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
febb70c243d45abf444a058df318fb059696720e7ed7479602dcba59b8dc2f6b
BLAKE2b-256 checksum
How to use checksums
f06d1d12c4b96d50603123ec2df9cdd6d915c8748b09cc4c7b064e5feeeb6f53
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / xcl_lang-0.5.3-py3-none-manylinux_2_28_x86_64.whl

Download URL xcl_lang-0.5.3-py3-none-manylinux_2_28_x86_64.whl
Size 7.7 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
457c0d0daaa0dd737294622bec25cb1df700950232a336b3a96d5194b92fedce
BLAKE2b-256 checksum
How to use checksums
0ca31ef41599ae6c1b1a344b6fb6028043b5f578da04ffde2b3d6674ea362276
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / xcl_lang-0.5.3-py3-none-manylinux_2_28_aarch64.whl

Download URL xcl_lang-0.5.3-py3-none-manylinux_2_28_aarch64.whl
Size 6.9 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
b11b67551cb828241220c1ff56c1693354fd70e9213e4e0e25aeac65fe538f91
BLAKE2b-256 checksum
How to use checksums
e64176850f2c39dd17f080a10f6c51b6f22dbd176e5529cec3a4b2e132460ce4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / xcl_lang-0.5.3-py3-none-macosx_11_0_x86_64.whl

Download URL xcl_lang-0.5.3-py3-none-macosx_11_0_x86_64.whl
Size 7.8 MB
Tags Python 3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
d99e8f726e712a77826c605d3ed4cdd2bc20fb3f090b0b7d1b6d5ce75df097d6
BLAKE2b-256 checksum
How to use checksums
5663f3374ba7bbcb7fba8b26e85af3c6aef3158f6f3ce6981b1816fb5a90f751
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release files / xcl_lang-0.5.3-py3-none-macosx_11_0_arm64.whl

Download URL xcl_lang-0.5.3-py3-none-macosx_11_0_arm64.whl
Size 7.2 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
1d8180bc8c668793d7e80ef3cc60ec677b99752c7c8786bf2ac648320a147438
BLAKE2b-256 checksum
How to use checksums
a67d7672342c6171ec30ad69f29957dd62b8a12e5210815b98cdd45a774d9046
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.3 This release

9 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page