Skip to content

augbastos/afkswitch

v0.6.8MIT

Tell AI agents when their human operator is physically away and when they are back.

Changelog

All notable changes to this project are documented here. Format follows Keep a Changelog; versions follow Semantic Versioning.

[Unreleased]

Changed

  • Queue human decisions while AFK without stalling independent authorized work; review them together on return and include their count in status replies.

[0.6.8] - 2026-10-19

Changed

  • The OpenAI plugin package declares requires_local_executor, so the directory lists AFKSwitch as Desktop only: its skills run a bundled Python script on your computer.

[0.6.7] - 2026-10-13

Changed

  • A click anywhere inside the switch's box toggles it, not only on the cells. A button takes no color, so "away" now shows as an orange border instead of an orange word.

[0.6.6] - 2026-10-02

Fixed

  • Keep the switch pending while its command is queued, and confirm the saved state after the command's turn finishes instead of showing a premature failure.

[0.6.5] - 2026-10-02

Added

  • One-time onboarding lines explain the switch and optional command context, dismissed on the first prompt or switch press.

Changed

  • Human transition text replaces !: dim saving… while pending and orange not switched — try /afk or /back on failure.

[0.6.4] - 2026-10-02

Changed

  • Before first use, the neutral switch is pressable and starts AFK when no state file exists; unreadable or invalid state remains neutral and cannot be pressed.
  • Reworked the README around installation and first use, with verified marketplace module loading on Claude Code 2.1.287 and the current plugin directory limitation.
  • Replaced the README demo image with a four-step capture showing present, AFK notification, continued peer work and reporting, and return.

[0.6.3] - 2026-10-02

Changed

  • New logo and plugin icon: the Claude Code switch itself, a bordered box with an orange AFK and the away cells. README art follows it, and the README switch cells now match the terminal.

[0.6.2] - 2026-10-02

Changed

  • The switch module no longer names a local variable h, the name JSX compiles to; the plugin directory's policy check blocked 0.6.0 and 0.6.1 for it. No behavior change.

[0.6.1] - 2026-10-02

Changed

  • The switch module is written in the form the Claude plugin directory can review: plain function declarations receive $, and registrations no longer chain an error fallback (the engine already skips a hook that throws).
  • The README states which events the switch hooks and which commands it runs.

[0.6.0] - 2026-10-01

Added

  • /back [optional context] returns opaque event context while available state keeps context null.
  • Independent state, sync, notify and fanIn capabilities; a one-shot generic local-agent sync reference.
  • Session awareness, portable event blocks, sync and cross-host conformance, and opt-in local model evals.
  • Read-only SessionStart and UserPromptSubmit hooks for Claude Code; experimental Codex hooks and a static Antigravity PreInvocation adapter.
  • Compact terminal AFK switch above the Claude Code prompt on builds with function hooks; clicks invoke the existing explicit skills with no context and confirmed state remains the only truth.
  • The switch requires loading via --plugin-dir or CLAUDE_CODE_PLUGIN_DIRS; directory and marketplace installs retain text skills and read-only sync hooks, but cannot load the switch until Anthropic enables modules for installed plugins.
  • Function-hooks UI tests for known/unknown states, captured click intent, concurrency and failures; visualSwitch and visualSwitchSurfaces capability declarations.

Changed

  • Reject unsafe controls, ESC sequences, CR/CRLF and lone surrogates; allow LF/tab and preserve stdin verbatim.
  • Each skill ships a byte-identical standalone helper. sleep and work are ordinary context, not presets.
  • Presence remains separate from reachability, permission and agent execution; only /back ends AFK, without timeout.
  • State protocol remains v2, including existing reset and migration semantics. All plugin manifests now declare 0.6.0.
  • Conformance fixture matrices invoke the real helper entry point in-process; subprocess CLI smoke tests and the lock-removal concurrency mutation remain.
  • Remove Codex hook pointers from default manifests; Codex and Antigravity sync=false until verified in a live host. Experimental hook files still ship.
  • Package and validate the function-hooks module alongside command hooks; exclude UI tests from the archive. Capability tables in details, spec and adapter docs include visual support; the root README remains unchanged in this change.

[0.5.2] - 2026-09-30

Changed

  • The Claude plugin description is one line, "AFKSwitch by augbastos — Tell your agents when you're away and when you're back.", because the directory shows it on one line. No behavior change.

[0.5.1] - 2026-09-30

Changed

  • The Claude plugin description now reads "AFKSwitch by augbastos" / "Tell your agents when you're away and when you're back." No behavior change.

[0.5.0] - 2026-09-30

