docs(rules): auto-load rule against 'Holding' without named dependency (Aaron's CLAUDE.md question)#3029
Merged
Conversation
…e mode (auto-load rule per Aaron's CLAUDE.md question) Aaron 2026-05-13 caught Otto in the Standing-by failure mode for the third time in one session, asking: "maybe something in claude.md needs to change?" The rules already auto-load from .claude/rules/ per the cold-boot mechanism (.claude/rules/claude-code-loading-taxonomy.md). The existing .claude/rules/never-be-idle.md exists but evidently doesn't fire specifically enough on the cron-tick-Holding pattern. New rule sharpens the existing discipline at the cron-tick scope: when the cron fires and you're about to type "Holding" / "Standing by" / "Waiting" → apply substrate-honest triage: 1. Is there a SPECIFIC named dependency with bounded ETA? → say so. 2. If NO → you're in Standing-by failure mode. Per infinite-backlog metabolism, decomposition work always exists. Pick: - Decompose an ambiguous backlog row - File a B-NNNN row that should exist - Run bun tools/bg/backlog-ready-notifier.ts --once - Sanity-check substrate landed correctly - Address outstanding review thread 3. Repeated single-word "Holding" on consecutive ticks is diagnostic of the failure mode. Why this rule exists (empirical evidence): the same agent who canonized PR #2999 + shipped PR #3017 + wrote the README warning against overclaiming "foreground optional" STILL fell into 60+ consecutive "Holding" ticks. Aaron caught it three times. Encoding rules without mechanizing produces a memory of failures (per .claude/rules/encoding-rules-without-mechanizing.md). This rule IS the mechanization at the cold-boot scope. Composes with: - never-be-idle.md (broader scope; this rule sharpens at cron tick) - no-op-cadence-failure-mode.md (multi-hour scope) - encoding-rules-without-mechanizing.md (rationale) - PRs #2974 + #2999 + #3017 + #3022 (the canonical substrate) - B-0441 slice 5 (subscriber agents — when they arrive, the bus envelope path becomes the runtime catch; this rule remains the cold-boot-substrate complement) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a new auto-loaded rule file that sharpens the never-be-idle discipline at the cron-tick scope: emitting bare "Holding"/"Standing by"/"Waiting" without naming a specific dependency + bounded ETA is treated as the Standing-by failure mode the B-0440 detector targets. The rule prescribes a 3-step substrate-honest triage and composes with existing rules and the B-0440 detector slices.
Changes:
This was referenced May 13, 2026
AceHack
added a commit
that referenced
this pull request
May 13, 2026
… registration (#3034) * feat(routines): git-tracked Claude Desktop routines substrate + autonomous-loop registration Aaron asked for a power-user / scripting / version-control path for Claude Desktop scheduled tasks (the "Routines" sidebar panel), composed with the existing CLI <<autonomous-loop>> cron substrate. This introduces tools/routines/ as canonical-source-of-truth for Desktop routines and registers the first one (autonomous-loop) as a Desktop-side every-2-hour fallback for the CLI every-minute tick. Two-layer architecture: tools/routines/<id>/ — git-tracked canonical (SKILL.md + schedule.json) ~/.claude/scheduled-tasks/ — runtime location, generated from canonical tools/routines/install.ts — idempotent Bun TS installer (rule-0 compliant) The scheduled-tasks MCP server is cross-host — same server wired into both CLI Claude Code and Claude Desktop. Both surfaces read/write the same disk store. This PR makes the prompt-body authoring path git-canonical so routines are diffable, PR-reviewable, and shareable across maintainer machines. Three-layer catch-43 defence now in place: 1. CLI session cron — every minute, cheap re-prompt, dies on exit 2. Desktop routine — every 2 hours, persistent cold-boot, survives restart 3. tools/routines/ repo — git canonical, survives runtime corruption Composes with: - .claude/rules/tick-must-never-stop.md (catch-43 substrate) - .claude/rules/rule-0-no-sh-files.md (TS installer, not bash) - .claude/rules/holding-without-named-dependency-is-standing-by-failure.md (PR #3029) - .claude/rules/dv2-data-split-discipline-activated.md (canonical vs runtime change-rate split) - docs/AUTONOMOUS-LOOP.md (canonical tick procedure) Tick shard: docs/hygiene-history/ticks/2026/05/13/2125Z.md Co-Authored-By: Claude <noreply@anthropic.com> * fix(routines): address PR #3034 reviewer feedback — tsc + portability + testability Bundles all 7 review findings from PR #3034 into one commit: install.ts - Fix tsc exactOptionalPropertyTypes violations (was the BLOCKING required check failure) - Eliminate TOCTOU races: replace existsSync+readFileSync pairs with try/catch around readFileSync via readFileOrUndefined helper (addresses CodeQL alert) - Surface invalid schedule.json instead of silently swallowing parse failures: new scheduleParseError field + console.error + parseErrors summary count (Codex P2) - Export listRoutines/readSchedule/syncRoutine/main with directory parameters so tests can drive deterministically without touching real homedir() or import.meta.dir (Copilot test-coverage suggestion; actual test suite is a follow-up) - Gate main() under if (import.meta.main) — aligns with other tools/** scripts that use the importable/testable pattern (Copilot) autonomous-loop/SKILL.md - Remove hardcoded /Users/acehack/Documents/src/repos/Zeta path from routine prompt (Codex P1, Copilot duplicate). Now portable across maintainer machines via "typically ~/Documents/src/repos/Zeta" guidance + project-metadata fallback. Installer will sync the new prompt to the live runtime SKILL.md on next run; the next routine fire (22:07Z) picks up the portable version. README.md - Fix Rule 0 wording: was "only `.sh` allowed there" (implied tools/setup/ is .sh-only); now ".sh files are restricted to under tools/setup/; other formats also live there" (matches .claude/rules/rule-0-no-sh-files.md) (Copilot) docs/hygiene-history/ticks/2026/05/13/2125Z.md - Update pr: TBD → pr: 3034 (Copilot — placeholder breaks consumers that parse frontmatter) Verify trace: 1. npx tsc --noEmit on routines files: clean ✓ 2. bun tools/routines/install.ts: [updated] autonomous-loop, parseErrors=0 ✓ 3. Runtime SKILL.md at ~/.claude/scheduled-tasks/autonomous-loop/SKILL.md now portable Follow-up (not in this commit): add bun:test test suite for install.ts (Copilot suggestion; refactor for testability landed here so the suite can land cleanly). Co-Authored-By: Claude <noreply@anthropic.com> * fix(lint): markdownlint MD037/MD032 in routines SKILL.md and tick shard - SKILL.md:16 — wrap cron expression in backtick span to avoid MD037 (asterisks in "* * * * *" were parsed as emphasis markers) - 2125Z.md:43 — add blank line before list to satisfy MD032 (markdownlint requires blank lines surrounding lists) Co-Authored-By: Claude <noreply@anthropic.com> * docs(memory): land split-brain empirical observation + tick shard 2140Z Real-time observation: Otto-CLI hijacked the primary worktree branch context while Otto-Desktop was working there, in the SAME session that Otto-CLI authored PR #3032's claim-acquire-before-worktree rule. The rule was speculative when proposed; this observation is its first empirical validation. Files: - memory/feedback_split_brain_real_time_otto_cli_otto_desktop_primary_worktree_branch_hijack_pr_3032_claim_acquire_rule_validation_2026_05_13.md - docs/hygiene-history/ticks/2026/05/13/2140Z.md The memory extends PR #3032's rule operationally — adds 3 clauses beyond "claim acquire before worktree work": 1. Each Otto gets ONE dedicated worktree (never share primary) 2. Never git checkout on a worktree another Otto is using 3. Bus claim envelope should include 'worktree' field Composes with PR #3032 (validates), substrate-or-it-didn't-happen (rules in flight don't apply to behavior in flight), glass-halo-bidirectional (observation enabled diagnosis). Co-Authored-By: Claude <noreply@anthropic.com> * fix(memory): add required frontmatter to split-brain observation memory The non-required CI check "check memory file frontmatter completeness" flagged the file. Added YAML frontmatter (name/description/type) matching the convention used by other memory/feedback_*.md files. Co-Authored-By: Claude <noreply@anthropic.com> * fix(routines): surface missing cronExpression + always emit registration hint P1: registration hint was gated on action=created|updated, so a schedule-only change (SKILL.md unchanged) silently skipped the create_scheduled_task reminder. Remove the action emitfilter the hint whenever cronExpression is present, regardless of action. P2: readSchedule returned { missing: false } with no parseError when schedule.json parsed but lacked cronExpression, producing a silent misconfiguration. Now surfaces a descriptive parseError so the caller prints the malformed-schedule warning. Addresses chatgpt-codex-connector review threads on PR #3034. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(routines): remove persona-name attribution + clarify schedule.json optionality Two Copilot review threads on PR #3034: install.ts (Copilot — BP "No name attribution in code"): - Doc comment said "ask Otto (or call directly) to run create_scheduled_task" - Console output said "(in a Claude session, ask Otto to run create_scheduled_task for each)" - Both replaced with persona-agnostic phrasing: "invoke create_scheduled_task from an interactive Claude session (or via direct MCP API call)" README.md (Copilot — internal consistency): - Top-level routine description said each routine has SKILL.md + schedule.json without noting schedule.json is optional - But installer explicitly supports missing schedule.json (ad-hoc routines) - Now: SKILL.md marked **required**, schedule.json marked **optional** with the ad-hoc clarification both in the bullet list and in the Authoring section Verify trace: - bun tools/routines/install.ts → [skipped-unchanged] (idempotent confirmed) - npx tsc --noEmit → clean on routines files Co-Authored-By: Claude <noreply@anthropic.com> * fix(routines): validate cronExpression type + non-zero exit on parse errors (Codex P2 x2) Two P2 findings from Codex on PR #3034: 1. Reject non-string cronExpression values (PRRT_kwDOSF9kNM6B5oEP): readSchedule now narrows parsed.cronExpression via typeof === "string" before accepting it. Non-string values (number, null, object) return a parseError with the offending type. Defends against schedule.json files that happen to round-trip through JSON but have semantically wrong types. 2. Fail installer when schedule parsing reports errors (PRRT_kwDOSF9kNM6B5oEU): main() now returns an exit code (0 on success, 1 if parseErrors > 0). The if (import.meta.main) entrypoint calls process.exit(main()) so CI catches malformed schedule.json files instead of silently counting them in the summary and exiting 0. Verify trace: - bun tools/routines/install.ts (clean run): exits 0, parseErrors=0 ✓ - npx tsc --noEmit: clean on routines files ✓ Co-Authored-By: Claude <noreply@anthropic.com> * docs(tick): 2150Z shard — PR #3034 thread sweep + Computer-Use framing correction Co-Authored-By: Claude <noreply@anthropic.com> * fix(memory): add missing created field to split-brain observation frontmatter The memory-index-integrity CI gate requires all four frontmatter fields: name, description, type, created. The prior fix commit (459a511) added the other three fields but omitted created. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(routines): more reviewer fixes — persona refs, read-error surfacing, empty cron rejection Four threads addressed (3 P1 + 2 P2 from Codex/Copilot on PR #3034): install.ts: - readFileOrUndefined now distinguishes ENOENT (returns undefined → "missing file") from other errors (re-throws → installer fails loudly). Permission errors, IO failures no longer silently treated as missing. (Codex P2, Copilot P1) - readSchedule now rejects empty cronExpression strings with parseError "cronExpression must be a non-empty string". (Codex P2) autonomous-loop/SKILL.md + README.md: - Remove remaining "Otto" persona attribution per BP "No name attribution in code" on current-state surfaces under tools/. SKILL.md description + first paragraph now use "Autonomous-loop tick" without persona claim. README.md "Ask Otto" rephrased to direct MCP invocation; "Otto bootstream" rephrased to "canonical bootstream" with note that the literal filename is historical-surface substrate. (Copilot P1) Identity-stays-unified substrate (PR #3036) is preserved — the fresh-session that fires this routine identifies as Otto via the bootstream's Part 1, not via the routine prompt itself. Routine prompt is functional description; identity is established at cold-boot. Deferred to follow-up row: bun:test coverage for install.ts (Copilot P1 thread 5). Refactor for testability already shipped (exported pure functions accept directory params); actual test suite is its own task — will file as a separate backlog row. Verify trace: - bun tools/routines/install.ts: exits 0, parseErrors=0 ✓ - npx tsc --noEmit: clean on routines files ✓ Co-Authored-By: Claude <noreply@anthropic.com> * fix(routines): listRoutines + missing-SKILL.md surface failures (Codex P1 + P2) Same silent-failure-prevention pattern as readFileOrUndefined: 1. listRoutines now distinguishes ENOENT (returns empty array — the no --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Aaron 2026-05-13 caught Otto in the Standing-by failure mode for the third time in one session and asked: "maybe something in claude.md needs to change?"
Adds a single auto-load rule at `.claude/rules/holding-without-named-dependency-is-standing-by-failure.md` that:
Why a new rule vs CLAUDE.md edit
The existing `.claude/rules/never-be-idle.md` covers the broader discipline, but evidently doesn't fire specifically enough on the cron-tick-Holding pattern. New rule sharpens at cron-tick scope. Auto-loads at session start per the cold-boot mechanism, so no CLAUDE.md edit needed (CLAUDE.md stays tight per the "thoughts free, actions razored" convention).
Operational evidence
The same agent who canonized PR #2999 + shipped PR #3017 + wrote the README warning against overclaiming "foreground optional" STILL fell into 60+ consecutive "Holding" ticks today. Encoding rules without mechanizing produces a memory of failures (per
.claude/rules/encoding-rules-without-mechanizing.md). This rule IS the mechanization at cold-boot scope.Composes with
never-be-idle.md(broader scope sharpened at cron tick)no-op-cadence-failure-mode.md(multi-hour scope)encoding-rules-without-mechanizing.md(rationale)🤖 Generated with Claude Code