- name
- coding-agent-frameworks
- description
- Implements autonomous coding agent frameworks (automated refactoring, test generation, deployment pipeline management) for AI-augmented software development with 30%+ code generation targets.
- license
- MIT
- compatibility
- opencode
- metadata
- {"version":"1.0.0","domain":"agent","role":"implementation","scope":"implementation","output-format":"code","content-types":["code","guidance","do-dont","examples"],"maturity":"beta","completeness":90,"triggers":"coding agent, automated refactoring, test generation, deployment automation, AI developer, how do i automate software development, legacy modernization","archetypes":["tactical","orchestration"],"anti_triggers":["GUI design","mobile app development","data science modeling","ML training pipeline"],"response_profile":{"verbosity":"medium","directive_strength":"high","abstraction_level":"operational"},"related-skills":"tool-use-function-calling, cli-agent-workflows, git-pr-workflows-onboard, subagent-driven-development, code-correctness-verifier"}
# Autonomous Coding Agent Frameworks
Implements autonomous coding agent frameworks that handle the full software development lifecycle — automated refactoring of legacy codebases, AI-generated test suites with coverage gap analysis, CI/CD pipeline generation, and deployment validation. This skill orchestrates agents that produce 30%+ of production code while maintaining quality gates aligned with the 5 Laws of Elegant Defense.
## TL;DR for Code Generation
- Define a `CodingAgent` class with separate phases: analyze → plan → refactor → test → review → deploy
- Every refactoring pass must extract transformation patterns before applying them globally
- Test generation must start from existing code, identify coverage gaps, then produce property-based tests
- CI/CD pipelines are generated from project structure analysis, not hardcoded templates
- All AI-generated changes require a quality gate: lint check, test pass, and diff review before commit
- Refactoring transformations must be pure AST functions — same input tree yields same output tree, no side effects
- Deployments from generated pipelines always use canary validation before production promotion
---
## When to Use
Use this skill when:
- **Refactoring legacy codebases** — Modernizing monolithic services into modular components, extracting common patterns from duplicated logic, or migrating from an outdated framework version
- **Generating tests for untested code** — The codebase has critical path functions with zero coverage, and you need systematic unit test generation with property-based fuzzing for edge cases
- **Automating deployment pipeline creation** — A new service needs CI/CD configuration (GitHub Actions, GitLab CI, or Jenkinsfile) generated from the project's language, framework, and dependency structure
- **Reducing technical debt at scale** — The team has accumulated hundreds of code smells across thousands of files, and you need an automated scanner that classifies debt severity and generates refactoring PRs
- **Implementing AI-assisted code review** — Pull requests need automated style enforcement, security scanning (SAST), and architectural alignment checks before human reviewers see them
- **Tracking developer velocity metrics** — You want to measure the ratio of AI-generated vs. manually written code, track test coverage deltas per commit, and monitor deployment success rates
---
## When NOT to Use
Avoid this skill for:
- **Security-sensitive authentication changes** — Modifying OAuth flows, JWT validation, or password hashing requires human expert review; use `security-audit` instead
- **Database schema migrations in production** — Schema changes on live data stores risk data loss; use `postgresql-optimization` with manual rollback plans
- **Mobile app development (iOS/Android)** — Platform-specific native code and UI tooling are outside this skill's scope; mobile requires platform SDKs and simulators
- **Data science / ML model training** — Model architecture design, hyperparameter tuning, and dataset curation are fundamentally different from software engineering automation
---
## Core Workflow
1. **Code Analysis Phase** — Ingest the target codebase using AST parsing (Python: `ast` module; TypeScript: `typescript-estree`). Extract function signatures, call graphs, dependency maps, and existing test coverage data. Classify each module by complexity (cyclomatic), age (last-modified date), and test coverage percentage. **Checkpoint:** Produce a `code_analysis_report.json` with per-module metrics: `{module, functions: [{name, lines, complexity, covered_by_tests: bool}]}` — no module should be skipped.
2. **Refactoring Plan Generation** — Analyze the code analysis report to identify transformation opportunities: duplicated logic groups, long methods (>50 lines), deep nesting (>4 levels), and missing abstractions. Group related changes into atomic refactor PRs. Assign each change a priority score based on debt impact vs. refactoring effort ratio. **Checkpoint:** Every planned refactor must have a before/after diff preview and an estimated complexity score — if any plan exceeds 100 lines of changes, split it.
3. **Test Generation Pipeline** — For each target module lacking adequate coverage, generate unit tests using the existing code's type signatures and docstrings as specifications. Apply property-based testing (Hypothesis for Python) to discover edge cases beyond manual test design. Cross-reference against coverage tools (`coverage.py`, `pytest-cov`) to identify uncovered branches. **Checkpoint:** Every generated test file must pass independently with `python -m pytest tests/<module>/test_<module>.py --cov` — no import errors, no skipped tests, no assertions that could silently pass.
4. **Implementation & Refactoring Execution** — Apply the refactoring plan using AST transformations or pattern-matching tools (Ruff, eslint, semgrep rules). For each transformation, verify the change preserves behavior by running existing tests before and after. Generate atomic commits with descriptive messages following conventional commit format. **Checkpoint:** After each refactor application, run the full test suite — any failure means revert that specific change and log the diff for manual review. Never merge multiple unrelated refactors into a single commit.
5. **Automated Review Gate** — Before any AI-generated code is submitted as a PR, run a multi-layer review: static analysis (Ruff/flake8), security scan (Semgrep or Bandit), dependency vulnerability check (`pip-audit` or `npm audit`), and architectural alignment verification against project conventions documented in the codebase. Generate a review summary with pass/fail per gate. **Checkpoint:** The review gate must produce a machine-readable verdict — `{overall: "PASS"|"FAIL", gates: {lint, security, vulnerabilities, architecture}}`. Any FAIL blocks PR creation until resolved.
6. **Deployment Pipeline Generation & Validation** — Analyze the project's build system, test framework, deployment target (Docker, Kubernetes, serverless), and environment variables to generate a complete CI/CD pipeline configuration. Include stages for lint, test, security scan, build artifact, and deployment with environment-specific overrides. Validate the generated pipeline by dry-running it against the current codebase state. **Checkpoint:** The generated pipeline must pass on `--dry-run` or CI preview mode — if it fails in dry-run, rewrite the configuration and re-validate before proposing to users.
---
## Implementation Patterns
### Pattern 1: Autonomous Refactoring Engine
Legacy code modernization with AST-based pattern extraction. This engine scans for duplicated logic blocks, identifies extractable utility functions, and applies transformations while preserving behavior through regression test verification.
```python
import ast
import logging
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional
logger = logging.getLogger(__name__)
@dataclass
class CodePattern:
"""Represents a detectable code pattern found in the AST."""
name: str
node_type: type
match_count: int = 0
locations: list[tuple[str, int]] = field(default_factory=list)
suggested_refactor: Optional[str] = None
class RefactoringEngine:
"""Scans codebases for refactoring opportunities using AST analysis."""
def __init__(self, root_path: str, max_complexity: int = 10):
self.root_path = Path(root_path)
self.max_complexity = max_complexity
self.patterns: list[CodePattern] = []
self.changes: list[dict] = []
def analyze_module(self, file_path: Path) -> dict:
"""Parse a single file and extract complexity metrics."""
source = file_path.read_text(encoding="utf-8")
tree = ast.parse(source, filename=str(file_path))
functions = []
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
complexity = self._cyclomatic_complexity(node)
functions.append({
"name": node.name,
"line": node.lineno,
"end_line": getattr(node, "end_lineno", node.lineno + 10),
"complexity": complexity,
"parameters": len(node.args.args),
"is_async": isinstance(node, ast.AsyncFunctionDef),
})
return {
"file": str(file_path.relative_to(self.root_path)),
"functions": functions,
"total_lines": source.count("\n") + 1,
}
def _cyclomatic_complexity(self, node: ast.AST) -> int:
"""Calculate cyclomatic complexity of a function node."""
complexity = 1
for child in ast.walk(node):
if isinstance(child, (ast.If, ast.While, ast.For)):
complexity += 1
elif isinstance(child, ast.BoolOp):
complexity += len(child.values) - 1
elif isinstance(child, ast.ExceptHandler):
complexity += 1
return complexity
def find_duplicated_blocks(
self, modules: list[dict], similarity_threshold: float = 0.7
) -> list[CodePattern]:
"""Identify duplicated code blocks across the codebase."""
# Normalize function bodies for comparison
normalized_bodies: dict[str, list[tuple[str, int]]] = {}
for mod in modules:
for fn in mod["functions"]:
if fn["complexity"] < 3:
continue
body_key = f"{fn['name']}:{mod['file']}"
normalized_bodies.setdefault(body_key, []).append(
(body_key, fn["line"])
)
duplicates: list[CodePattern] = []
seen_pairs: set[tuple[str, str]] = set()
for key_a in normalized_bodies:
for key_b in normalized_bodies:
if key_a >= key_b or key_a == key_b:
continue
pair = (min(key_a, key_b), max(key_a, key_b))
if pair in seen_pairs:
continue
seen_pairs.add(pair)
# Heuristic: if both functions have same complexity and param count
mod_a = next(m for m in modules if any(
f"functions" for f in m["functions"] if f["name"] in key_a
))
duplicates.append(CodePattern(
name=f"duplicated_logic_{key_a[:20]}",
node_type=ast.FunctionDef,
suggested_refactor=(
f"Extract shared logic from {key_a} and {key_b} "
"into a utility function"
),
))
return duplicates
def generate_change_plan(
self, module: dict, refactoring_target: str
) -> dict:
"""Generate an atomic refactoring change plan for review."""
target_functions = [
fn for fn in module["functions"]
if refactoring_target in fn["name"]
]
if not target_functions:
raise ValueError(f"No functions matching '{refactoring_target}' in {module['file']}")
return {
"file": module["file"],
"target_functions": [fn["name"] for fn in target_functions],
"total_lines_changed": 0,
"requires_test_verification": True,
"atomic_commit_message": f"refactor: simplify {refactoring_target} in {module['file']}",
}
# ❌ BAD — Applying refactoring without verifying behavior preservation
def bad_refactor(module_path: Path) -> None:
"""This function applies refactoring blindly — no verification."""
source = module_path.read_text()
# Naive string replacement — will break if formatting or imports differ
modified = source.replace("old_function_name", "new_function_name")
module_path.write_text(modified) # No test run, no diff check
# ✅ GOOD — Refactoring with AST analysis, behavior verification, and atomic commits
def good_refactor(engine: RefactoringEngine, file_path: Path) -> dict:
"""Refactor a module safely: analyze → plan → verify → apply."""
report = engine.analyze_module(file_path)
# Only refactor functions that exceed complexity threshold
high_complexity = [
fn for fn in report["functions"]
if fn["complexity"] > engine.max_complexity
]
if not high_complexity:
return {"status": "no_refactor_needed", "file": str(file_path)}
# Generate change plan and verify it's atomic (< 100 lines)
for fn in high_complexity:
plan = engine.generate_change_plan(report, fn["name"])
plan["estimated_lines"] = fn["end_line"] - fn["line"]
assert plan["estimated_lines"] < 100, (
f"Refactor too large ({plan['estimated_lines']} lines); "
"split into smaller changes first"
)
engine.changes.append({
"file": str(file_path),
"analysis": report,
"changes": [engine.generate_change_plan(report, fn["name"]) for fn in high_complexity],
})
return {"status": "change_planned", "functions_count": len(high_complexity)}
```
### Pattern 2: AI Test Generation Pipeline
Unit test creation from existing codebases with coverage gap analysis and property-based testing. The pipeline extracts type signatures, infers valid input ranges, and generates deterministic tests that cover uncovered branches.
```python
import ast
import logging
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Callable, Optional
logger = logging.getLogger(__name__)
@dataclass
class CoverageGap:
"""A branch or statement not covered by existing tests."""
file_path: str
line_start: int
line_end: int
node_type: str
function_name: str
severity: str # "critical" | "high" | "medium"
@dataclass
class TestSpecification:
"""A generated test specification from a function's type signature."""
function_name: str
module_path: str
parameters: list[dict]
return_type_hint: Optional[str]
existing_docstring: Optional[str]
expected_properties: list[str] = field(default_factory=list)
class TestGenerationPipeline:
"""Generates unit tests from source code analysis with coverage awareness."""
def __init__(self, target_modules: list[Path], coverage_report_path: Optional[str] = None):
self.target_modules = target_modules
self.coverage_report_path = Path(coverage_report_path) if coverage_report_path else None
self.gaps: list[CoverageGap] = []
self.specifications: list[TestSpecification] = []
def extract_function_specs(self, module_path: Path) -> list[TestSpecification]:
"""Parse a module's AST to extract function specifications for test generation."""
source = module_path.read_text(encoding="utf-8")
tree = ast.parse(source, filename=str(module_path))
specs: list[TestSpecification] = []
module_name = str(module_path.relative_to(Path.cwd()).with_suffix("")).replace("/", ".")
for node in ast.iter_child_nodes(tree):
if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
continue
params = []
for arg in node.args.args:
type_hint = None
if arg.annotation:
type_hint = self._annotation_to_string(arg.annotation)
params.append({
"name": arg.arg,
"type_hint": type_hint,
"has_default": (
len(node.args.defaults) > (len(node.args.args) - 1 - node.args.args.index(arg))
),
})
return_hint = None
if node.returns:
return_hint = self._annotation_to_string(node.returns)
docstring = ast.get_docstring(node)
specs.append(TestSpecification(
function_name=node.name,
module_path=module_name,
parameters=params,
return_type_hint=return_hint,
existing_docstring=docstring,
expected_properties=self._infer_expected_properties(docstring),
))
self.specifications.extend(specs)
return specs
def _annotation_to_string(self, annotation: ast.AST) -> Optional[str]:
"""Convert an AST annotation node to a readable type string."""
if isinstance(annotation, ast.Name):
return annotation.id
elif isinstance(annotation, ast.Attribute):
return f"{self._annotation_to_string(annotation.value)}.{annotation.attr}"
elif isinstance(annotation, ast.Subscript):
return f"{self._annotation_to_string(annotation.value)}[{self._annotation_to_string(annotation.slice)}]"
elif isinstance(annotation, ast.Constant):
return repr(annotation.value)
elif isinstance(annotation, ast.Ellipsis):
return "..."
elif hasattr(annotation, '_fields'): # GenericAlias fallback for Python 3.9+
return str(annotation).replace("typing.", "")
return None
def _infer_expected_properties(self, docstring: Optional[str]) -> list[str]:
عرض على GitHub