Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,62 @@ Edit any file to customize the agent's behavior. User prompt templates **must**

Override the config directory by setting the `ASKCC_HOME` environment variable (e.g. for testing).

#### Subagent Frontmatter

Each `*_SYSTEM_PROMPT.md` template may begin with a [Claude Code subagent](https://code.claude.com/docs/en/subagents.md)–style YAML frontmatter block that declares the agent's tool surface, model, and reasoning effort:

```markdown
---
name: develop
description: Develops a planned/defined issue
tools: Read, Write, Edit, Bash, Grep, Glob
model: opus
effort: max
max_thinking_tokens: 32000
max_turns: 200
---
You are an expert software developer ...
```

Recognized fields (all optional):

| Field | Type | Allowed values |
|---|---|---|
| `name` | string | informational |
| `description` | string | informational |
| `tools` | comma-separated list | translated to `--allowedTools` (e.g. `Read, Bash(gh:*)`) |
| `disallowed_tools` | comma-separated list | translated to `--disallowedTools` |
| `model` | string | `opus`, `sonnet`, `haiku`, `inherit` |
| `effort` | string | `low`, `medium`, `high`, `xhigh`, `max` |
| `max_thinking_tokens` | integer | thinking token budget |
| `max_turns` | integer | translated to `--max-turns` |

Templates without frontmatter continue to work unchanged. Invalid values (e.g. `model: opuz`, `effort: turbo`) raise a clear error at load time rather than mid-run.

##### Per-Action Defaults

| Action | tools | model | effort |
|---|---|---|---|
| `prepare` | `Read, Grep, Glob, Bash(gh:*)` | `sonnet` | `medium` |
| `plan` | `Read, Grep, Glob, Bash(gh:*)` | `opus` | `high` |
| `develop` | `Read, Write, Edit, Bash, Grep, Glob` | `opus` | `max` |
| `issue-review` | `Read, Grep, Glob, Bash(gh:*)` | `sonnet` | `medium` |
| `pr-review` | `Read, Grep, Glob, Bash(gh:*,git:*)` | `opus` | `high` |
| `explore` | `Read, Grep, Glob, Bash(gh:*)` | `sonnet` | `high` |
| `diagnose` | `Read, Grep, Glob, Bash(gh:*,git:*)` | `sonnet` | `high` |
| `fix-ci` | `Read, Write, Edit, Bash, Grep, Glob` | `sonnet` | `high` |

Note: askcc runs `claude` with `--dangerously-skip-permissions` so it can execute unattended; the per-action `tools` allowlist is the safety boundary that narrows what each agent can call.

##### Override Precedence

For `effort` and `max_thinking_tokens`, askcc resolves the effective value in this order (highest wins):

1. Explicit CLI flag (`--effort`, `--max-thinking-tokens`)
2. Environment variable (`ASKCC_CLAUDE_EFFORT_LEVEL`, `ASKCC_CLAUDE_MAX_THINKING_TOKENS`)
3. Template frontmatter (per-action default in `~/.askcc/templates/`)
4. Built-in default (`xhigh`, `21000`)

### Post-Develop Verification

After the `develop` command completes successfully, askcc can run verification commands (tests, linting, type checks) before transitioning the issue to `action:review`. This is **optional** — if no verification config is found, the transition proceeds without checks.
Expand Down
48 changes: 40 additions & 8 deletions askcc/cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import argparse
import logging
import os
import subprocess
import sys
import tempfile
Expand Down Expand Up @@ -55,6 +56,33 @@ def _build_prompt(
return prompt, tempfiles


def _resolve_effort(cli_effort: str | None, frontmatter_effort: str | None) -> str:
"""Precedence: CLI flag > env var > template frontmatter > built-in default."""
if cli_effort is not None:
return cli_effort
env_value = os.environ.get("ASKCC_CLAUDE_EFFORT_LEVEL", "")
if env_value:
try:
return VALID_EFFORT_LEVELS(env_value).value
except ValueError:
logger.warning("Invalid ASKCC_CLAUDE_EFFORT_LEVEL=%r — falling through to frontmatter/default", env_value)
if frontmatter_effort is not None:
return frontmatter_effort
return settings.DEFAULT_EFFORT_LEVEL


def _resolve_max_thinking_tokens(cli_value: int | None, frontmatter_value: int | None) -> int:
"""Precedence: CLI flag > env var > template frontmatter > built-in default."""
if cli_value is not None:
return cli_value
raw_env = os.environ.get("ASKCC_CLAUDE_MAX_THINKING_TOKENS", "")
if raw_env.isdigit():
return int(raw_env)
if frontmatter_value is not None:
return frontmatter_value
return settings.DEFAULT_MAX_THINKING_TOKENS


def _print_validation_report(issue_url: str, checks: list[CheckResult]) -> None:
"""Print a structured pass/fail validation report."""
passed_count = sum(1 for c in checks if c.passed)
Expand Down Expand Up @@ -108,16 +136,18 @@ def main() -> None: # noqa: PLR0912, PLR0915, C901
parser.add_argument(
"--effort",
choices=VALID_EFFORT_LEVELS,
default=settings.ASKCC_CLAUDE_EFFORT_LEVEL,
help=f"Claude thinking effort level (default: {settings.ASKCC_CLAUDE_EFFORT_LEVEL}). "
"Env: ASKCC_CLAUDE_EFFORT_LEVEL.",
default=None,
help=f"Claude thinking effort level. "
f"Precedence: CLI > env (ASKCC_CLAUDE_EFFORT_LEVEL) > template frontmatter > "
f"built-in default ({settings.DEFAULT_EFFORT_LEVEL}).",
)
parser.add_argument(
"--max-thinking-tokens",
type=int,
default=settings.ASKCC_CLAUDE_MAX_THINKING_TOKENS,
help=f"Thinking token budget (default: {settings.ASKCC_CLAUDE_MAX_THINKING_TOKENS}). "
"Env: ASKCC_CLAUDE_MAX_THINKING_TOKENS.",
default=None,
help=f"Thinking token budget. "
f"Precedence: CLI > env (ASKCC_CLAUDE_MAX_THINKING_TOKENS) > template frontmatter > "
f"built-in default ({settings.DEFAULT_MAX_THINKING_TOKENS}).",
)
parser.add_argument(
"--disable-thinking",
Expand Down Expand Up @@ -250,14 +280,16 @@ def main() -> None: # noqa: PLR0912, PLR0915, C901
if args.language != SupportedLanguage.ENGLISH:
prompt += f"\nOutput all comments in {args.language}."
runner = get_runner(args.runner)
effort_level = _resolve_effort(args.effort, config.effort)
max_thinking_tokens = _resolve_max_thinking_tokens(args.max_thinking_tokens, config.max_thinking_tokens)
try:
return_code, usage = runner.run(
prompt,
config=config,
issue_url=issue_url,
cwd=cwd,
effort_level=args.effort,
max_thinking_tokens=args.max_thinking_tokens,
effort_level=effort_level,
max_thinking_tokens=max_thinking_tokens,
disable_thinking=args.disable_thinking,
disable_adaptive_thinking=args.disable_adaptive_thinking,
)
Expand Down
80 changes: 80 additions & 0 deletions askcc/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@

PREPARE_AGENT_PROMPT = (
"""\
---
name: prepare
description: Analyzes a backlog issue for development readiness and suggests improvements
tools: Read, Grep, Glob, Bash(gh:*)
model: sonnet
effort: medium
---
You are an issue preparation specialist operating inside Claude Code with access to the filesystem, git, and the gh CLI.

Goal: Analyze the given GitHub issue for development readiness and post a structured preparation comment \
Expand Down Expand Up @@ -108,6 +115,13 @@

PLAN_AGENT_PROMPT = (
"""\
---
name: plan
description: Plans implementation for given issue
tools: Read, Grep, Glob, Bash(gh:*)
model: opus
effort: high
---
You are a software architect operating inside Claude Code with access to the filesystem, git, and the gh CLI.

Goal: Analyze the given GitHub issue against this project's codebase and produce a structured implementation plan.
Expand Down Expand Up @@ -164,7 +178,19 @@
"""
)

# NOTE: develop and fix-ci require write access (Edit/Write/Bash) to actually
# implement changes and run tests. The runner currently passes
# `--dangerously-skip-permissions` globally so all actions run unattended; the
# tools allowlist below is the per-action safety boundary for these write-capable
# agents.
DEVELOP_AGENT_PROMPT = f"""\
---
name: develop
description: Develops a planned/defined issue
tools: Read, Write, Edit, Bash, Grep, Glob
model: opus
effort: max
---
You are an expert software developer operating inside Claude Code with access to the filesystem, git, and the gh CLI.

Goal: Implement the planned GitHub issue, open a pull request, and link it back to the issue.
Expand Down Expand Up @@ -260,6 +286,13 @@

REVIEW_AGENT_PROMPT = (
"""\
---
name: issue-review
description: Reviews a GitHub issue for clarity, completeness, and feasibility
tools: Read, Grep, Glob, Bash(gh:*)
model: sonnet
effort: medium
---
You are an issue reviewer operating inside Claude Code with access to the filesystem, git, and the gh CLI.

Goal: Review the given GitHub issue for clarity, completeness, and feasibility, then post actionable feedback \
Expand Down Expand Up @@ -297,6 +330,13 @@

EXPLORE_AGENT_PROMPT = (
"""\
---
name: explore
description: Investigates a GitHub issue and proposes best-practice solutions
tools: Read, Grep, Glob, Bash(gh:*)
model: sonnet
effort: high
---
You are a solutions architect operating inside Claude Code with access to the filesystem, git, and the gh CLI.

Goal: Investigate the given GitHub issue, research the codebase, and propose best-practice solutions with trade-offs.
Expand Down Expand Up @@ -351,6 +391,13 @@

DIAGNOSE_AGENT_PROMPT = (
"""\
---
name: diagnose
description: Investigates a reported issue and identifies potential causes
tools: Read, Grep, Glob, Bash(gh:*,git:*)
model: sonnet
effort: high
---
You are a diagnostic engineer operating inside Claude Code with access to the filesystem, git, and the gh CLI.

Goal: Investigate the reported issue, identify potential root causes, flag unknowns, and request additional \
Expand Down Expand Up @@ -403,6 +450,13 @@

REVIEWPR_AGENT_PROMPT = (
"""\
---
name: pr-review
description: Reviews a pull request against its linked issue's Definition of Done
tools: Read, Grep, Glob, Bash(gh:*,git:*)
model: opus
effort: high
---
You are a code reviewer operating inside Claude Code with access to the filesystem, git, and the gh CLI.

Goal: Review the pull request linked to the given GitHub issue, verify it meets the Definition of Done, \
Expand Down Expand Up @@ -476,7 +530,17 @@
)


# See note above DEVELOP_AGENT_PROMPT — fix-ci is a write-capable action that
# needs Edit/Write/Bash to apply CI fixes; rely on the tools allowlist below for
# the per-action safety boundary.
FIXCI_AGENT_PROMPT = """\
---
name: fix-ci
description: Identifies failing CI checks on the current PR or branch and implements fixes
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
effort: high
---
You are a CI fix specialist operating inside Claude Code with access to the filesystem, git, and the gh CLI.

Goal: Identify failing CI checks on the current PR or branch and implement fixes to make them pass.
Expand Down Expand Up @@ -542,6 +606,22 @@ class AgentConfig:
system_prompt_file: str
user_prompt_file: str
required_variables: tuple[str, ...] = ()
# Subagent-style frontmatter fields — populated from the system_prompt's
# leading `---`-delimited block by load_agent_config when present.
tools: tuple[str, ...] | None = None
disallowed_tools: tuple[str, ...] | None = None
model: str | None = None
effort: str | None = None
max_thinking_tokens: int | None = None
max_turns: int | None = None


# Allowed values for frontmatter enum fields (validated at load time).
VALID_FRONTMATTER_MODELS: tuple[str, ...] = ("opus", "sonnet", "haiku", "inherit")
# Frontmatter keys recognized by the parser. Unknown keys are warned and ignored.
KNOWN_FRONTMATTER_KEYS: frozenset[str] = frozenset(
{"name", "description", "tools", "disallowed_tools", "model", "effort", "max_thinking_tokens", "max_turns"}
)


class SupportedLanguage(StrEnum):
Expand Down
Loading
Loading