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
6 changes: 6 additions & 0 deletions .coderabbit 2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
reviews:
auto_review:
enabled: false

chat:
auto_reply: false
71 changes: 71 additions & 0 deletions CONTEXT 2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# codeforerunner Context

codeforerunner is a prompt-first documentation tool for keeping repository knowledge aligned with code. Its language separates prompt-pack tasks from thin runtime wrappers.

## Language

**Architecture Review**:
A documentation task that surfaces repo-grounded opportunities to deepen modules and improve maintainability. The command/path name is `arch-review`; the human-facing title is Architecture Review.
_Avoid_: Architecture audit, refactor report

**Deepening Opportunity**:
A candidate architecture improvement that hides more behavior behind a smaller interface, increasing leverage for callers and locality for maintainers. Architecture Reviews rank Deepening Opportunities but do not implement them.
_Avoid_: Refactor idea, cleanup item

**Task Registry**:
A catalog of codeforerunner task identity and policy: task name, output role, refresh inclusion, scan exemption, and installable skill surface. It is the source agents and wrappers consult instead of rediscovering task facts from scattered files.
_Avoid_: Task list, command list

**Prompt Session**:
A run-scoped interaction with codeforerunner prompt tasks that owns task lookup, scan-first enforcement, scan state, and bundle resolution. CLI and MCP code act as adapters to a Prompt Session rather than each reimplementing task ordering rules.
_Avoid_: Prompt runner, execution context

**Distribution Inventory**:
A catalog of codeforerunner distribution artifacts and install policy: canonical skill, skill copies, per-task skills, marketplace manifest, managed markers, and default install destinations. Installer, doctor, and validators consult the Distribution Inventory instead of repeating packaging paths.
_Avoid_: Package list, artifact list

**npm Publishing**:
The release path that makes the Node installer package available through npm-compatible registries. codeforerunner treats npmjs publishing, GitHub Packages publishing, and pinned installer shims as related but separately fixable release surfaces.
_Avoid_: JavaScript release, package upload

**Release Surface Manifest**:
A catalog of release surfaces, versions, registry targets, authentication modes, and validation expectations for codeforerunner releases. npm Publishing uses it to keep npmjs, GitHub Packages, installer shims, and release PR checks aligned.
_Avoid_: Release checklist, publish config

**Package Contents Inspector**:
A release validation module that checks the packed npm artifact before publish, including required files, executable entrypoints, skill payloads, lock metadata, and shim pins. It treats the package artifact as the test surface.
_Avoid_: npm pack script, file list check

**Agent Onboarding**:
A task that creates or refreshes the instructions and domain vocabulary a coding agent needs before working in a repo. Agent Onboarding may create or update `CONTEXT.md` with conservative glossary terms inferred from stable repo evidence.
_Avoid_: Init docs, setup docs

## Example Dialogue

Dev: "Run arch-review on this repo."

Domain expert: "That means produce an Architecture Review: ranked Deepening Opportunities, grounded in scan evidence, without changing code or proposing final interfaces yet."

Dev: "Run init for this repo."

Domain expert: "That means perform Agent Onboarding: update agent instructions and, when stable terms are evident, maintain the repo glossary in `CONTEXT.md`."

Dev: "Add a new prompt task."

Domain expert: "Register it in the Task Registry so wrappers, skills, docs, and refresh policy read the same task identity."

Dev: "Why does scan-first logic exist in both CLI and MCP?"

Domain expert: "That rule belongs to a Prompt Session: adapters should ask the session whether a task can run."

Dev: "Where should canonical skill paths and marketplace paths live?"

Domain expert: "In the Distribution Inventory, so installer, doctor, and validators share distribution facts."

Dev: "Fix npm publishing."

Domain expert: "Treat npm Publishing as three release surfaces: npmjs trusted publish, GitHub Packages publish, and installer shim pins."

Dev: "How do we keep release workflows aligned?"

Domain expert: "Use a Release Surface Manifest, then validate packed npm artifacts with a Package Contents Inspector before publish."
37 changes: 37 additions & 0 deletions plugins/codeforerunner/skills/forerunner-arch-review/SKILL 2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: forerunner-arch-review
description: Rank architecture improvement candidates. Use when the user wants architecture friction reviewed before planning refactors.
---

# forerunner-arch-review

