Skip to content

feat: pick a turn a usage limit stopped back up once the limit resets - #673

Merged
omartelo merged 3 commits into
mainfrom
feat/auto-resume-after-limit
Oct 8, 2026
Merged

omartelo merged 3 commits into
mainfrom
feat/auto-resume-after-limit

Conversation

@omartelo

@omartelo omartelo commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

When a plan's usage limit stops a turn, lich now says so on the card and picks the turn back up once the limit resets. Gap #14 of the ADE triage (Claude Desktop week 33, cmux 0.65.0).

How each provider signals a limit (measured)

Provider Signal Reset time What lich does
Claude Code 2.1.293 StopFailure with error: "rate_limit" instead of Stop; a synthetic assistant line in the transcript quotaLimits.resetsAt on that line reads it on every done and parks the continuation
Codex 0.144.5 (codex exec) no hook: UserPromptSubmit fires, Stop never does; the rollout writes a token_count with a window at 100%, then task_complete with no message rate_limits.*.resets_at reads open Codex turns every 30s, ends the turn as interrupted, parks the continuation
opencode session.status retry only the next attempt nothing: it retries by itself
oh-my-pi auto_retry_start / auto_retry_end no nothing: it retries by itself
Antigravity, Crush, Cursor CLI, Kiro CLI no failure event no out, documented

Claude Code 2.1.293 also ships its own autoContinueAtUsageLimit, gated per account by the server (off on the account measured). lich lives with it rather than toggling it: see below.

Design

  • Signal. Claude: the plugin reports StopFailure as done (fix: report Claude Code's StopFailure as done lich-plugin#48), and noteLimit reads the limit off the transcript on every done. Codex: RunLimitWatch reads the rollout of each open Codex turn every 30s and ends a limited one through noteInterrupt, which also fixes the card spinning forever.
  • Continuation. relay.ParkResume parks a scheduled prompt (the existing one, later.go) due two minutes after the reset, so it shows on the card, survives a restart and is typed like any scheduled prompt. Nothing is parked for a reset already past or more than 24h out (Claude Code's own horizon), nor over a prompt already parked.
  • No double continuation. Any busy on that session before the prompt is due drops it (dropResume): the person going on by hand, Claude Code's own auto-continue (which resumes at the reset itself, hence the two-minute grace), or a relay delivery. A prompt the person parked in its place stays.
  • Card. A new amber rung: Session limit · resumes in 2h, or Weekly limit · resets Mon 09:00 when nothing will resume it. Cancelling goes through the existing Scheduled… item and its Cancel it.

Ceilings (in docs/ceilings.md)

  • The continuation is told apart from a person's prompt by its exact text (ponytail: in resume.go); a column on the row is the upgrade if that ever matters.
  • The Codex read is inferred from the rollout's shape and was measured on codex exec, not on the TUI.
  • The limit rung lives in the window only; a reload leaves the parked prompt as a plain scheduled one.

Provider support rows added to README.md and README.zh-CN.md; hook contract updated in docs/hooks/session-state.md (no new state, no fixture change).

Refactor: the card's status rung

SessionCard.tsx was already past the 800-line ceiling, and this adds one more rung to its ladder. The ladder, and the stores only it reads (relay, handoff, inbox, limit, todo, tool, waiting reason), move to SessionStatusRung.tsx; the card keeps one line and drops to ~710 lines.

render-budget.test.tsx changes because the contract did, not to buy a green run: the rung is a child the card repaints with, so it joins CARD_CHROME, and a todo event now repaints the rung alone instead of the whole card (narrower than before).

Tests

  • internal/terminal/limit_test.go: transcript and rollout readers, against the lines measured on a real Claude transcript and a Codex rig (fake responses endpoint answering usage_limit_reached).
  • internal/terminal/limit_service_test.go (!windows, reuses stubBins): done on a Claude limit parks the resume; the watch ends a limited Codex turn.
  • internal/relay/resume_test.go: park, horizon, the person's prompt, drop on busy.
  • Frontend: session-limit-store.test.ts, limit-line.test.ts.

Local gate: gofmt, go vet, go test ./..., the cross-compile loop, biome ci (exit 0), vitest with coverage (1973 passing), pnpm build. The new async tests ran 100 times clean.

Needs lichdotdev/lich-plugin#48 for Claude Code; Codex works without it.

@omartelo omartelo added the ci:os Runs the backend suite on Windows and macOS runners label Oct 8, 2026
@omartelo
omartelo force-pushed the feat/auto-resume-after-limit branch 3 times, most recently from 9303962 to a96d23f Compare October 8, 2026 15:19
Claude Code reports the turn through StopFailure (lich-plugin), and lich
reads the limit and its reset off the transcript on every done. Codex
reports nothing, so open Codex turns are read off their rollout every 30s
and ended as interrupted. The continuation is a scheduled prompt due two
minutes after the reset, within 24h, dropped by any turn that starts
first; the card shows the limit on a rung of its own.
SessionCard was past the 800-line ceiling, and the usage-limit rung added
one more branch to the ladder. The ladder and the stores only it reads
move to SessionStatusRung; the card keeps one line.

render-budget changes because the contract did: the rung is now a child
the card repaints with (CARD_CHROME), and a todo event repaints the rung
alone instead of the whole card.
@omartelo
omartelo force-pushed the feat/auto-resume-after-limit branch from a96d23f to ef49639 Compare October 8, 2026 15:25
@omartelo
omartelo merged commit d06c0fb into main Oct 8, 2026
7 checks passed
@omartelo
omartelo deleted the feat/auto-resume-after-limit branch October 8, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:os Runs the backend suite on Windows and macOS runners

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant