Task discovery
For retry, bulk actions, and the dashboard’s task picker to work, the agent needs a task registry - a list of every task name the engine can run. Engines don’t usually expose this directly; we probe.
The 5-layer probe
Section titled “The 5-layer probe”Each engine adapter tries these sources in order. The first one that yields a non-empty result wins.
Layer 1 - Engine API (if available)
Section titled “Layer 1 - Engine API (if available)”Celery has app.tasks (a dict of name → task). Dramatiq has dramatiq.get_broker().actors. Use these when present.
Layer 2 - Worker introspection
Section titled “Layer 2 - Worker introspection”Celery: app.control.inspect().registered() - asks running workers for their registry. Slow; avoided on hot paths.
Layer 3 - Entry points
Section titled “Layer 3 - Entry points”Some apps declare tasks in pyproject.toml entry points (rare but elegant). We scan z4j.tasks group.
Layer 4 - Module scan
Section titled “Layer 4 - Module scan”Walk sys.modules for objects decorated with @app.task / @dramatiq.actor / @rq.job / etc. Run on agent startup, cached for 15 minutes.
Layer 5 - Observed tasks
Section titled “Layer 5 - Observed tasks”Every task name we see in an event is added to the registry with source: observed. Covers dynamically-registered tasks that the other layers miss.
Freshness
Section titled “Freshness”- Layers 1, 4 run at agent boot.
- Layer 2 runs every 5 minutes in the background (Celery only).
- Layer 5 is real-time.
The registry is shipped to the brain on every change (dedup’d). The dashboard shows an “as of” timestamp per agent.
Caveats
Section titled “Caveats”- Lazy imports - tasks defined in modules that haven’t been imported at agent boot won’t appear until they’re first enqueued. Layer 5 catches them.
- Multi-agent discrepancies - two agents with different import sets will report different registries. The UI shows the union with per-agent breakdown.
- Dynamic task names - tasks whose name is constructed at runtime show up only via Layer 5.
Implications for UI features
Section titled “Implications for UI features”- “Enqueue task” form - populated from the registry. Tasks not in the registry cannot be enqueued from the UI (but can still be enqueued from code).
- Bulk retry filter - matches against registry + observed names.
- Agent drawer - shows registry size and source breakdown per layer.