Produces an Architecture Review: ranked Deepening Opportunities that identify shallow modules, leaky seams, testability friction, and high-leverage refactor candidates.

Inspired by Matt Pocock's `/improve-codebase-architecture` skill:
https://github.com/mattpocock/skills/tree/main/skills/engineering/improve-codebase-architecture

## Activate when

User asks to: review architecture, find deepening opportunities, identify shallow modules, assess refactor candidates, or improve codebase architecture.

## Collect this context

- Scan result (run `/forerunner-scan` first)
- Key module/package files from the scan result
- Existing tests for the modules under review
- `CONTEXT.md` or `CONTEXT-MAP.md` if present
- Relevant `docs/adr/*.md` files if present
- Existing architecture docs only when they clarify current design

## Execute

Run `forerunner generate --prompt-only arch-review` — outputs the assembled prompt bundle to stdout. Read this output and execute the architecture review task it describes.

Without CLI, get the prompt from:
- `src/codeforerunner/prompts/tasks/arch-review.md`
- `src/codeforerunner/prompts/system/base.md`
- `src/codeforerunner/prompts/partials/output-rules.md`

## Output

`.forerunner/arch-review.md` with a top recommendation and 3-7 ranked Deepening Opportunities. Each candidate includes files/modules, problem, evidence, proposed direction, locality/leverage benefits, testing impact, risk/blast radius, and recommendation strength. Do not implement changes or propose final interfaces.
30 changes: 8 additions & 22 deletions scripts/validate_skill_copies.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,29 @@
CANONICAL_SKILL_REL,
DISTRIBUTED_SKILL_COPIES_REL,
)
from codeforerunner.skill_parity import check_skill_body_parity # noqa: E402

CANONICAL = CANONICAL_SKILL_REL
COPIES = list(DISTRIBUTED_SKILL_COPIES_REL)


def strip_frontmatter(text: str) -> str:
text = text.replace("\r\n", "\n").replace("\r", "\n")
lines = text.split("\n")
if lines and lines[0] == "---":
for index in range(1, len(lines)):
if lines[index] == "---":
return "\n".join(lines[index + 1 :]).strip()
return text.strip()


def read_body(path: Path) -> str:
return strip_frontmatter((ROOT / path).read_text(encoding="utf-8"))


def print_checked_files(*, stream=sys.stdout) -> None:
print(f"canonical: {CANONICAL}", file=stream)
for path in COPIES:
print(f"copy: {path}", file=stream)


def main() -> int:
canonical_body = read_body(CANONICAL)
failures: list[Path] = []

for copy in COPIES:
if read_body(copy) != canonical_body:
failures.append(copy)
result = check_skill_body_parity(ROOT)

if failures:
if not result.ok:
print("V10 violation: distributed skill body drift detected.", file=sys.stderr)
print_checked_files(stream=sys.stderr)
for path in failures:
if result.missing_canonical:
print(f"missing: {CANONICAL}", file=sys.stderr)
for path in result.missing_copies:
print(f"missing: {path}", file=sys.stderr)
for path in result.drifted_copies:
print(f"mismatch: {path}", file=sys.stderr)
return 1

Expand Down
37 changes: 37 additions & 0 deletions skills/forerunner-arch-review/SKILL 2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: forerunner-arch-review
description: Rank architecture improvement candidates. Use when the user wants architecture friction reviewed before planning refactors.
---

# forerunner-arch-review

Produces an Architecture Review: ranked Deepening Opportunities that identify shallow modules, leaky seams, testability friction, and high-leverage refactor candidates.

Inspired by Matt Pocock's `/improve-codebase-architecture` skill:
https://github.com/mattpocock/skills/tree/main/skills/engineering/improve-codebase-architecture

## Activate when

User asks to: review architecture, find deepening opportunities, identify shallow modules, assess refactor candidates, or improve codebase architecture.

## Collect this context

- Scan result (run `/forerunner-scan` first)
- Key module/package files from the scan result
- Existing tests for the modules under review
- `CONTEXT.md` or `CONTEXT-MAP.md` if present
- Relevant `docs/adr/*.md` files if present
- Existing architecture docs only when they clarify current design

## Execute

Run `forerunner generate --prompt-only arch-review` — outputs the assembled prompt bundle to stdout. Read this output and execute the architecture review task it describes.

