atl tick
Run one in-session maintenance pass — the work the three-speed cadence fires every few minutes while you're in a session: a cheap fan-out, plus a throttled drain + doctor self-check.
You almost never run this by hand. atl setup-hooks wires it to the UserPromptSubmit hook as atl tick --throttle=10m, so it rides your prompts automatically. The manual surface exists for setup, debugging, and forcing a pass.
When to use it
- Normally: never directly. It runs on every prompt via the hook, throttled so the heavy part only fires every ~10 minutes.
- To force a pass now — e.g. you want pending capture markers moved into the queue before running
/drain— runatl tickwith no--throttle. - To drain one file (debugging the marker parser) —
atl tick --file <path>.
Usage
atl tick # force a full pass now (no throttle)
atl tick --throttle=10m # skip the drain+doctor pass if the last tick was <10m ago
atl tick --file <path> # drain a single file instead of discovering transcripts (debug)atl tick operates on the current project — the directory you ran it in.
What a pass does
In order:
Fan-out (every call, ~free). Pulls any newly-changed files down from the user-global layer into this project. It's guarded by a global generation counter (
~/.atl/generation): if the global layer hasn't changed since this project last fanned out, it's a single small file read and does nothing. This step runs even when the throttle skips everything else — it's already cheap enough to ride every prompt.Auto-drain signal (every call). For each active capture channel — core's own
learning, plus any channel an installed team declares — prints a one-line auto-drain signal when that channel has pending items (atl: N learning(s) pending — auto-drain them now in a background subagent (per the learning-capture rule)), so the agent spawns that channel's drain as a background subagent. Each sentence is assembled from the channel's own declaration, so the platform names no team: it says which channel is pending and which rule acts on it, and that rule ships with whichever team owns the channel (see declaring a capture channel). It's one cheap count read and runs before the throttle gate, so it fires on every prompt the queue is non-empty — the throttle never suppresses it.Throttle gate. With
--throttle=<dur>, if the last tick was within<dur>the pass stops here — only the fan-out and the auto-drain signal ran (the fast path that keeps the per-prompt hook cheap). The stamp is per-project, at~/.atl/cache/last-tick-<project-hash>, so concurrent sessions in different projects don't starve each other's pass. With no--throttle(or--throttle=0), the gate always passes.Drain. Discovers this project's Claude Code transcripts modified since the last tick, extracts the assistant text, and transfers any capture markers into the durable queue — exactly once. Idempotency comes from the queue's marker-hash dedup, so re-draining the same text enqueues nothing new.
Capture watchdog. On the newest scanned transcript (the live session), measures the dry stretch — logical assistant turns and user-authored chars since the last marker-bearing turn, computed fresh from the file each pass (no counters to drift). The stretch is measured per capture channel, so a
learningmarker cannot mask a missed marker on a team's channel: each active channel gets its own stretch, its own latch, and its own nudge, naming the drain skill and the rule its declaration supplies (core'slearningnames/drain). Two channels can fire on the same turn — they are different subagents. If both thresholds are exceeded for a channel (≥2 assistant turns AND ≥1000 chars of user-authored input), it prints a one-line nudge to review the recent turns for what went unmarked and spawn that background drain, whose mining step sweeps the stretch (valid even with an empty queue). Fires once per dry stretch per channel — a latch keyed by (session file, channel, marker ordinal) re-arms whenever a new marker appears or a new session starts, so it never nags. This closes the pipeline's one non-deterministic link: a marker the agent forgot to write is no longer silent.ATL_NO_CAPTURE_WATCHDOG=1opts out."User-authored" is narrower than "role: user". Most user-role transcript records are machine-injected, and counting them turns the char threshold into a formality. Four carriers are excluded:
isMetarecords (a skill'sSKILL.mddump), tag-opening strings (task notifications), the compaction recap the harness writes after compacting a long session (13,995–17,966 chars observed — one alone clears the threshold), and the[Request interrupted by user]cancellation notice. On one real corpus these were 45% of everything the gate was counting.Doctor self-check. Runs the same queue-health + asset-integrity checks as
atl doctorandatl session-start, printing only the lines that are not OK (or that self-healed). Silent when everything is healthy.Promote gains (ring 1→2). Lifts this project's accumulated gains up to the user-global layer. It's additive and conflict-archived, so it's safe to ride the tick rather than waiting for a manual
atl promote. Quiet when there's nothing to lift.
The drain step only enqueues learnings. Folding them into the knowledge base is LLM work, so it stays on the skill side of the CLI/Skill boundary — that's what /drain does, spawned automatically as a background subagent by the auto-drain signal above whenever the queue is non-empty.
Flags
| Flag | Default | Effect |
|---|---|---|
--throttle <dur> | 0 | Skip the drain + doctor pass if the last tick was within this duration (e.g. 10m). The fan-out and the auto-drain signal still run. A zero/absent value always runs the full pass. |
--file <path> | "" | Drain a single file instead of discovering transcripts. Manual/debug only — skips the throttle and the cursor; does not advance the drain position. |
Example — force a pass
$ atl tick
tick: scanned 2 transcript(s) — 5 marker(s), 3 new, 2 already queuedWhen there's nothing new since the last tick:
$ atl tick
tick: no new transcripts to drainWhen the global layer changed since this project last synced, the fan-out line appears too:
$ atl tick
tick: fanned out 4 file(s) from the global layer
tick: scanned 1 transcript(s) — 2 marker(s), 2 new, 0 already queuedExample — drain one file (debug)
$ atl tick --file ./transcript.txt
tick: drained ./transcript.txt — 3 marker(s), 1 new, 2 already queuedRelated
atl setup-hooks— wirestickto theUserPromptSubmithook (this is how it normally runs).atl doctor— the on-demand surface for the same health checks the tick runs./drain— folds the queued learnings into the knowledge base (the LLM half of the loop).atl promote— the manual version of the gain-lift the tick does automatically.