Quickstart - Django
This example assumes an existing Django 5 / 6 + Celery 5 application.
1. Install
Section titled “1. Install”pip install z4j-django[celery]The [celery] extra pulls the engine adapter AND celery-beat in one shot. Other engines follow the same pattern: [rq], [dramatiq], [huey], [arq], [taskiq]. Use [all] for every engine in one go.
Pip transitively pulls z4j-core and z4j-bare.
2. Mint an agent token
Section titled “2. Mint an agent token”Open the brain dashboard, pick a project, navigate to /projects/{slug}/agents, and click new agent. The mint dialog returns two values, both shown ONCE:
- token → goes into
Z4J_TOKEN - hmac_secret → goes into
Z4J_HMAC_SECRET
Copy both before closing the dialog. The brain stores only their hash; if you lose them you have to mint another agent.
3. Configure settings
Section titled “3. Configure settings”Add the following to your .env:
Z4J_BRAIN_URL=http://localhost:7700 # http:// to a loopback host is fine for devZ4J_TOKEN=<token from step 2>Z4J_HMAC_SECRET=<hmac_secret from step 2>Z4J_PROJECT_ID=<project slug from URL> # any non-empty string works locallyZ4J_AGENT_NAME=fragmaster-web # optional, displayed in dashboardThen in settings.py:
INSTALLED_APPS += [ "z4j_django",]
Z4J = { "brain_url": env("Z4J_BRAIN_URL"), "token": env("Z4J_TOKEN"), "hmac_secret": env("Z4J_HMAC_SECRET"), "project_id": env("Z4J_PROJECT_ID"), "agent_name": env("Z4J_AGENT_NAME", default=None),}That’s it. No CELERY_APP setting, no Z4J_DEV_MODE, no dev_mode=True kwarg. Auto-detect handles 95% of project layouts. If your celery.py lives somewhere unusual or auto-detect can’t find it, add a fallback:
CELERY_APP = "myproject.celery:app" # only if auto-detect failed4. Restart
Section titled “4. Restart”./manage.py runserver # devcelery -A myproject worker -l info -E # worker (separate process)# orsystemctl restart gunicorn # prodThe agent opens a WebSocket on boot, advertises its engines in the hello frame, and starts streaming events. The dashboard populates within 2-5 seconds.
Expected log output
Section titled “Expected log output”runserver - should be silent on the z4j side (one optional INFO line about engines):
April 23, 2026 - 13:30:50Django version 6.0.4, using settings 'myproject.settings'Starting development server at http://127.0.0.1:8000/celery worker - look for the bootstrap line right before Celery’s banner:
INFO:z4j.celery.worker_bootstrap:z4j worker bootstrap: agent runtime started (celery_app=myproject, framework=DjangoFrameworkAdapter)That line is the proof the engine is attached. If you don’t see it, no tasks will reach the brain.
5. Verify
Section titled “5. Verify”Run the doctor first — it confirms the agent can reach the brain end-to-end and reports a specific failure if it can’t:
python manage.py z4j_doctorIf gunicorn/uvicorn is your web server, run as the same user the service runs under (sudo -u www-data /srv/.../venv/bin/python manage.py z4j_doctor). All probes should be [OK].
Then in the brain dashboard:
/projects/{slug}/agents→ your agent should be online, withcelery(andcelery-beatif installed) in adapters./projects/{slug}/tasks→ enqueue anything; it appears within ~100ms./projects/{slug}/schedules→ ifdjango-celery-beatis your scheduler, yourCELERYBEAT_SCHEDULEentries appear (read-write withDatabaseScheduler, read-only with filesystem schedulers).
Multi-engine (optional)
Section titled “Multi-engine (optional)”If you also use RQ in the same Django project:
pip install z4j-rq z4j-rqschedulerThe agent will discover both engines automatically. No additional settings needed.
Auto-detect, in detail
Section titled “Auto-detect, in detail”The Celery app is located by trying these in order (first hit wins):
settings.CELERY_APP(object or"module:attr"/"module.attr"string)<root>.celery_apppackage-level attribute (cookiecutter convention - your project’s__init__.pydoingfrom .celery import app as celery_app)<root>.apppackage-level attributecelery.current_app._get_current_object()(any configured app made current by import-time side-effect)<root>.celery.appsubmodule attribute
<root> is tried in order: ROOT_URLCONF head, WSGI_APPLICATION head, ASGI_APPLICATION head, BASE_DIR.name. The vast majority of layouts hit one of these.
Troubleshooting
Section titled “Troubleshooting”hmac_secret is required- you used the first-boot setup token instead of an agent token. Mint a real agent at/projects/{slug}/agentsand copy BOTHtokenANDhmac_secret.refusing plain ws:// connection to ws://...- you’re connecting to a non-loopback host without TLS. Loopback (localhost/127.0.0.1/::1) is auto-allowed; for any other host, setZ4J_BRAIN_URL=https://...(recommended) orZ4J_DEV_MODE=true(trusted networks only).connection closed during send: received 4002- two processes are using the same agent token at the same time. The brain accepts only one WebSocket per token and force-closes the older one. Mint a second agent for the second process.no Celery app located in this process(INFO log) - benign in the standard split-process layout. The worker process owns task-lifecycle capture; the web process only missestask.delay()send-events. To capture those too, addCELERY_APP = "myproject.celery:app"tosettings.py.- No tasks in dashboard, worker boots quietly - the
INFO:z4j.celery.worker_bootstrap: agent runtime started ...line should appear right before Celery’s banner. If it’s missing, the agent isn’t running. CheckZ4J_*env vars and that your worker is actually invoked ascelery worker(the bootstrap signal only fires under that command). - Schedules read-only - you are using a read-only beat backend.
django-celery-beatwithDatabaseScheduleris writable; filesystem-based schedulers are not.
See troubleshooting for more.