Without CLI, get the prompt from:
- `src/codeforerunner/prompts/tasks/arch-review.md`
- `src/codeforerunner/prompts/system/base.md`
- `src/codeforerunner/prompts/partials/output-rules.md`

## Output

`.forerunner/arch-review.md` with a top recommendation and 3-7 ranked Deepening Opportunities. Each candidate includes files/modules, problem, evidence, proposed direction, locality/leverage benefits, testing impact, risk/blast radius, and recommendation strength. Do not implement changes or propose final interfaces.
45 changes: 13 additions & 32 deletions src/codeforerunner/doctor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from typing import Callable

from codeforerunner import distribution as _dist
from codeforerunner import skill_parity as _parity
from codeforerunner.config import CONFIG_FILENAME, ConfigError, load_from_repo

# Distribution artifact identity and markers come from the Distribution
Expand Down Expand Up @@ -62,47 +63,27 @@ def _load_script_module(repo: Path, relpath: str, module_name: str):


def _check_skill_body_parity(repo: Path, run_scripts: bool = False) -> list[Finding]:
"""Verify that all distributed skill copies match the canonical body."""
if not run_scripts:
return [
Finding(
"warn",
"skill-body-parity",
"skipping script validation (pass --run-scripts to allow executing repo scripts)",
)
]
try:
skill_mod = _load_script_module(
repo, "scripts/validate_skill_copies.py", "_forerunner_doctor_skill_copies"
)
strip_frontmatter: Callable[[str], str] = skill_mod.strip_frontmatter
except Exception as exc: # pragma: no cover - defensive
return [Finding("error", "skill-body-parity", f"loader failure: {exc}")]

canonical_path = repo / CANONICAL_REL
if not canonical_path.is_file():
"""Verify that all distributed skill copies match the canonical body.

Body parity is owned by the Skill Body Parity module, which only reads
files (no target-repo code is executed), so this runs regardless of
``run_scripts`` — that flag still gates checks that load repo scripts.
"""
result = _parity.check_skill_body_parity(repo)
if result.missing_canonical:
return [
Finding(
"error",
"skill-body-parity",
f"canonical skill missing: {CANONICAL_REL}",
)
]
canonical_body = strip_frontmatter(canonical_path.read_text(encoding="utf-8"))

findings: list[Finding] = []
for rel in SKILL_COPIES_REL:
p = repo / rel
if not p.is_file():
findings.append(
Finding("error", "skill-body-parity", f"copy missing: {rel}")
)
continue
body = strip_frontmatter(p.read_text(encoding="utf-8"))
if body != canonical_body:
findings.append(
Finding("error", "skill-body-parity", f"body drift in {rel}")
)
for rel in result.missing_copies:
findings.append(Finding("error", "skill-body-parity", f"copy missing: {rel}"))
for rel in result.drifted_copies:
findings.append(Finding("error", "skill-body-parity", f"body drift in {rel}"))
if not findings:
findings.append(
Finding(
Expand Down
19 changes: 4 additions & 15 deletions src/codeforerunner/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from typing import Iterable, Literal

from codeforerunner import distribution as _dist
from codeforerunner import skill_parity as _parity
from codeforerunner.tasks import installable_slugs as _installable_slugs

# Distribution artifact identity and markers come from the Distribution
Expand Down Expand Up @@ -129,25 +130,13 @@ def resolve_marketplace_target(agent: str, override: Path | None) -> Target:


def strip_frontmatter(text: str) -> str:
"""Body extraction matching scripts/validate_skill_copies.py."""
text = text.replace("\r\n", "\n").replace("\r", "\n")
lines = text.split("\n")
if lines and lines[0] == "---":
for i in range(1, len(lines)):
if lines[i] == "---":
return "\n".join(lines[i + 1 :]).strip()
return text.strip()
"""Body extraction; owned by the Skill Body Parity module."""
return _parity.body_of(text)


def extract_frontmatter(text: str) -> str:
"""Return frontmatter block (incl. fences) or '' if none."""
text = text.replace("\r\n", "\n").replace("\r", "\n")
lines = text.split("\n")
if lines and lines[0] == "---":
for i in range(1, len(lines)):
if lines[i] == "---":
return "\n".join(lines[: i + 1]) + "\n"
return ""
return _parity.split_frontmatter(text)[0]


def _hash(s: str) -> str:
Expand Down
Loading