Skip to content

feat: autonomous (cron) session turn cap#17

Merged
nyem69 merged 9 commits into
mainfrom
feat/autonomous-session-turn-cap
Jun 2, 2026
Merged

feat: autonomous (cron) session turn cap#17
nyem69 merged 9 commits into
mainfrom
feat/autonomous-session-turn-cap

Conversation

@nyem69

@nyem69 nyem69 commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Caps autonomous cron Claude sessions via the CLI's --max-turns ceiling + an
advisory prompt contract, and classifies a ceiling-hit as a distinct
session_budget_stop (not a generic error). Targets the marathon-session spend
concentration (top ~2% of sessions ≈ 80% of cost; ≥200-turn sessions ≈ 90%).

Design: docs/superpowers/specs/2026-06-03-autonomous-session-turn-cap-design.md
Plan: docs/superpowers/plans/2026-06-03-autonomous-session-turn-cap.md

What it does

  • New sessions/budget.ts: cap resolution, contract prompt, stop classification (unit-tested).
  • --max-turns <cap> passed to the Claude CLI for cron sessions; default 300,
    per-job maxTurns override, opt-out via sessionBudget.hardCap:false.
  • Budget stop classified strictly on result.subtype === "error_max_turns"
    (never turn count), before dead-session/rate-limit handling; carried through
    the rate-limit retry path. Codex fallback is advisory-only (no hard cap).
  • EngineResult.subtype now captured generically; ClaudeEngine.run never
    transient-retries a budget stop.
  • Runlog session_budget_stop (distinct from success/error) + ops alert
    only for sessionBudget.sideEffects:true jobs.

Scope

  • cron only (v1). Web/API uses dispatchWebSessionRun (separate path);
    interactive is covered by the shipped UserPromptSubmit guard. sdk source
    doesn't exist yet. No continuation-artifact schema in v1 (deferred to steward data).

Known gap (documented)

A mutating cron without sessionBudget.sideEffects:true produces a runlog-only
(Telegram-silent) budget stop. Owners of write/deliver jobs must opt in.

Testing

  • 754 unit tests green (budget.test.ts + --max-turns arg cases added); typecheck clean.
  • Live E2E smoke against the running gateway with a maxTurns:3 throwaway cron:
    runlog → {"status":"session_budget_stop","maxTurns":3,"actualTurns":4},
    session row → interrupted | session_budget_stop: hit max-turns cap (3),
    ops-alert fired (sideEffects-gated). Throwaway job removed (byte-exact restore).

🤖 Generated with Claude Code

nyem69 and others added 9 commits June 3, 2026 03:28
CLI --max-turns ceiling + advisory prompt contract + session_budget_stop
runlog classification for cron/sdk sessions. Scoped per brainstorming;
interactive covered by the shipped UserPromptSubmit guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ering

- sdk source doesn't exist yet; scope v1 to source=='cron' (web/api uses
  dispatchWebSessionRun, separate design)
- rate-limit retry engine.run must carry maxTurns + re-classify; Codex
  fallback advisory-only (no hard cap)
- classify error_max_turns FIRST, before dead-session/rate-limit handling
- intentional no transient-retry on error_max_turns in ClaudeEngine.run
- append budget contract AFTER pre-session hooks (hook may replace prompt)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7 TDD tasks: schema, budget.ts core (tested), --max-turns arg, subtype
capture + no-retry, runSession wiring (incl. retry path), runner runlog +
alert, end-to-end smoke. Full code per step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gineResult.subtype, CronJob.maxTurns/sessionBudget, sessions.budget)
@nyem69 nyem69 merged commit d9c0cf9 into main Jun 2, 2026
3 checks passed
@nyem69 nyem69 deleted the feat/autonomous-session-turn-cap branch June 2, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant