Build and wait

from nullspace import Template, default_build_logger

build = Template.build(
    builder,
    name="my-template",
    tags=["stable"],
    cpu_count=4,
    memory_mb=2048,
    skip_cache=True,
    on_log_entry=default_build_logger(),
)
print(build.status, build.name)

Background build

build = Template.build_in_background(builder, name="my-template", tags=["next"])
snapshot = build.get_status()
print(snapshot.build.status)

finished = build.wait_until_terminal()
print(finished.build.status)

Reconnect

from nullspace import TemplateBuild

build = TemplateBuild.connect("tb_...")
status = build.get_status(offset=0)
for entry in status.entries:
    print(entry.kind, entry.message)
print(status.next_offset)

for entry in build.logs(offset=status.next_offset, follow=True):
    print(entry.kind, entry.message)
get_status() returns a snapshot plus incremental entries. logs() uses the canonical reconnectable log stream, replays durable entries from offset or cursor, and keeps following live entries when follow=True. Save status.next_offset after each poll or stream resume and pass it back on the next reconnect.

History, Validate, And Plan

history = Template.list_builds("team/my-template", status="error")
for build in history.builds:
    print(build.build_id, build.status, build.tags)

validation = Template.validate(builder)
print(validation.valid, validation.errors)

plan = Template.plan(builder)
print(plan.source_type, plan.context_manifest)
Build history includes failed, untagged, and superseded builds. Validate and plan use the build request parser without starting the build executor.

Control Builds

from nullspace import TemplateBuild

build = TemplateBuild.connect("tb_...")
cancelled = build.cancel(reason="superseded")
retry = build.retry(tags=["next"])
promoted = retry.promote(tag="stable")
print(cancelled.build.status, retry.build_id, promoted.canonical_ref)
cancel() is idempotent for completed builds. Active cancellation aborts the API build task and records a durable cancelled log entry. retry() rebuilds from the sanitized persisted definition, so private base image credentials must be supplied again when the original build required them. promote() moves a tag to a retained ready build artifact.

CLI

nullspace template builds team/my-template
nullspace template builds team/my-template --status error --limit 20
nullspace template validate --from-python-image 3.12 --apt-install git
nullspace template plan --from-python-image 3.12 --apt-install git
nullspace template build-status tb_...
nullspace template build-status tb_... --offset 10
nullspace template logs tb_...
nullspace template logs tb_... --offset 10 --follow
nullspace template cancel tb_... --reason superseded
nullspace template retry tb_... --tag next
nullspace template promote tb_... --tag stable
nullspace template wait tb_... --offset 10 --poll-interval-ms 500 --log-format jsonl
nullspace template build --from-python-image 3.12 --name my-template --tag stable --cpu-count 4 --memory-mb 2048 --skip-cache
nullspace template build --from-python-image 3.12 --name my-template --tag next --background