Changed

  • State protocol v2. ~/.afkswitch/state.json gains generation, a counter that goes up by one on every real change and orders presence without trusting clocks. Repeating /afk with the same context, or /back, keeps both since and generation.
  • The state is written only by a bundled standard-library Python 3.9+ helper (skills/afk/scripts/afkswitch_state.py; /back reaches it through a shim). It validates input, takes an O_EXCL lock file, writes a temp file with fsync and an atomic rename, reads the result back, and only then lets the skill notify anyone. Without Python the skills say state helper unavailable (python not found) and change nothing.
  • Peer messages start with [AFKSwitch g<G>]; a session that already saw a newer generation ignores an older message. Status replies start with afkswitch-status g<G>, so a reply to an earlier /back is shown as late instead of being counted. Reports show g<G>.
  • Context over 2048 characters is refused with a clear message instead of being saved or cut. The /afk skill tells the model to copy the context itself, never rebuild, shorten or summarize it, and to stop when the helper refuses it.
  • A malformed state file is kept as state.json.corrupt-<time> before it is replaced; a state file from a newer AFKSwitch is never overwritten (unsupported state version N).
  • Privacy wording: "AFKSwitch runs no server and makes no network requests of its own. Messages between sessions travel through the host's own mechanisms and are governed by the host." replaces broader claims in the README and PRIVACY.md.
  • The README no longer says every session is told; it says which ones the host could reach.

Added

  • conformance/: executable state tests (including 60 concurrent transitions and a check that they fail without the lock), notify and fan-in scenarios with a pure reference checker, and a README saying what PASS means per level.
  • adapters/capabilities.json (the one support matrix, rendered into the docs by scripts/validate.py --write) and adapters/README.md for adapter authors.
  • docs/compatibility.md: only versions actually run.
  • CI on Linux, Windows and macOS (validation, packaging, conformance, Python 3.9 floor) and a weekly check against the latest Claude Code and Codex CLIs.

Migration

Nothing to do. A version 1 state file from 0.4.x is migrated to version 2 on the next /afk or /back (generation starts at 1); nothing needs deleting. Python 3.9+ must be on PATH.

[0.4.1] - 2026-09-27

Added

  • Claude plugin manifest: display name AFKSwitch, an icon (.claude-plugin/icon.svg, generated by scripts/make-logo.py), and documentation, support, privacy and terms links.

No behaviour change: /afk, /back, the state file and the Codex adapter are identical to 0.4.0.

[0.4.0] - 2026-09-27

Changed

  • Renamed the product from claude-session-presence to AFKSwitch, keeping the prototype's commits in the repository history.
  • Reduced the public product to the universal /afk [optional context] + /back contract.
  • Reframed Claude Code as the first/reference adapter rather than the product identity.
  • Moved portable presence state to ~/.afkswitch/state.json with a versioned, host-neutral schema.
  • Removed /live and /broadcast from the AFKSwitch product surface; their history remains in Git.
  • Removed personal-environment policy from the public skills and kept only portable presence, authorization, physical-blocker, and native-first semantics.
  • Added explicit capability levels for adapters: state-only, notify, and fan-in. Claude Code is fan-in; Codex is state-only.
  • Kept the semantics proven in the first overnight dogfood run: /back subscribes with the native one-shot notify_when_idle and reads its own session name as the reply address; /afk reports discovered / notified / not notified and lists who does not know; peers classify needs as remote-blocking, non-urgent, or physical-blocking and record deferred steps in one BLOCKED FOR HUMAN line; sleep and work stay as optional presets.
  • A message the host reports as held for approval or refused counts as not notified (Claude Code 2.1.283 delivery notices).
  • When one human action releases several sessions, /back lists it first with the sessions it releases, and never triggers that action itself.

Added

  • Portable plugin manifest (plugin.json) with Codex interface metadata.
  • Claude Code plugin manifest and a plugin catalog for direct install from this repository.
  • Codex skill metadata (agents/openai.yaml): Codex only, implicit invocation disabled.
  • Host-neutral presence specification and JSON Schema.
  • MIT license, privacy policy, security policy, support, terms, contributing guide, and project history.
  • README section disclosing everything the plugin reads, writes, and sends.
  • Short README (install, three rules, one example, disclosure); details moved to docs/details.md.
  • Pixel-art logo (assets/, generated by scripts/make-logo.py), shown in the README and used as the plugin icon.
  • CI validation, Windows installer smoke test, issue templates, PR template, and a plugin archive builder (scripts/package.py).
  • Validation gates for manifest field limits, archive layout, relative Markdown links, explicit-only skills, and the CHANGELOG section of the current version.

