untether: Command for Claude Code

.claude/commands/debug/step-classify.md

step-classify is a command for Claude Code from littlebearapps/untether. It costs 0 tokens per session (2,161 once invoked), scanned A, original, MIT.

A reference table for assigning each Untether issue—the project’s agent and messaging system—to the main area where its root cause belongs.

In plain words
What is it for?
Use it to classify issues involving subprocesses, Telegram messaging, control channels, and other documented system areas.
Why use it?
It makes investigations consistent and points developers toward the right logs, checks, and project rules.

Command for Claude Code

Written for Claude Code: installed under .claude/. Also seen: reads .claude/ paths; names the ExitPlanMode tool.

This is littlebearapps/untether's own configuration. It tells Claude Code how to work on untether itself, so it is not a mod to install elsewhere. Copy it as a starting point and replace the rules that are about this project. Everything untether configures →

Reuse

Borrowing it

Nothing to install: this file belongs to littlebearapps/untether. Take a copy, put it at the same path in your own repository, and replace the rules that are about this project with yours.

Copy the file
curl -O https://raw.githubusercontent.com/littlebearapps/untether/master/.claude/commands/debug/step-classify.md
Clone the repo
git clone --depth 1 https://github.com/littlebearapps/untether

Made for: Claude Code.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for step-classify

