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
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,44 @@ 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).

### 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.

Configure verification commands in either of these files (checked in order):

#### `pyproject.toml`

```toml
[[tool.askcc.verify]]
name = "tests"
cmd = "uv run poe test"

[[tool.askcc.verify]]
name = "lint"
cmd = "uv run poe check"

[[tool.askcc.verify]]
name = "typecheck"
cmd = "uv run poe typecheck"
```

#### `.askcc.toml`

For non-Python projects or when `pyproject.toml` is not used:

```toml
[[verify]]
name = "tests"
cmd = "npm test"

[[verify]]
name = "lint"
cmd = "npm run lint"
```

Each entry requires a `name` (used in log output) and `cmd` (shell command to run). If any command fails, the issue label stays at `action:develop` and the failure details are logged. Each command has a 5-minute timeout.

### Examples

Prepare a backlog issue for development:
Expand Down
13 changes: 10 additions & 3 deletions askcc/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from .functions import (
CheckResult,
_parse_issue_url,
_run_project_verification,
append_usage_to_last_comment,
bootstrap_templates,
fetch_github_issue,
Expand Down Expand Up @@ -201,8 +202,7 @@ def main() -> None: # noqa: PLR0912, PLR0915, C901
sys.exit(1)
issue_url = pr_result.stdout.strip()
ci_context = (
f"Auto-detected PR: {issue_url}\n\n"
"No linked issue provided. Use the PR URL above to find CI failures."
f"Auto-detected PR: {issue_url}\n\nNo linked issue provided. Use the PR URL above to find CI failures."
)
with tempfile.NamedTemporaryFile(mode="w", prefix="askcc_fix-ci_", suffix=".md", delete=False) as f:
f.write(ci_context)
Expand Down Expand Up @@ -264,7 +264,14 @@ def main() -> None: # noqa: PLR0912, PLR0915, C901
transition_issue_to_planning(issue_url)

if action == AgentAction.DEVELOP and return_code == 0:
transition_issue_to_review(issue_url)
verify_result = _run_project_verification(cwd)
if verify_result.passed:
transition_issue_to_review(issue_url)
else:
logger.warning("Post-develop verification failed: %s", verify_result.message)
for check in verify_result.checks:
status = "PASS" if check.passed else "FAIL"
logger.warning(" [%s] %s: %s", status, check.name, check.message)

sys.exit(return_code)

Expand Down
19 changes: 19 additions & 0 deletions askcc/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,25 @@
- No hardcoded credentials or connection strings — use environment variables or secrets management.
- No overly permissive file or network access introduced by the change.

PR description:
- Include a `## Key Flows` section with mermaid diagrams illustrating the main flows \
introduced or changed by this PR. Focus on control flow, data flow, or state transitions \
that help the reviewer understand the change at a glance. Example:
```
## Key Flows

```mermaid
flowchart TD
A[develop completes] --> B{{verification configured?}}
B -- yes --> C[run checks]
B -- no --> D[transition to review]
C -- all pass --> D
C -- any fail --> E[stay in develop]
`` `
```
- Keep diagrams concise — one or two diagrams covering the most important flows. \
Skip this section if the change is trivial (e.g. config-only, docs-only, single-line fix).

On completion:
- Run /simplify or /refactor to simplify and improve the code.
- Commit, push the feature branch, and open a PR linked to the issue.
Expand Down
81 changes: 81 additions & 0 deletions askcc/functions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import json
import logging
import re
import shlex
import shutil
import subprocess
import tempfile
import tomllib
from dataclasses import dataclass, replace
from importlib.resources import files as package_files
from pathlib import Path
Expand Down Expand Up @@ -208,6 +210,85 @@ class CheckResult:
message: str


@dataclass(frozen=True)
class VerificationResult:
passed: bool
message: str
checks: list[CheckResult]


VERIFICATION_TIMEOUT = 300 # 5 minutes per command


def _detect_verification_commands(cwd: Path) -> list[tuple[str, list[str]]]:
"""Load user-configured verification commands from project config.

Checks (in order):
1. ``[tool.askcc.verify]`` in ``pyproject.toml``
2. ``[[verify]]`` in ``.askcc.toml``

Returns a list of (check_name, command_args) tuples.
If no config is found, returns an empty list (verification is skipped).
"""
pyproject = cwd / "pyproject.toml"
if pyproject.exists():
try:
data = tomllib.loads(pyproject.read_text())
entries = data.get("tool", {}).get("askcc", {}).get("verify", [])
if entries:
return [(e["name"], shlex.split(e["cmd"])) for e in entries if "name" in e and "cmd" in e]
except (tomllib.TOMLDecodeError, KeyError):
logger.warning("Failed to parse [tool.askcc.verify] from %s", pyproject)

askcc_toml = cwd / ".askcc.toml"
if askcc_toml.exists():
try:
data = tomllib.loads(askcc_toml.read_text())
entries = data.get("verify", [])
if entries:
return [(e["name"], shlex.split(e["cmd"])) for e in entries if "name" in e and "cmd" in e]
except (tomllib.TOMLDecodeError, KeyError):
logger.warning("Failed to parse [[verify]] from %s", askcc_toml)

return []


def _run_project_verification(cwd: Path) -> VerificationResult:
Comment thread
monkut marked this conversation as resolved.
"""Run detected project verification commands and return aggregate result."""
commands = _detect_verification_commands(cwd)
if not commands:
logger.info("No verification commands detected in %s, skipping verification", cwd)
return VerificationResult(passed=True, message="No verification commands detected, skipping", checks=[])

checks: list[CheckResult] = []
for name, cmd in commands:
logger.info("Running verification: %s (%s)", name, " ".join(cmd))
try:
result = subprocess.run( # noqa: S603
cmd,
capture_output=True,
text=True,
check=False,
cwd=cwd,
timeout=VERIFICATION_TIMEOUT,
)
if result.returncode == 0:
checks.append(CheckResult(name=name, passed=True, message="passed"))
else:
stderr_snippet = result.stderr.strip()[:200] if result.stderr else result.stdout.strip()[:200]
checks.append(CheckResult(name=name, passed=False, message=f"failed: {stderr_snippet}"))
except FileNotFoundError:
checks.append(CheckResult(name=name, passed=False, message=f"command not found: {cmd[0]}"))
except subprocess.TimeoutExpired:
checks.append(CheckResult(name=name, passed=False, message=f"timed out after {VERIFICATION_TIMEOUT}s"))

all_passed = all(c.passed for c in checks)
passed_count = sum(1 for c in checks if c.passed)
total = len(checks)
message = f"{passed_count}/{total} checks passed"
return VerificationResult(passed=all_passed, message=message, checks=checks)


def _has_acceptance_criteria(body: str) -> bool:
"""Check for an acceptance criteria section with checklist items."""
match = re.search(r"#{2,}\s+acceptance\s+criteria", body, re.IGNORECASE)
Expand Down
16 changes: 8 additions & 8 deletions askcc/skills/request-askcc/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Use the `askcc` tool to request processing of GitHub issues defined by a URL.

```bash
# This fleshes out a backlog issue by suggesting acceptance criteria, identifying dependencies, and proposing an estimate to get it ready for planning.
askcc prepare --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
askcc --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} prepare --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
```

- "Validate https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1"
Expand All @@ -39,14 +39,14 @@ Use the `askcc` tool to request processing of GitHub issues defined by a URL.

```bash
# This analyzes a prepared issue against the codebase and produces a step-by-step implementation plan.
askcc plan --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
askcc --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} plan --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
```

- "Proceed with development of https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1"

```bash
# This proceeds to implement/develop a github issue that has a clear development/implementation plan.
askcc develop --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
askcc --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} develop --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1

```

Expand All @@ -61,35 +61,35 @@ Use the `askcc` tool to request processing of GitHub issues defined by a URL.

```bash
# This investigates the github issue, researches the codebase, and proposes best-practice solutions with trade-offs.
askcc explore --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
askcc --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} explore --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
```

- "Diagnose https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1"

```bash
# This investigates the reported issue, identifies potential root causes, and requests additional information.
askcc diagnose --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
askcc --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} diagnose --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
```

- "Review the PR for https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1"

```bash
# This fetches the issue and its linked PR, reviews the code against Definition of Done criteria, and posts a structured review on the PR.
askcc pr-review --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
askcc --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} pr-review --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
```

- "Fix CI for https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1"

```bash
# This fetches the linked PR, identifies failing CI checks, and implements fixes to make them pass.
askcc fix-ci --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
askcc --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} fix-ci --github-issue-url https://github.com/{GITHUB ORG}/{GITHUB REPO}/issues/1
```

- "Fix CI on the current branch" (no issue URL)

```bash
# This auto-detects the open PR for the current branch, identifies failing CI checks, and implements fixes.
askcc fix-ci --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY}
askcc --cwd {PROJECTS DIRECTORY}/{TARGET DEVELOPMENT REPOSITORY} fix-ci
```

WARNING: If the `{TARGET DEVELOPMENT REPOSITORY}` cannot be determined, ASK user in Slack.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "askcc"
version = "0.2.1"
version = "0.2.2"
description = "A one-shot cc cli executor"
authors = [{ name = "mknt", email = "shane.cousins@gmail.com" }]
readme = "README.md"
Expand Down
Loading
Loading