Fixed

  • Codex CLI 0.156 loads plugin skills only from .codex-plugin/plugin.json; the plugin now ships that manifest alongside the portable plugin.json, and validate.py keeps the two in step. Codex docs and example prompts use the qualified $afkswitch:afk / $afkswitch:back, the only form verified to reach the plugin skill.
  • /back could copy the context label from its report template instead of the saved state (seen once: AFK (sleep) after /afk work). Report templates now use placeholders filled only from the state and the run.
  • CI ran twice per push to a PR branch (push and pull_request); it now runs once.

Notes on earlier entries

Entries before 0.4.0 describe the private claude-session-presence prototype, including behavior tied to its author's own environment (a work-roster lookup, a password-manager signing workflow) that AFKSwitch does not ship.

Security

  • AFK/back explicitly remain presence signals, never permission or authorization changes.
  • The reference design remains backend-free: no AFKSwitch server, account, telemetry, daemon, database, listener, or polling loop.

[0.3.1] - 2026-09-27

Fixed

  • /live frontmatter was invalid YAML (an unquoted : in the description), so the skill listing and autocomplete showed no real description. The description is now quoted and short. No behaviour change.

[0.3.0] - 2026-09-27

Changed

  • /afk now means only physically away: remote availability through Remote Control stays possible, often intermittent. Sessions keep full progress and never depend on an immediate answer. They classify what they need as REMOTE-BLOCKING (ask once through Remote Control, don't wait), NON-URGENT (group, keep going) or PHYSICAL-BLOCKING (only that sub-step waits for /back). The old instruction "do not message him while he is gone" is gone.
  • Running /afk changes no session setting. Model, effort and fast mode may change during AFK (on request, by an authorised rule or for an operational reason), but each change is confirmed against the session's real state and reported before → after; a mismatch is flagged and an unconfirmed value is UNKNOWN. New /live power prints every live session's model | effort | fast mode. Auto Mode and permission mode stay. A message from the user during AFK is normal interaction and does not end it; only /back does.
  • The state file gains physical_presence, remote_presence, current_context and expected_physical_return (an estimate for planning, with its source). The control may fill them from the author's work-roster tool, read-only and only with what it reports. The user's own estimate outranks an inferred one.
  • /afk work reads as intermittently reachable instead of "may take several hours to answer".

[0.2.0] - 2026-09-27

Added

  • /live lists only the live local sessions, as name — status. Its "The rule" section is the single definition of a live session: a local Claude Code row (interactive), in a running state, and never Remote Control, cloud, another machine, a subagent or anything offline.

Changed

  • /afk, /back and /broadcast read and apply that rule instead of messaging every ListAgents peer. Offline and stale Remote Control rows, including one that shares a live session's name, are no longer targets. Nothing else in their behaviour changed.

[0.1.2] - 2026-09-21

Added

  • /back now leads its report with the vault when any session reports a credential- or vault-shaped blocker, above every other section — one line naming which sessions a single unlock releases.

    The reasoning is the same one the AFK policy is built on, inverted: the policy spends its whole effort avoiding a credential prompt with nobody at the machine, which makes /back the one moment a human is guaranteed to be there and the prompt is safe. A locked vault is also usually the cheapest blocker to clear, since one unlock releases every session at once.

    It tells, and never unlocks. Unlocking needs the user's body, not a command, and /back will not trigger a signing operation to force the prompt: on Windows each sub-shell needs its own authorization from the app, so a prompt raised by a tool call authorizes a shell that is about to exit. Repeating that produces a row of prompts and no unlock. A service-account helper is not a substitute either — it bypasses the app by design and so cannot sign.

    It also does not act on the other sessions: no retry messages, no committing their staged work. One unlock re-arms the signing window and each session picks it up on its own next attempt. When nothing is blocked on credentials, the line does not appear.

[0.1.1] - 2026-09-21

No functional changes. This release exists to record that 0.1.0 survived its first real overnight, multi-session run — it was dogfooded, not just tested.

First overnight dogfood

/afk sleep at 01:53, /back at 10:15 — 8h 21m, across four live peer sessions working on unrelated projects.

  • Broadcast: the AFK message was delivered to all four sessions; all four were reached, none was unavailable.
  • Recovery: /back was answered by all four, each in the requested dir:/needs-user:/completed:/running:/other-blockers: shape. Replies arrived asynchronously over ~2 minutes and consolidated Needs you now first, as specified.
  • notify_when_idle earned its place. All four idle notices fired, which is what separated "this report is final" from "still working" — with no polling, no re-sends and no held-open turn.
  • The absence policy held under a real failure. The password-manager signing key expired mid-run. Three independent sessions each hit it, and each staged the work and stopped rather than raising a vault-unlock prompt on a sleeping user's machine. None bypassed signing. That is precisely the behaviour /afk sleep exists to produce, and it was exercised by accident rather than by design, which is evidence that the policy transmits intact.
  • No hooks, daemon, watcher or polling loop were involved at any point.

Validated only partially

The overnight /back ran in the same session that had run /afk. The "/back from any terminal" property was exercised during testing — a second session read the global state written by the first — but has not yet been exercised in a real overnight cycle. Worth repeating from a different terminal before treating it as proven in the field.

[0.1.0] - 2026-09-21

First implementation: three tiny skills that provide broadcast and human presence semantics on top of Claude Code's native cross-session messaging.

Commands

  • /broadcast <message> — relays one message verbatim to every reachable peer session, wrapped as [User broadcast] ... and nothing more. Multi-line preserved. Stateless: never reads or writes presence.
  • /afk — user is away. No return time assumed.
  • /afk sleep — user is sleeping. Extra emphasis on causing no interaction that could wake them: nothing that lights a screen, raises a window, or leaves a dialog open overnight.
  • /afk work — user is away at work; may take hours to answer.
  • /afk <free text> — passed through verbatim as context.
  • /back — user returned. Clears the state, announces, requests status, consolidates.

Absence policy

While AFK, sessions continue safe autonomous work but defer anything that may require authentication, elevation, credentials or physical user interaction.

  • They keep reading, analysing, coding, fixing, testing, reviewing, researching, documenting and running already-authorized local work, and do not message the user while he is away — it keeps for /back.
  • They defer anything that could predictably raise an interactive prompt: a password manager or any vault unlock, Windows password / PIN / Hello / fingerprint / face, passkey, UAC or elevation, credential or browser auth popup, interactive OAuth or device authorization, MFA/2FA or phone push approval, or any physical confirmation.
  • They do not run a command just to find out whether it prompts. A reasonable chance is enough to defer; by the time a prompt is open the screen is already lit.
  • AFK never grants permissions. Not for a destructive action, deploy, merge, publication, production change, purchase, outbound external message, anything irreversible, or credentials not already held.
  • A blocked step blocks only itself. Independent work finishes, and the session records BLOCKED FOR USER: <task> — stopped at <point> — needs <interaction> — resume with: <command>.
  • /back does not authorize either. Deferred steps may be reconsidered, not executed: "I need elevation to continue. Ready when you are."

Global presence

  • Presence belongs to the user, not to a repository or terminal. /afk from any session notifies all reachable sessions; /back from any session — not necessarily the same one — returns and collects status.
  • No owner: the /afk terminal may be closed before /back runs.
  • Minimal shared state at ~/.claude/session-presence/state.json (status, mode, since, message), so a session that never saw the /afk can still report how long the user was gone. Plain file, read and written only by these skills.
  • Idempotent: /afk twice, /back twice, and /back with no prior /afk all work. A missing or corrupt state file is never an error.

/back output order

Needs you now → Completed while AFK → Still running → Other blockers → No reply yet. The first section collects everything blocked on a password manager, a password, PIN, Windows Hello, UAC or elevation, MFA, a passkey, a login, a credential, a confirmation or a human decision, each with where it stopped and how to resume.

Design constraints held

  • Hooks added by this plugin: 0. No hooks key in the manifest, no hook file, no background process, nothing on a timer. The state file did not change this.
  • Built entirely on the native ListAgents and SendMessage tools, verified against Claude Code 2.1.278. No daemon, server, database, socket, watcher or custom protocol.
  • No password-manager integration, no credential handling, no control over Windows lock state, no elevation check, no prompt detection. The skill transmits policy; sessions apply it.
  • At most one copy per target per invocation. Retry only after a confirmed failure, at most once, reported as retried once.
  • Failure isolation: one bad target never cancels delivery to the rest. Every report closes with discovered / delivered / failed.
  • /back is bounded by the turn, never by a polling loop, and uses the native one-shot notify_when_idle to distinguish a silent session from a slow one.

Installation

  • install.ps1 installs the skills to ~/.claude/skills/ so they answer to the bare command names in any session on the machine, regardless of repository or working directory; -Uninstall removes them.
  • .claude-plugin/plugin.json — the same three skills as a plugin.

Known limitations

  • The broadcast reaches sessions alive at that moment. Sessions started afterwards are not notified and nothing makes them read the state file on startup — that would need a SessionStart hook, excluded by design. The state record itself survives.
  • ListAgents exposes no working directory or repository, so sessions appear as short handles (api-1f). /back works around it by asking each session for its own dir:.
  • Delivery is not readership; cloud and Remote Control sessions never report back.