Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx agentmods add agents/multiplex-term/multiplex/lifecycle-and-attentiongit clone --depth 1 https://github.com/multiplex-term/MultiplexWhat it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5 | $0.00000 | $0.02483 |
| Opus 5 | $0.00000 | $0.01241 |
| Sonnet 5 | $0.00000 | $0.00497 |
| Haiku 4.5 | $0.00000 | $0.00248 |
Grade A, and why
lifecycle-and-attention scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 159 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Host lifecycle, background time & attention alerts
Load-bearing decisions split from AGENTS.md — read before touching host enable/disable, session resume, background keep-alive/refresh, or alerts.
- A disabled host is one the app never dials on its own
(
Host.isEnabled; deck rail menu / DISABLED tile / Host Settings → Monitoring): the wall skips it inrunFeed, never asksConnectionHubfor its model (asking would revive it), drops it fromtileCount/fleetSummaryand thelocalNetworkAccess.checklist;ExternalActionPerformerrefuses with its own message. It rides the synced record and stays inconnectionModelConfiguration— load-bearing twice: the feed restarts on the change, and that restart is where a disable from ANOTHER device tears the probe down (hub.suspendModel, which unlikedropModelkeeps the deck snapshot); the local action calls it too so the socket goes with the press. Deliberately NOT covered: already-open terminal windows keep running (explicit intent,keepHostProbeWarmincluded) and Host Settings' Signal check still connects. Disabling never buys back a free-tier host slot. - A suspended app's dead transport repairs itself; a session the user
ended stays ended (
SessionResumePolicy, pure + tested). The channel closes identically for suspension damage and a deliberate exit, so the discriminator is: did the app leave the foreground while the session was live, and has it not been live since. Both orderings count — the socket death surfaces before OR after.active, and a close within a short grace window after returning is still that wake; never attempted from the background. Attempts capped (3, spaced 0/2/5 s), reset the moment a session reaches live.TerminalWorkspaceowns the ONE app-level background/foreground observation and fans it out (unmounted tabs need repair too — not a scene-phase concern). A pending key-passphrase challenge always defers to the person. Logs under categoryresume(debug level). Deliberately NOT covered: a foreground transport death stays manual, exactly so a deliberate exit is never undone. - Background keep-alive is one opt-in host record buying one
background-task assertion — never a
UIBackgroundModesdeclaration (Host.backgroundKeepAlive, Host Settings → Monitoring;BackgroundActivityPolicypure + tested;BackgroundActivitythe UIKit shell). Off is the plain iOS contract thatSessionResumePolicyrepairs. On,didEnterBackgroundtakes ONE app-widebeginBackgroundTaskand this host's transports and probes keep running until the grant ends — measured ~26 s on iPad 26; tens of seconds, never indefinite, so every surface's copy is sized to that and none of them promises minutes. The modes that would buy more (audio,voip,location) require the app to genuinely do that thing and faking one is a rejection;BGTaskSchedulerreconnects minutes-to-hours later at the system's discretion, which is not keep-alive and is far too late for "your agent is waiting on you". Both were considered and refused (2026-08-05) — don't re-propose either without new platform facts. Load-bearing details:- The assertion is only taken when there is work for it
(
wantsBackgroundTime: an opted-in host that isisEnabledor has a live tab — a disabled host's already-open windows count). A user who opted no host in never takes one, so the default install's background behaviour is byte-for-byte unchanged. isHoldingBackgroundTimeis cleared BEFORE the assertion is handed back, or a tick starting in between opens an exec channel the suspension is about to cut. The expiration handler MUST end the task or the app is killed.- ⚠
backgroundTimeRemaininganswers.greatestFiniteMagnitudewhile the system is not counting down — which is exactly whendidEnterBackgroundruns. It is finite, so anisFiniteguard passes andInt(_:)traps pastInt.max: a crash on every background, caught E2E 2026-08-05. Range-check the value, never its finiteness. - The probe feed's lifetime is the wall's visibility, not the
scene's focus (
FleetWall.restartFeedIfNeededkeys onisOnScreen;viewDidDisappearis what ends a feed). It used to die on resign-active, which both defeated this gate and stopped an iPad Stage Manager sibling's visible deck from probing at all. Activity changes still force a restart — that is where a returning scene resets each model's connect-retry backoff. Pinned bytestTheProbeFeedOutlivesTheSceneResigningActive. .inactivecounts as permitted for every host (unsuspended foreground);.backgroundneeds the opt-in AND a held assertion. Three loops ask: the wall feed,keepHostProbeWarm(reads the LIVE record, so an edit reaches it without a tab change), and the direct shell's agent monitor.- Deliberately NOT covered: reconnecting from the background.
SessionResumePolicystill parks repair until foreground — redialling inside a window that is about to end is churn, not recovery. The file viewer's watch tick likewise stays.active-only. - Free, not Pro: this is connection plumbing, and the agent alerts it
feeds are already gated where they are scheduled. Rides the synced
record and participates in
connectionModelConfiguration. - Headless: seed key
backgroundKeepAlive, notify hookdebug.hostkeepalive(flips the FIRST host). Proof is thebackgroundlog category (debug level) plus the harness sshd log continuing to take exec probes across the trip; background the simulator app by launching another one (xcrun simctl launch <udid> com.apple.mobilesafari) — Xcode 27 ships no Simulator.app to send Cmd+Shift+H to. - Deliberately still
.active-only:watchActivePane's 1 s focused-pane check. It refreshes helper chips — UI nobody can see while backgrounded — at one exec per second, and it is not an alert source. Letting it run would spend the grant on invisible chrome instead of the 5 s probe that feeds notifications.
- The assertion is only taken when there is work for it
(
- The late half of keep-alive is one
BGAppRefreshTask, on iOS's schedule (BackgroundRefresh;UIBackgroundModes: fetch+BGTaskSchedulerPermittedIdentifiers, the app's ONLY background mode). The assertion covers tens of seconds; a real agent turn takes minutes, so leaving and having the turn end 60 s later reached nobody until the app was reopened (measured, user-reported 2026-08-05). This wakes the app later, probes the opted-in hosts, and lets the edges post.earliestBeginDate(15 min) is a FLOOR — the system decides from usage, and Background App Refresh off means never. No surface may promise timing. Scheduled only when there is something to deliver (an opted-in enabled host ANDattention.isActive), re-armed at the top of every run so an expiration still chains. The grant window ridesBackgroundActivity.isRunningBackgroundRefresh, OR'd with the assertion intohasBackgroundGrant, and is closed BEFORE the task completes.- ⚠ Its whole ability to emit rests on the edge baseline surviving a
reconnect.
AttentionTracker.updatereturns nothing without a prior observation, and the socket always dies across a suspension.evaluateAttentiontherefore clears the displayed attention map when the probe stops showing sessions but KEEPS the tracker — a lost connection is not evidence an agent's state changed. Resetting it (as the code did until 2026-08-05) makes both this and "alert me on return" silently impossible. Verified E2E: busy at suspension → turn ends while suspended → the reconnect's first pass poststurnEnded. - ⚠ Cold relaunch gap: if iOS terminated rather than suspended the app, the tracker starts empty and a refresh only establishes a baseline. Persisting baselines was deliberately declined — it would announce a turn that ended hours ago as if it just happened.
- Headless: the simulator NEVER schedules (
submitthrowsBGTaskSchedulerErrorDomain error 1, logged and ignored), and a suspended app cannot receive a notify poke — sodebug.bgrefreshruns the same probe under the same window and must be fired while the app is running. Scheduling itself is only provable on device.
- ⚠ Its whole ability to emit rests on the edge baseline surviving a
reconnect.
- Keyboard focus only silences an alert while the app is frontmost
(
AttentionFocusPolicy, pure + tested;AttentionCenter.isFocused). The arbiter answers "which terminal would receive a keystroke", NOT "is anyone here" — it keeps its owner when the app leaves the screen. So the old focus check silently inverted on backgrounding and suppressed alerts about the session the user had just walked away from, which is the likeliest one running an agent: "leave while the agent works, get pinged" was the one case that stayed quiet (user-reported, fixed 2026-08-05)..inactivedeliberately does not count as engagement — a Stage Manager sibling beside the app being typed in is not being watched, andForegroundBannerexists to draw over a visible-but-unattended window. All three event sources share the rule (probe alerts, direct-shell events, in-band bells). - Notification permission is asked with the app on screen, never from
the background (
AttentionCenter.primeAuthorization, called fromsceneDidBecomeActiveand when the Alerts switch goes on). The ask used to ride the FIRST alert; raised for a backgrounded app that puts a system prompt over whatever the user switched to and spends the alert buying permission instead of delivering it — verified on the iPhone 17 sim 2026-08-05 (prompt over Safari, no banner ever). A background alert with permission still undetermined is dropped; the wall's NEEDS YOU badge stays the in-app surface and the next foreground moment asks properly. - Every alert that does not become a banner says why (category
attention, debug level:alert dropped for <session>: focused|locked/alert posted for <session>). An undelivered alert is otherwise indistinguishable from one never detected, which is what made the focus bug above invisible for so long. ⚠ Notification authorization cannot be granted headlessly (simctl privacyhas no such service), so the log line is the delivery proof a simulator run can give.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 2d ago First seen · 159 lines · 0 tokens per session scan A 6d607f7e9163
lifecycle-and-attention is an agent published in the GitHub repository multiplex-term/Multiplex (10 stars, last pushed 6d ago), licensed Apache-2.0. It costs nothing until one of its globs matches a file; then it loads 2,483 tokens. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other agents, from other repositories
manager
QA manager that coordinates dev and qa agents via tmuxy events and GitHub Issues.
dev
Dev agent that implements bug fixes assigned by the manager, reports progress via GitHub issue comments.
apply-review-agent
Design policy update specialist. MUST BE USED when user requests to apply architecture review findings to design policy. Reads context from apply-review-context.json and outputs apply-review-result.json. Updates design policy documents based on must-fix and should-fix items from review.
multi-server-state-isolation
Which app state is per-server versus intentionally global, where each lives, and which tests guard the isolation. Almost all isolation holds by construction through the server-keyed view tree and cache keys described below; "Clear Offline Cache" is explicitly scoped to the active server.
i18n
Hermex ships one String Catalog, HermesMobile/Resources/Localizable.xcstrings, included in the app, widget, and share-extension targets. Every user-facing literal is already externalized (String(localized:) / LocalizedStringKey), so adding a language is normally translation-only — no Swift edits.
kanban
Durable rules for the shipped Kanban feature (HermesMobile/Features/Kanban/). These are normative where they differ from the desktop WebUI. Vocabulary is owned by root CONTEXT.md: upstream task/taskid stay network-boundary names; user-facing and Swift domain names use Card with a Kanban qualifier.