README.md
[![agentmods](https://agentmods.dev/badge/commands/littlebearapps/untether/step-classify/github.svg)](https://agentmods.dev/commands/littlebearapps/untether/step-classify)
Your own site
<a href="https://agentmods.dev/commands/littlebearapps/untether/step-classify"><img src="https://agentmods.dev/badge/commands/littlebearapps/untether/step-classify/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for step-classify

Your own site · 80×15
<a href="https://agentmods.dev/commands/littlebearapps/untether/step-classify"><img src="https://agentmods.dev/badge/commands/littlebearapps/untether/step-classify.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 0 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 2,161 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 1 finding. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What 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.

ModelPer sessionOnce invoked
Fable 5.1 $0.00000 $0.02161
Opus 5.5 $0.00000 $0.00864
Sonnet 5.5 $0.00000 $0.00432
Haiku 4.5 $0.00000 $0.00216

Measured 18d ago against content hash 1c7c6b376716, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade A, and why

step-classify scanned grade A with 1 finding 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 18d 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.

Runs shell commandslowCapability

Expected in a hook, worth knowing in a rule or an instructions file.

| **runner-subprocess** | `subprocess.create.failed`, `subprocess.died_without_completion`, `runner_failed`, signal exits (rc=143/137), JSONL parse errors, EventFactory misuse | grep `engine=<X>` `event=session.summary`;
.claude/commands/debug/step-classify.md · 65 lines

How it starts

The opening of the file, as written. The whole thing — 65 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Step 1 — Classify

This is the canonical Untether issue-class table. Pick exactly one primary class per issue (the area where the root cause lives). If behaviour crosses boundaries, note a secondary class.

For each row: the column "diagnostic hints" lists grep targets and the canonical rule file that owns the area. Match aggressively — over-classifying is far less costly than under-classifying.

The 15 classes

Class Indicators in logs / chat Diagnostic hints Canonical rule
runner-subprocess subprocess.create.failed, subprocess.died_without_completion, runner_failed, signal exits (rc=143/137), JSONL parse errors, EventFactory misuse grep engine=<X> event=session.summary; check 3-event contract; verify proc_returncode and last_event_type runner-development.md
telegram-transport Outbox stuck, rate-limit 429, callback_data overflow, message-too-long, voice transcription failures, file upload denied, media-group dedup grep outbox, file_transfer, voice_transcription, rate_limit, 429; check TelegramOutbox invariants; verify callback_data ≤ 64 bytes telegram-transport.md
control-channel Approval buttons missing / stuck, PTY FD leak, ask-question crash, outline-gate bypass, ExitPlanMode re-issue loop, AskUserQuestion stuck-sequential grep control_request, control_response, _OUTLINE_PENDING, _PENDING_ASK_REQUESTS; check PTY finally cleanup; check session-registry cleanup control-channel.md
trigger-cron-webhook Cron fired wrong time / wrong tz, webhook 401/403/429/503, SSRF block, fetch-cron parse failure, hot-reload didn't apply, run_once re-fired grep triggers.cron.firing, triggers.dispatch, triggers.webhook, ssrf, triggers paused, config.reload; check timezone string in cron config; verify HMAC signature (none — see src/untether/triggers/)
session-resume-lock Wrong session resumed, stale resume token, session lock leak, registry not cleaned, /continue failures grep SessionLockMixin, lock_for, session_id, resume; check WeakValueDictionary cleanup; verify lock acquired before subprocess spawn runner-development.md
stall-liveness-watchdog subprocess.liveness_stall, subprocess.liveness_kill, stall_warning, peak_idle excessive, repeat stall_warnings on cron sessions grep liveness, stall, proc_diag, cpu_active; check tool_timeout vs mcp_tool_timeout; see systemic-patterns.md for by-design cases (cron + plan-mode) (none — see src/untether/utils/proc_diag.py)
auto-continue Auto-continue loops (death spiral), missing auto-continue (Claude exit with last_event_type=user), retry exhaustion, signal-death suppression bypass grep auto_continue, last_event_type, proc_returncode; check signal-death suppression (rc=143/137); verify [auto_continue].max_retries runner-development.md
config-hot-reload Restart-required key edited mid-run, hot-reload race, update_from() field copy missed, TelegramBridgeConfig corruption grep config.reload, restart_required, RESTART_REQUIRED_FIELDS; check update_from() field coverage; verify slot preservation; see feedback_agent_self_restart_pattern in MEMORY.md telegram-transport.md §TelegramBridgeConfig hot-reload
fleet-rollout fleet-rollout.sh failure, attestation marker missing, version mismatch across hosts, partial-rollback state check ~/.untether-dev/integration-test-pass-${VERSION}.json exists; check pipx list on each host; verify integration-test gate not bypassed release-discipline.md §Fleet rollout
outbox-delivery Files not delivered, deny-glob false-positive, size-limit hit, file-count cap, auto-cleanup didn't fire, file archived as stale (written before the run started, #924) grep outbox, outbox.stale, outbox.overflow, deny_glob, file_transfer; check .untether-outbox/ and .untether-outbox/.skipped/ in project; verify [transports.telegram.files] config (outbox_stale_policy) telegram-transport.md §Outbox file delivery
cost-budget Per-run budget exceeded silently, daily budget reset wrong, alert level skipped, auto-cancel didn't trigger grep cost_budget. (alert, run_blocked, run_stopped, run_anyway), cost_tracker.daily_; check cost_tracker.py + budget_gate.py + daily_cost.json; verify daily reset timezone (none — see src/untether/cost_tracker.py)
at-scheduler-cancel-restart /at delay lost on restart, /cancel didn't drop pending delay, /new orphan tasks, /restart drain timeout; Loop mode: loop fired uncapped, came back after /cancel or a resume, ⏰ Self-paced wake-up limit reached (#925, #926) grep at_scheduler, cancel.requested, shutdown.drain, _cancel_chat_tasks, loop. (loop.cli_job_denied, loop.restore); verify drain integration via at_scheduler.active_count(); check active_loops.json and [loop] own_schedule control-channel.md §Scheduling hooks for Loop mode; otherwise none — see src/untether/telegram/at_scheduler.py, loop_scheduler.py, commands/topics.py
help-faq-release-guard FAQ deleted/moved (hook block), guard-script edit blocked, force-push to master blocked, PR merge to master blocked, MCP write to master blocked check the hooks are registered in .claude/settings.json (#915) and bash .claude/hooks/tests/test-release-guard.sh passes; verify help-faq-protect.sh, release-guard.sh, release-guard-protect.sh, release-guard-mcp.sh; check docs/faq/faq.md exists and has ≥7 question-shaped H2s help-faq.md, release-discipline.md §Release guard
auto-error-watcher Watcher daemon stopped, false-positive filings, duplicate issues, wrong host tag, signature dedup miss check systemctl --user status untether-issue-watcher on each host; inspect ~/.local/state/untether-issue-watcher/seen.json; verify HOST env var (none — see MEMORY.md untether-issue-watcher section)
ci-pipeline-release-guard CI job failure (format/ruff/ty/pytest/build/lockfile/install-test/pip-audit/bandit/codeql/docs), validate_release.py reject, auto-tag-on-master skip on stable bump, OIDC publish failure check .github/workflows/; verify pyproject.toml version matches CHANGELOG.md heading; verify all changelog entries have [#N] links; check uv lock --check clean release-discipline.md, context-quality.md

Read the full file on GitHub · 65 lines

Changes

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.

  1. 18d ago Changed · +2 lines 1c7c6b376716
  2. 1mo ago First seen · 63 lines · 0 tokens per session scan A 757b2656ba40

Subscribe to this mod's changes

step-classify is a command published in the GitHub repository littlebearapps/untether (74 stars, last pushed today), licensed MIT. It costs nothing until one of its globs matches a file; then it loads 2,161 tokens. A static security scan graded it A with 1 finding (runs shell commands). No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.