Skip to content

Quickstart - Bare Python

z4j-bare is the foundation package; every framework adapter depends on it. You can use it directly if you have no framework.

Terminal window
pip install z4j-bare z4j-celery

From the z4j dashboard, Agents, Mint. The response shows the bearer token and the per-project HMAC secret. Save both as Z4J_TOKEN and Z4J_HMAC_SECRET. The token is stored only as a hash and cannot be recovered. The HMAC value is derived from the brain master and project ID; it is shared by agents in that project rather than stored as an agent-specific secret. The runtime refuses to start without it.

worker.py
import asyncio
from z4j_bare import install_agent
from z4j_celery import CeleryEngineAdapter
# my_celery_app = Celery("myapp", broker="redis://...")
runtime = install_agent(
engines=[CeleryEngineAdapter(celery_app=my_celery_app)],
# brain_url / token / hmac_secret / project_id default to the
# matching Z4J_* env vars; pass them explicitly only if you do
# not want the env-var lookup.
)
try:
asyncio.run(your_work())
finally:
runtime.stop() # stop transport and close the durable local buffer

install_agent returns a started AgentRuntime. Hold the reference and call .stop() on shutdown. The runtime drives the WebSocket connection on a background thread and an internal asyncio loop, so it composes with sync workloads. stop() does not wait for the brain to acknowledge every pending event; unsent rows stay in the SQLite buffer for a later start.

Verify before launching the long-running agent

Section titled “Verify before launching the long-running agent”

Before you run worker.py for the first time, run the doctor. It checks local configuration, the buffer path, DNS/TCP/TLS reachability, and whether the transport can start without leaving a persistent agent running:

Terminal window
Z4J_BRAIN_URL=... Z4J_TOKEN=... Z4J_HMAC_SECRET=... Z4J_PROJECT_ID=... \
python -m z4j_bare doctor

Run as the same user your worker process will run under. The WebSocket probe does not wait for the agent-auth handshake, so [OK] is not proof that the token or project is accepted. After starting the worker, also confirm that its worker slot is online in z4j and inspect agent-auth warnings.

  • Opens the configured transport. auto currently means WebSocket; there is no automatic long-poll fallback. To use long-poll, set Z4J_TRANSPORT=longpoll and the minted Z4J_AGENT_ID explicitly.
  • Sends hello with engine and scheduler capabilities.
  • Installs patches on the supplied engine adapters to capture lifecycle events.
  • Starts a heartbeat loop.
  • On runtime.stop(), requests transport shutdown, joins the background thread within the timeout, and closes the durable buffer. Pending rows are not synchronously flushed to the brain.

install_agent accepts any number of engine adapters; the runtime fans events out for each:

from z4j_bare import install_agent
from z4j_celery import CeleryEngineAdapter
from z4j_rq import RqEngineAdapter
from redis import Redis
from rq import Queue
rq_connection = Redis.from_url("redis://localhost:6379/0")
rq_queue = Queue(connection=rq_connection)
runtime = install_agent(
engines=[
CeleryEngineAdapter(celery_app=celery_app),
RqEngineAdapter(rq_app=rq_queue),
],
)
  • For mapped configuration fields, explicit keywords win over environment variables, which win over defaults. Adapter objects, framework, buffer_path, and dev_mode are code-only inputs. Z4J_BUFFER_PATH is a removed variable that causes startup refusal, and Z4J_DEV_MODE is ignored by the generic resolver. See install_agent reference for the full argument list.
  • The same AgentRuntime object can be stopped and started again. Do not call install_agent() a second time after stopping it: the process singleton returns the already-registered, stopped runtime. Call runtime.start() on the object you retained instead.