Skip to content

feat: expose Claude thinking/reasoning controls via ASKCC_CLAUDE_* env vars and CLI flags #78

Description

@ellen-goc

Problem

Claude Code exposes several controls for extended thinking / reasoning that ClaudeRunner in askcc/runners.py does not currently pass through. For long-running background tasks (develop, plan, review), controlling thinking depth and budget is useful for balancing cost vs. reasoning depth.

The following are Claude Code native settings (not askcc settings). askcc does not currently expose or pass any of these to the claude subprocess:

Claude Code Setting Kind Values Purpose
--effort <level> Claude Code CLI flag low, medium, high, max Effort level for the current session
CLAUDE_CODE_EFFORT_LEVEL Claude Code env var low, medium, high, max, auto Effort level; takes precedence over --effort and /effort
MAX_THINKING_TOKENS Claude Code env var integer Thinking token budget
CLAUDE_CODE_DISABLE_THINKING Claude Code env var 1 Force-disable extended thinking regardless of model support
CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING Claude Code env var 1 Disable adaptive reasoning on Opus 4.6 / Sonnet 4.6 (falls back to fixed budget)

Sources:

Proposed Approach

Add env var defaults in askcc/settings.py using the ASKCC_CLAUDE_* prefix, and expose matching CLI flags on the top-level parser so they apply to every subcommand. Precedence: CLI flag > ASKCC_CLAUDE_* env var > Claude Code default.

1. askcc/settings.py

VALID_EFFORT_LEVELS: tuple[str, ...] = ("low", "medium", "high", "max")

ASKCC_CLAUDE_EFFORT_LEVEL: str | None = os.getenv("ASKCC_CLAUDE_EFFORT_LEVEL") or None
DEFAULT_MAX_THINKING_TOKENS = 21000  # ~5% of Max5 plan daily token budget (~422K tokens/day)

ASKCC_CLAUDE_MAX_THINKING_TOKENS: int = (
    int(os.environ["ASKCC_CLAUDE_MAX_THINKING_TOKENS"])
    if os.getenv("ASKCC_CLAUDE_MAX_THINKING_TOKENS", "").isdigit()
    else DEFAULT_MAX_THINKING_TOKENS
)
ASKCC_CLAUDE_DISABLE_THINKING: bool = os.getenv("ASKCC_CLAUDE_DISABLE_THINKING", "").lower() in ("1", "true")
ASKCC_CLAUDE_DISABLE_ADAPTIVE_THINKING: bool = os.getenv("ASKCC_CLAUDE_DISABLE_ADAPTIVE_THINKING", "false").lower() not in ("0", "false")

2. askcc/cli.py — top-level flags (apply to every subcommand)

parser.add_argument(
    "--effort",
    choices=VALID_EFFORT_LEVELS,
    default=settings.ASKCC_CLAUDE_EFFORT_LEVEL,
    help="Claude thinking effort level. Env default: ASKCC_CLAUDE_EFFORT_LEVEL.",
)
parser.add_argument(
    "--max-thinking-tokens",
    type=int,
    default=settings.ASKCC_CLAUDE_MAX_THINKING_TOKENS,
    help="Thinking token budget (default: 21000). Env default: ASKCC_CLAUDE_MAX_THINKING_TOKENS.",
)
parser.add_argument(
    "--disable-thinking",
    action="store_true",
    default=settings.ASKCC_CLAUDE_DISABLE_THINKING,
    help="Force-disable extended thinking. Env default: ASKCC_CLAUDE_DISABLE_THINKING.",
)
parser.add_argument(
    "--disable-adaptive-thinking",
    action=argparse.BooleanOptionalAction,
    default=settings.ASKCC_CLAUDE_DISABLE_ADAPTIVE_THINKING,
    help="Disable adaptive reasoning (Opus 4.6, Sonnet 4.6); default: true. Env default: ASKCC_CLAUDE_DISABLE_ADAPTIVE_THINKING.",
)

3. askcc/runners.py — wire through to child process

  • --effort is appended to cmd as a Claude CLI flag.
  • The three env vars are injected into the env dict passed to subprocess.run, after the existing env.pop("CLAUDECODE", None).
if effort_level:
    cmd.extend(["--effort", effort_level])
if max_thinking_tokens is not None:
    env["MAX_THINKING_TOKENS"] = str(max_thinking_tokens)
if disable_thinking:
    env["CLAUDE_CODE_DISABLE_THINKING"] = "1"
if disable_adaptive_thinking:
    env["CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING"] = "1"

The runner's run() signature gains these values — either threaded through as kwargs or bundled into a small ThinkingOptions dataclass constructed in cli.main() from the parsed args.

Acceptance Criteria

  • WHEN ASKCC_CLAUDE_EFFORT_LEVEL is set to a valid value, the system SHALL pass --effort <value> to claude.
  • WHEN --effort is passed on the askcc CLI, the system SHALL use that value, overriding the env var.
  • WHEN an invalid --effort value is provided, argparse SHALL reject it at the CLI layer.
  • WHEN an invalid ASKCC_CLAUDE_EFFORT_LEVEL value is set, the system SHALL log a warning and NOT pass --effort (Claude Code default applies).
  • WHEN ASKCC_CLAUDE_MAX_THINKING_TOKENS is set to a positive integer, the system SHALL export MAX_THINKING_TOKENS=<value> to the claude subprocess environment.
  • WHEN ASKCC_CLAUDE_MAX_THINKING_TOKENS is unset, the system SHALL default to 21000 (~5% of Max5 plan daily token budget).
  • WHEN ASKCC_CLAUDE_DISABLE_THINKING is truthy (1/true), the system SHALL export CLAUDE_CODE_DISABLE_THINKING=1 to the claude subprocess environment.
  • WHEN ASKCC_CLAUDE_DISABLE_ADAPTIVE_THINKING is unset, the system SHALL default to true (adaptive thinking disabled). Set to 0 or false to enable.
  • WHEN ASKCC_CLAUDE_DISABLE_ADAPTIVE_THINKING is truthy, the system SHALL export CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING=1 to the claude subprocess environment.
  • Unit tests SHALL cover: CLI flag overrides env var, env var sets runner state, invalid effort level rejected, no-op when unset.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions