From 5518e57bdda5fcd331c739513d8229de4b3a6dd8 Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Fri, 10 Apr 2026 22:43:30 +0200 Subject: [PATCH 1/6] feat: compact agent governance loading --- .../rules/session_startup_instructions.mdc | 44 +- .github/copilot-instructions.md | 25 +- AGENTS.md | 467 ++---------------- CLAUDE.md | 343 +------------ docs/.doc-frontmatter-enforced | 1 + docs/_data/nav.yml | 21 + .../05-non-negotiable-checklist.md | 50 ++ docs/agent-rules/10-session-bootstrap.md | 54 ++ docs/agent-rules/20-repository-context.md | 67 +++ .../agent-rules/30-worktrees-and-branching.md | 56 +++ docs/agent-rules/40-openspec-and-tdd.md | 60 +++ .../50-quality-gates-and-review.md | 68 +++ .../60-github-change-governance.md | 59 +++ .../agent-rules/70-release-commit-and-docs.md | 59 +++ .../80-current-guidance-catalog.md | 71 +++ docs/agent-rules/INDEX.md | 87 ++++ docs/contributing/frontmatter-schema.md | 15 + openspec/CHANGE_ORDER.md | 1 + .../TDD_EVIDENCE.md | 39 ++ .../design.md | 120 +++++ .../proposal.md | 27 + .../specs/agent-governance-loading/spec.md | 94 ++++ .../specs/github-hierarchy-cache/spec.md | 19 + .../tasks.md | 36 ++ scripts/check_doc_frontmatter.py | 101 +++- tests/helpers/doc_frontmatter_types.py | 20 + .../unit/docs/test_agent_rules_governance.py | 54 ++ .../test_agent_rule_frontmatter.py | 130 +++++ 28 files changed, 1374 insertions(+), 814 deletions(-) create mode 100644 docs/agent-rules/05-non-negotiable-checklist.md create mode 100644 docs/agent-rules/10-session-bootstrap.md create mode 100644 docs/agent-rules/20-repository-context.md create mode 100644 docs/agent-rules/30-worktrees-and-branching.md create mode 100644 docs/agent-rules/40-openspec-and-tdd.md create mode 100644 docs/agent-rules/50-quality-gates-and-review.md create mode 100644 docs/agent-rules/60-github-change-governance.md create mode 100644 docs/agent-rules/70-release-commit-and-docs.md create mode 100644 docs/agent-rules/80-current-guidance-catalog.md create mode 100644 docs/agent-rules/INDEX.md create mode 100644 openspec/changes/governance-03-deterministic-agent-governance-loading/TDD_EVIDENCE.md create mode 100644 openspec/changes/governance-03-deterministic-agent-governance-loading/design.md create mode 100644 openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md create mode 100644 openspec/changes/governance-03-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md create mode 100644 openspec/changes/governance-03-deterministic-agent-governance-loading/specs/github-hierarchy-cache/spec.md create mode 100644 openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md create mode 100644 tests/unit/docs/test_agent_rules_governance.py create mode 100644 tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py diff --git a/.cursor/rules/session_startup_instructions.mdc b/.cursor/rules/session_startup_instructions.mdc index 689b0598..620609c6 100644 --- a/.cursor/rules/session_startup_instructions.mdc +++ b/.cursor/rules/session_startup_instructions.mdc @@ -1,45 +1,15 @@ --- -description: This rule provides essential instructions for testing and building the project correctly, avoiding common pitfalls with test environment management. +description: Bootstrap Cursor sessions through the canonical agent governance docs instead of relying on stale inline reminders. globs: alwaysApply: true --- # Session Startup Instructions -## Core Workflow Reminders +1. Read `AGENTS.md`. +2. Read `docs/agent-rules/INDEX.md`. +3. Read `docs/agent-rules/05-non-negotiable-checklist.md`. +4. Detect repository root, branch, and worktree state before implementation. +5. Load any additional rule files selected by the applicability matrix in `docs/agent-rules/INDEX.md`. -- **Testing:** Run `hatch run smart-test`. Ensure total coverage is >= 80%. -- **Formatting:** Apply `black .`, `isort .`, `mypy .`, and `pylint src tests` before committing. -- **Commits:** Use the [Conventional Commits](https://www.conventionalcommits.org/) format. -- **Versioning:** When releasing, update `CHANGELOG.md`, `pyproject.toml`, `setup.py`, and `src/__init__.py`. -- **Docstrings:** Follow the [Google Python Style Guide](https://google.github.io/styleguide/pyguide.html). - -## Initial Context Checklist - -1. **Review: -1.1. `GEMINI.md`: Check for any session-specific goals or instructions (applies to GEMINI CLI only). -1.2. `CLAUDE.md`: Check for any session-specific goals or instructions (applies to Claude CLI only). -2. `docs/README.md` to get the latest project status and priorities and see which plan is referenced as being worked on: Understand the current development phase and tasks based on the mentioned plan in the README.md file. -3. Outline your understanding of the current development phase and tasks based on the mentioned plan in the README.md file, before proceeding with any work. Ask the user for confirmation before proceeding. - -## Documentation and Planning Guidelines - -**CRITICAL**: When working with planning and documentation: - -- **Work directly with major artifacts**: Update strategic plans, implementation plans, and analysis documents directly. Do NOT create plans for plans, tracking documents for tracking documents, or status artifacts for status artifacts. -- **Update existing artifacts**: Add status annotations (βœ… Complete, ⏳ In Progress, 🟑 Pending) directly to existing plan documents rather than creating separate status files. -- **Consolidate, don't multiply**: Only create new documentation artifacts when they add clear, unique value that cannot be captured in existing artifacts. -- **Performance metrics**: Record timing and performance data directly in implementation status documents, not in separate performance tracking files. -- **Test results**: Include test results and validation outcomes in the relevant implementation status or quality analysis documents. - -**Examples of what NOT to do**: - -- ❌ Creating `PHASE0_TRACKING.md` when `CODE2SPEC_STRATEGIC_PLAN.md` already exists -- ❌ Creating `STEP1_1_TEST_RESULTS.md` when `PHASE1_IMPLEMENTATION_STATUS.md` can be updated -- ❌ Creating `PERFORMANCE_METRICS.md` when performance data can go in implementation status - -**Examples of what TO do**: - -- βœ… Update `CODE2SPEC_STRATEGIC_PLAN.md` with status annotations (βœ… Complete, ⏳ Next) -- βœ… Add test results and performance metrics to `PHASE1_IMPLEMENTATION_STATUS.md` -- βœ… Update `QUALITY_GAP_ANALYSIS.md` with measurement results and progress +Do not treat this file as a complete workflow handbook. The canonical repository governance now lives in `docs/agent-rules/`. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index ad6cb5f3..48d63eaf 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,23 +1,10 @@ # GitHub Copilot Instructions β€” specfact-cli -## Clean-Code Charter +Use [AGENTS.md](../AGENTS.md) as the mandatory bootstrap surface and [docs/agent-rules/INDEX.md](../docs/agent-rules/INDEX.md) as the canonical governance dispatcher. -This repository enforces the **7-principle clean-code charter** defined in: -- `skills/specfact-code-review/SKILL.md` (`nold-ai/specfact-cli-modules`) -- Policy-pack: `specfact/clean-code-principles` +## Minimal reminders -Review categories checked on every PR: **naming Β· kiss Β· yagni Β· dry Β· solid** - -Phase A KISS thresholds: LOC > 80 warning / > 120 error per function. -Nesting-depth and parameter-count checks are active. Phase B (>40/80) is deferred. - -Run `hatch run specfact code review run --json --out .specfact/code-review.json` before submitting. - -## Key conventions - -- Python 3.11+, Typer CLI, Pydantic models, `@icontract` + `@beartype` on all public APIs -- No `print()` in `src/` β€” use `get_bridge_logger()` -- Branch protection: work on `feature/*`, `bugfix/*`, `hotfix/*` branches; PRs to `dev` -- Pre-commit checklist: `hatch run format` β†’ `type-check` β†’ `lint` β†’ `yaml-lint` β†’ `contract-test` β†’ `smart-test` - -See `AGENTS.md` and `.cursor/rules/` for the full contributor guide. +- This repository enforces the clean-code review gate through `hatch run specfact code review run --json --out .specfact/code-review.json`. +- Public APIs require `@icontract` and `@beartype`. +- Work belongs on `feature/*`, `bugfix/*`, `hotfix/*`, or `chore/*` branches, normally in a worktree. +- The full governance rules live in `docs/agent-rules/`; do not treat this file as a complete standalone handbook. diff --git a/AGENTS.md b/AGENTS.md index b1dd559f..31c1ca70 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,420 +1,51 @@ # AGENTS.md -This file provides guidance to coding agents when working with code in this repository. - -## Project Overview - -SpecFact CLI is a Python CLI tool for agile DevOps teams. It keeps backlogs, specs, tests, and code in sync with contract-driven development, validation, and enforcement. Built with Typer + Rich, using Hatch as the build system. Python 3.11+. - -## Essential Commands - -```bash -# Development environment -pip install -e ".[dev]" -hatch shell - -# Format & lint (run after every code change, in this order) -hatch run format # ruff format + fix -hatch run type-check # basedpyright strict mode -hatch run contract-test # contract-first validation (primary) -hatch test --cover -v # full pytest suite - -# Contract-first testing layers -hatch run contract-test-contracts # runtime contract validation only -hatch run contract-test-exploration # CrossHair symbolic execution -hatch run contract-test-scenarios # integration/E2E with contract refs -hatch run contract-test-full # all layers -hatch run contract-test-status # coverage status report - -# Run a single test file -hatch test -- tests/unit/specfact_cli/test_example.py -v - -# Lint subsystems -hatch run lint # full lint suite -hatch run governance # pylint detailed analysis -hatch run yaml-lint # YAML validation -hatch run lint-workflows # GitHub Actions actionlint - -# Code scanning -hatch run scan-all # semgrep analysis - -# SpecFact code review JSON (dogfood; see "SpecFact Code Review JSON" below and openspec/config.yaml) -hatch run specfact code review run --json --out .specfact/code-review.json -``` - -## Architecture - -### Modular Command Registry with Lazy Loading - -The CLI uses a module package system in `src/specfact_cli/modules/`. Each module is a self-contained package: - -``` -modules/{name}/ - module-package.yaml # metadata: name, version, commands, dependencies - src/{name}/ - __init__.py - main.py # typer.Typer app with command definitions -``` - -The registry (`src/specfact_cli/registry/`) discovers modules at startup but defers imports until a command is actually invoked. `bootstrap.py` registers all modules; `registry.py` manages lazy loading; `module_packages.py` handles discovery from `module-package.yaml` files. - -**Entry flow**: `cli.py:cli_main()` β†’ Typer app with global options β†’ `ProgressiveDisclosureGroup` for help β†’ lazy-loaded command groups from registry. - -### Contract-First Development - -All public APIs must use `@icontract` decorators (`@require`, `@ensure`, `@invariant`) and `@beartype` for runtime type checking. CrossHair discovers counterexamples via symbolic execution. Contracts are the primary validation mechanism; traditional unit tests are secondary. - -### Key Subsystems - -- **`models/`** - Pydantic BaseModel classes for all data structures -- **`parsers/`**, **`analyzers/`** - Code analysis -- **`generators/`** - Code/spec generation using Jinja2 templates from `resources/templates/` -- **`validators/`** - Schema, contract, FSM validation -- **`adapters/`** - Bridge pattern for tool integrations (GitHub, Azure DevOps, Jira, Linear) -- **`modes/`** - Operational modes: CICD (fast, deterministic, non-interactive) vs Copilot (interactive, IDE-aware). Auto-detected from environment. -- **`resources/`** - Bundled prompts, templates, schemas, mappings (force-included in wheel) - -### Logging - -Use `from specfact_cli.common import get_bridge_logger` and avoid `print()` in production command paths. Debug logs go to `~/.specfact/logs/specfact-debug.log` when `--debug` is passed. - -## Development Workflow - -### Branch Protection - -`dev` and `main` are protected. Always work on feature/bugfix/hotfix branches and submit PRs: -- `feature/your-feature-name` -- `bugfix/your-bugfix-name` -- `hotfix/your-hotfix-name` - -### Git Worktree Policy (Parallel Development) - -Use git worktrees for parallel development branches only. - -- Allowed branch types in worktrees: `feature/*`, `bugfix/*`, `hotfix/*`, `chore/*` -- Forbidden in worktrees: `dev`, `main` -- The primary checkout remains the canonical `dev` workspace - -Canonical layout: - -- Primary checkout: `.../specfact-cli` (tracks `dev`) -- Worktrees root: `.../specfact-cli-worktrees//` -- Worktree folder name MUST reflect the branch slug - -Preferred helper commands (from repository root): - -```bash -scripts/worktree.sh create feature/ -scripts/worktree.sh list -scripts/worktree.sh cleanup feature/ -``` - -Create a new worktree from `origin/dev`: - -```bash -git fetch origin -git worktree add ../specfact-cli-worktrees/feature/ -b feature/ origin/dev -``` - -Attach an existing local branch to a worktree: - -```bash -git fetch origin -git worktree add ../specfact-cli-worktrees/feature/ feature/ -``` - -Operational rules: - -- Never create a worktree for `dev` or `main` -- One branch maps to exactly one worktree path at a time -- Keep branch naming consistent: `/-` -- Keep one active OpenSpec change scope per branch where possible -- Create a separate virtual environment inside each worktree (for example, `.venv/`) -- Bootstrap Hatch once per new worktree before running quality gates: `hatch env create` -- Run quick pre-flight checks from the worktree root: `hatch run smart-test-status` and `hatch run contract-test-status` -- If Hatch cannot write to default home/cache paths, set writable overrides (for example `HATCH_DATA_DIR=/tmp/hatch-data` and `HATCH_CACHE_DIR=/tmp/hatch-cache`) -- Run all quality gates from inside the active worktree before commit/PR - -Conflict avoidance: - -- Check `openspec/CHANGE_ORDER.md` before creating new parallel branches -- Avoid concurrent branches editing the same `openspec/changes//` directory -- Rebase frequently on `origin/dev` in each worktree -- Use `git worktree list` daily to detect stale or incorrect branch/path attachments - -Local cleanup after merge to `dev`: - -```bash -git fetch origin -git worktree remove ../specfact-cli-worktrees/feature/ -git branch -d feature/ -git worktree prune -``` - -If remote cleanup is needed: - -```bash -git push origin --delete feature/ -``` - -### Developing specfact-cli-modules (IDE dependencies) - -Bundle code in **specfact-cli-modules** imports from `specfact_cli` (models, runtime, validators, etc.). That repo uses **Hatch**: a `pyproject.toml` with optional dependency `.[dev]` pulls in `specfact-cli` from a sibling path (`file://../specfact-cli`). When opening the modules repo in Cursor/VS Code: - -- In **specfact-cli-modules**: run `hatch env create` (with specfact-cli at `../specfact-cli`, or symlink / edit path in pyproject), then in the IDE select **Python: Select Interpreter** β†’ `.venv` in that repo. -- See **specfact-cli-modules** `README.md` β†’ "Local development (IDE / Cursor)" for sibling layout and worktree/symlink options. - -### Pre-Commit Checklist - -Run all steps in order before committing. Every step must pass with no errors. - -1. `hatch run format` # ruff format + autofix -2. `hatch run type-check` # basedpyright strict -3. `hatch run lint` # full lint suite -4. `hatch run yaml-lint` # YAML + markdown validation -5. `hatch run contract-test` # contract-first validation -6. `hatch run smart-test` # targeted test run (use `smart-test-full` for larger modifications) - -With `pre-commit` installed (`pre-commit install`), staged `*.py` / `*.pyi` files also run the local code review gate (`scripts/pre_commit_code_review.py`), which writes the same `.specfact/code-review.json` path. That hook is fast feedback; it does not replace the **PR / change-completion** review rules in the next section when your OpenSpec tasks require a full-scope run. - -### SpecFact Code Review JSON (Dogfood, Quality Gate) - -This matches **`openspec/config.yaml`** (project `context` and **`rules.tasks`** for code review): treat **`.specfact/code-review.json`** as mandatory evidence before an OpenSpec change is considered complete and before you rely on β€œall gates green” for a PR. - -**When to (re)run the review** - -- The file is **missing**, or -- It is **stale**: the report’s last-modified time is older than any file you changed for this work under `src/`, `scripts/`, `tools/`, `tests/`, or under `openspec/changes//` **except** `openspec/changes//TDD_EVIDENCE.md` β€” evidence-only edits there do **not** by themselves invalidate the review; re-run when proposal, specs, tasks, design, or code change. - -**Command** - -```bash -hatch run specfact code review run --json --out .specfact/code-review.json -``` - -- While iterating on a branch, prefer a **changed-files scope** when available (e.g. `--scope changed`) so feedback stays fast. -- Before the **final PR** for a change, run a **full** (or equivalent) scope so the report covers the whole quality surface your tasks expect (e.g. `--scope full`). - -**Remediation** - -- Read the JSON report and fix **every** finding at any severity (warning, advisory, error, or equivalent in the schema) unless the change proposal documents a **rare, explicit, justified** exception. -- After substantive edits, re-run until the report shows a **passing** outcome from the review module (e.g. overall verdict PASS / CI exit 0 per schema). -- Record the review command(s) and timestamp in `openspec/changes//TDD_EVIDENCE.md` or in the PR description when the change touches behavior or quality gates. - -**Consistency** - -- OpenSpec change **`tasks.md`** should include explicit tasks for generating/updating this file and clearing findings (see `openspec/config.yaml` β†’ `rules.tasks` β†’ β€œSpecFact code review JSON”). Agent runs should treat those tasks and this section as the same bar. - -### Clean-Code Review Gate - -specfact-cli enforces the 7-principle clean-code charter through the `specfact code review run` gate. The canonical charter lives in `skills/specfact-code-review/SKILL.md` (in `nold-ai/specfact-cli-modules`). This repo consumes the expanded clean-code categories from that review module: - -| Category | Principle covered | -|----------|-------------------| -| `naming` | Meaningful naming, exception-pattern rules | -| `kiss` | Keep It Simple: LOC, nesting-depth, parameter-count (Phase A: >80 warning / >120 error) | -| `yagni` | You Aren't Gonna Need It: unused-abstraction detection | -| `dry` | Don't Repeat Yourself: clone-detection and duplication checks | -| `solid` | SOLID principles: dependency-role and single-responsibility checks | - -Zero regressions in any of these categories are required before merge. Run the review gate with: - -```bash -hatch run specfact code review run --json --out .specfact/code-review.json -``` - -**Phase A thresholds are active.** Phase B thresholds (>40 / >80 LOC) are deferred to a later cleanup change and are not yet enforced. - -### Module Signature Gate (Required for Change Finalization) - -Before PR creation, every change MUST pass bundled module signature verification: - -1. Run `hatch run ./scripts/verify-modules-signature.py --require-signature`. -2. If verification fails because module contents changed, re-sign affected manifests: - - `hatch run python scripts/sign-modules.py --key-file ` -3. Re-run verification until green. - -Rules: - -- Do not merge/PR with stale or missing integrity metadata for bundled modules. -- Treat signature verification as a quality gate equal to lint/type-check/tests. -- Module version bump is mandatory before signing changed module contents. Do not keep the same module version when module files or signatures change. -- For any module re-sign/sign operation, increment module version using semver (major/minor/patch) so published/registered versions are immutable. -- Use signer/verifier enforcement paths: - - signer rejects changed modules with unchanged version by default; - - verifier/CI enforces version-bump checks for changed manifests. - -### OpenSpec Workflow - -Before modifying application code, **always** verify that an active OpenSpec change in `openspec/changes/` **explicitly covers the requested modification**. This is the spec-driven workflow defined in `openspec/config.yaml`. Skip only when the user explicitly says `"skip openspec"` or `"implement without openspec change"`. - -**Agent MUST NOT apply any code edits** when a fix, change, modification, or edit to any codebase file is requested unless an active OpenSpec change exists that explicitly covers the requested scope. If no such change exists, ask for clarification: - -- **a) New change** β€” create a new OpenSpec change proposal (`/opsx:new`) -- **b) Modify existing** β€” select and continue an existing change in `openspec/changes/` -- **c) Delta** β€” add a targeted delta to an existing change's specs - -The existence of *any* open change is not sufficient β€” the change must specifically address the requested modification. Do not proceed until one of the above is resolved. - -### Hard Gate: Strict TDD Order (Non-Negotiable) - -For any behavior change, the implementation order is mandatory and must be auditable: - -1. Update or add spec deltas first. -2. Add/modify tests next, mapped to spec scenarios. -3. Run tests and capture a **failing** result before implementation. -4. Only then modify production code. -5. Re-run tests and quality gates until passing. - -Required evidence: - -- Create/update `openspec/changes//TDD_EVIDENCE.md` with: - - test command(s) and timestamp for the pre-implementation failing run - - short failure summary - - test command(s) and timestamp for the post-implementation passing run - -Agent enforcement: - -- Agents MUST NOT edit production code for new/changed behavior until failing-test evidence is recorded. -- If this order cannot be followed, stop and ask the user for explicit override before proceeding. - -#### Change Order (`openspec/CHANGE_ORDER.md`) - -`openspec/CHANGE_ORDER.md` is the **single source of truth** for change sequencing, module grouping, and inter-change dependencies. Always use it to avoid redundant analysis of `openspec/changes/` folders. - -**Read it first** β€” before creating, implementing, or archiving any change, consult `CHANGE_ORDER.md` to: -- Check which changes are already archived (implemented) and their dates -- Verify hard blockers are resolved before starting implementation -- Understand where a new change fits in module order and wave sequencing - -**Keep it updated** β€” whenever a change lifecycle event occurs, update `CHANGE_ORDER.md` in the same commit: -- **New change created**: add a row to the correct module group table with folder name, GitHub issue link, and blocked-by dependencies -- **Change archived**: move the entry from "Pending" to "Implemented (archived)" with the archive date; update wave status if a wave is now complete -- **Change modified/renamed**: update the folder name and any affected dependency references -- **Blocker resolved**: update the "Blocked by" column (append βœ… to resolved blockers) - -#### GitHub hierarchy cache - -`.specfact/backlog/github_hierarchy_cache.md` is the local lookup source for current Epic and Feature hierarchy metadata in this repository. It is ephemeral local state and MUST NOT be committed. - -- Before creating a new change issue, syncing an existing change, or resolving parent or blocker metadata, consult the cache first. -- If the cache is missing or stale, rerun `python scripts/sync_github_hierarchy_cache.py`. -- Recreate the cache as part of OpenSpec and GitHub issue work rather than treating it as a versioned repo artifact. -- Use manual GitHub lookup only when the cache cannot answer the question after refresh. - -Use the `specfact-openspec-workflows` skill as the default execution path for OpenSpec lifecycle work. - -- When a Markdown plan exists and the intent is to create a change from that plan, use `.cursor/commands/wf-create-change-from-plan.md` (`/wf-change-from-plan`) to generate the proposal/tasks/spec deltas. -- For plans targeting an internal repository, still run the same workflow but follow its repo rules (for example, skip public GitHub issue creation where required). -- After any change is created or modified, run `.cursor/commands/wf-validate-change.md` (`/wf-validate-change`) and capture its output in `openspec/changes//CHANGE_VALIDATION.md`. -- Treat validation output as required context for dependency and interface impact, including any workflow-provided GitHub issue sync context. - -### Version Updates - -When bumping version, sync across: `pyproject.toml`, `setup.py`, `src/specfact_cli/__init__.py`. CI/CD auto-publishes to PyPI on merge to `main` only if version exceeds the published one. - -**Version semantics (SemVer):** -- `feature/*` branches β†’ **minor** increment (e.g. `0.5.0 β†’ 0.6.0`) -- `bugfix/*` / `hotfix/*` branches β†’ **patch** increment (e.g. `0.5.0 β†’ 0.5.1`) -- Breaking changes or major milestones β†’ **major** increment (requires explicit confirmation) - -Always propose the increment type based on the branch name and ask for confirmation before applying the bump. - -### Changelog - -Keep `CHANGELOG.md` updated with every meaningful change. Update it in the same commit that bumps the version and do not let them diverge. - -- Follow [Keep a Changelog](https://keepachangelog.com/) format: `Added`, `Changed`, `Fixed`, `Removed`, `Security` -- Each version entry must match the version in `pyproject.toml` -- Unreleased changes accumulate under `## [Unreleased]` until a version bump - -### Commits - -Follow Conventional Commits: `feat:`, `fix:`, `docs:`, `test:`, `refactor:`. - -#### Commit Signing (GPG) - -- This repository may enforce signed commits (`commit.gpgsign=true`). -- If an agent-run commit fails with `gpg failed to sign the data` in a non-interactive shell, the agent MUST: - 1. Stage all intended files. - 2. Provide the exact `git commit -S -m ""` command for the user to run locally. - 3. Continue with push/PR steps after the user confirms the signed commit exists. -- Agents MUST NOT bypass signing with `--no-gpg-sign` unless the user explicitly requests that override. - -### Documentation - -Keep docs current with every code change that affects user-facing behaviour. - -- Docs source lives in `docs/` and is published to [docs.specfact.io](https://docs.specfact.io) via GitHub Pages (Jekyll) -- **Preserve all front-matter** on every edit (`title`, `layout`, `nav_order`, `permalink`, etc.) and check `docs/_layouts/default.html` and `docs/index.md` before adding or removing front-matter keys -- When a command, option, or behaviour changes, update the corresponding doc page in the same PR -- Broken or outdated docs for users are P0; prefer a small doc fix over shipping undocumented changes - -### README Maintenance - -`README.md` (repo root) and the docs landing page (`docs/index.md` or `docs/README.md`) must stay in sync with what SpecFact actually does. - -- On larger refactorings or feature additions, reconsider the README from an **external/new-user perspective** and lead with value and USP, not internal architecture -- A first-time reader should understand what SpecFact does, why they'd use it, and how to get started within the first screen -- Do not let the README drift from the actual CLI interface or command list - -## Code Conventions - -- Python 3.11+, line length 120, Google-style docstrings -- `snake_case` for files/modules, `PascalCase` for classes, `UPPER_SNAKE_CASE` for constants -- All data structures use Pydantic `BaseModel` with `Field(...)` and descriptions -- CLI commands use `typer.Typer()` + `rich.console.Console()` -- Only write high-value comments and avoid verbose or redundant commentary -- `rich~=13.5.2` is pinned for semgrep compatibility and should not be upgraded without validation - -## CLI Command Pattern - -```python -import typer -from beartype import beartype -from icontract import require, ensure -from rich.console import Console - -app = typer.Typer() -console = Console() - -@app.command() -@require(lambda repo_path: repo_path.exists(), "Repository path must exist") -@beartype -def my_command( - repo_path: Path = typer.Argument(..., help="Path to repository"), -) -> None: - """Command docstring.""" - console.print("[bold]Processing...[/bold]") -``` - -## Backlog Command Topology - -Keep backlog functionality grouped under the common top-level `backlog` command: - -- `specfact backlog ceremony standup` -- `specfact backlog ceremony refinement` -- `specfact backlog analyze-deps` -- `specfact backlog delta status|impact|cost-estimate|rollback-analysis` -- `specfact backlog verify-readiness` - -Project-scoped orchestration belongs under `project`: - -- `specfact project link-backlog` -- `specfact project health-check` -- `specfact project devops-flow --stage --action <...>` -- `specfact project snapshot|regenerate|export-roadmap` - -## Testing - -**Contract-first approach**: `@icontract` contracts on public APIs are the primary coverage mechanism (target 80%+ API coverage). Redundant unit tests that only assert input validation or type checks should be removed because contracts and beartype already cover them. - -Test structure mirrors source: `tests/unit/`, `tests/integration/`, `tests/e2e/`. Use `@pytest.mark.asyncio` for async tests. Guard environment-sensitive logic with `os.environ.get("TEST_MODE") == "true"`. - -## CI/CD - -Key workflows in `.github/workflows/`: -- `tests.yml` β€” contract-first test execution -- `specfact.yml` β€” contract validation on PR/push (`hatch run specfact repro --verbose`) -- `pr-orchestrator.yml` β€” coordinates PR workflows -- `build-and-push.yml` β€” Docker image building (depends on all above passing) +This file is the mandatory bootstrap governance surface for coding agents working in this repository. It is intentionally compact. The detailed rules that used to live here have been preserved in `docs/agent-rules/` so new sessions do not pay the full context cost up front. + +## Mandatory bootstrap + +1. Read this file. +2. Read [docs/agent-rules/INDEX.md](docs/agent-rules/INDEX.md). +3. Read [docs/agent-rules/05-non-negotiable-checklist.md](docs/agent-rules/05-non-negotiable-checklist.md). +4. Detect repository root, active branch, and worktree state. +5. Reject implementation from the `dev` or `main` checkout unless the user explicitly overrides that rule. +6. If GitHub hierarchy metadata is needed and `.specfact/backlog/github_hierarchy_cache.md` is missing or stale, refresh it with `python scripts/sync_github_hierarchy_cache.py`. +7. Load any additional rule files required by the applicability matrix in [docs/agent-rules/INDEX.md](docs/agent-rules/INDEX.md) before implementation. + +## Precedence + +1. Direct system and developer instructions +2. Explicit user override where repository governance allows it +3. This file +4. [docs/agent-rules/05-non-negotiable-checklist.md](docs/agent-rules/05-non-negotiable-checklist.md) +5. Other selected files under `docs/agent-rules/` +6. Change-local OpenSpec artifacts and workflow notes + +## Non-negotiable gates + +- Work in a git worktree unless the user explicitly overrides that rule. +- Do not implement from the `dev` or `main` checkout by default. +- Treat a provided OpenSpec change id as candidate scope, not automatic permission to proceed. +- Verify the selected change against current repository reality and dependency state before implementation. +- Do not auto-refine stale or ambiguous changes without the user. +- Perform `spec -> tests -> failing evidence -> code -> passing evidence` in that order for behavior changes. +- Require public GitHub metadata completeness before implementation when linked issue workflow applies: parent, labels, project assignment, blockers, and blocked-by relationships. +- If a linked GitHub issue is already `in progress`, pause and ask for clarification before implementation. +- Run the required verification and quality gates for the touched scope before finalization. +- Fix SpecFact code review findings, including warnings, unless a rare explicit exception is documented. +- Treat the clean-code compliance gate as mandatory: the review surface enforces `naming`, `kiss`, `yagni`, `dry`, and `solid` categories and blocks regressions. +- Enforce module signatures and version bumps when signed module assets or manifests are affected. + +## Canonical rule docs + +- [docs/agent-rules/INDEX.md](docs/agent-rules/INDEX.md) +- [docs/agent-rules/10-session-bootstrap.md](docs/agent-rules/10-session-bootstrap.md) +- [docs/agent-rules/20-repository-context.md](docs/agent-rules/20-repository-context.md) +- [docs/agent-rules/30-worktrees-and-branching.md](docs/agent-rules/30-worktrees-and-branching.md) +- [docs/agent-rules/40-openspec-and-tdd.md](docs/agent-rules/40-openspec-and-tdd.md) +- [docs/agent-rules/50-quality-gates-and-review.md](docs/agent-rules/50-quality-gates-and-review.md) +- [docs/agent-rules/60-github-change-governance.md](docs/agent-rules/60-github-change-governance.md) +- [docs/agent-rules/70-release-commit-and-docs.md](docs/agent-rules/70-release-commit-and-docs.md) +- [docs/agent-rules/80-current-guidance-catalog.md](docs/agent-rules/80-current-guidance-catalog.md) + +Detailed guidance was moved by reference, not removed. If a rule seems missing here, consult the canonical rule docs before assuming the instruction was dropped. diff --git a/CLAUDE.md b/CLAUDE.md index 971f9f99..afa4a6b1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,344 +1,11 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +This file is an alias surface for Claude Code. Follow [AGENTS.md](AGENTS.md) as the primary bootstrap contract, then load the canonical governance docs in [docs/agent-rules/INDEX.md](docs/agent-rules/INDEX.md). -## Project Overview +## Claude-specific note -SpecFact CLI is a Python CLI tool for agile DevOps teams. It keeps backlogs, specs, tests, and code in sync with contract-driven development, validation, and enforcement. Built with Typer + Rich, using Hatch as the build system. Python 3.11+. +Claude must treat the canonical rule docs as the source of truth for worktree policy, OpenSpec gating, GitHub completeness checks, TDD order, quality gates, versioning, and documentation rules. Do not rely on this file as a standalone governance handbook. -## Essential Commands +## Clean-code alias -```bash -# Development environment -pip install -e ".[dev]" -hatch shell - -# Format & lint (run after every code change, in this order) -hatch run format # ruff format + fix -hatch run type-check # basedpyright strict mode -hatch run contract-test # contract-first validation (primary) -hatch test --cover -v # full pytest suite - -# Contract-first testing layers -hatch run contract-test-contracts # runtime contract validation only -hatch run contract-test-exploration # CrossHair symbolic execution -hatch run contract-test-scenarios # integration/E2E with contract refs -hatch run contract-test-full # all layers -hatch run contract-test-status # coverage status report - -# Run a single test file -hatch test -- tests/unit/specfact_cli/test_example.py -v - -# Lint subsystems -hatch run lint # full lint suite -hatch run governance # pylint detailed analysis -hatch run yaml-lint # YAML validation -hatch run lint-workflows # GitHub Actions actionlint - -# Code scanning -hatch run scan-all # semgrep analysis -``` - -## Architecture - -### Modular Command Registry with Lazy Loading - -The CLI uses a module package system in `src/specfact_cli/modules/`. Each module is a self-contained package: - -``` -modules/{name}/ - module-package.yaml # metadata: name, version, commands, dependencies - src/{name}/ - __init__.py - main.py # typer.Typer app with command definitions -``` - -The registry (`src/specfact_cli/registry/`) discovers modules at startup but defers imports until a command is actually invoked. `bootstrap.py` registers all modules; `registry.py` manages lazy loading; `module_packages.py` handles discovery from `module-package.yaml` files. - -**Entry flow**: `cli.py:cli_main()` β†’ Typer app with global options β†’ `ProgressiveDisclosureGroup` for help β†’ lazy-loaded command groups from registry. - -### Contract-First Development - -All public APIs must use `@icontract` decorators (`@require`, `@ensure`, `@invariant`) and `@beartype` for runtime type checking. CrossHair discovers counterexamples via symbolic execution. Contracts are the primary validation mechanism; traditional unit tests are secondary. - -### Key Subsystems - -- **`models/`** - Pydantic BaseModel classes for all data structures -- **`parsers/`**, **`analyzers/`** - Code analysis -- **`generators/`** - Code/spec generation using Jinja2 templates from `resources/templates/` -- **`validators/`** - Schema, contract, FSM validation -- **`adapters/`** - Bridge pattern for tool integrations (GitHub, Azure DevOps, Jira, Linear) -- **`modes/`** - Operational modes: CICD (fast, deterministic, non-interactive) vs Copilot (interactive, IDE-aware). Auto-detected from environment. -- **`resources/`** - Bundled prompts, templates, schemas, mappings (force-included in wheel) - -### Logging - -Use `from specfact_cli.common import get_bridge_logger` and avoid `print()` in production command paths. Debug logs go to `~/.specfact/logs/specfact-debug.log` when `--debug` is passed. - -## Development Workflow - -### Branch Protection - -`dev` and `main` are protected. Always work on feature/bugfix/hotfix branches and submit PRs: -- `feature/your-feature-name` -- `bugfix/your-bugfix-name` -- `hotfix/your-hotfix-name` - -### Git Worktree Policy (Parallel Development) - -Use git worktrees for parallel development branches only. - -- Allowed branch types in worktrees: `feature/*`, `bugfix/*`, `hotfix/*`, `chore/*` -- Forbidden in worktrees: `dev`, `main` -- The primary checkout remains the canonical `dev` workspace - -Canonical layout: - -- Primary checkout: `.../specfact-cli` (tracks `dev`) -- Worktrees root: `.../specfact-cli-worktrees//` -- Worktree folder name MUST reflect the branch slug - -Create a new worktree from `origin/dev`: - -```bash -git fetch origin -git worktree add ../specfact-cli-worktrees/feature/ -b feature/ origin/dev -``` - -Attach an existing local branch to a worktree: - -```bash -git fetch origin -git worktree add ../specfact-cli-worktrees/feature/ feature/ -``` - -Operational rules: - -- Never create a worktree for `dev` or `main` -- One branch maps to exactly one worktree path at a time -- Keep branch naming consistent: `/-` -- Keep one active OpenSpec change scope per branch where possible -- Create a separate virtual environment inside each worktree (for example, `.venv/`) -- Bootstrap Hatch once per new worktree before running quality gates: `hatch env create` -- Run quick pre-flight checks from the worktree root: `hatch run smart-test-status` and `hatch run contract-test-status` -- If Hatch cannot write to default home/cache paths, set writable overrides (for example `HATCH_DATA_DIR=/tmp/hatch-data` and `HATCH_CACHE_DIR=/tmp/hatch-cache`) -- Run all quality gates from inside the active worktree before commit/PR - -Conflict avoidance: - -- Check `openspec/CHANGE_ORDER.md` before creating new parallel branches -- Avoid concurrent branches editing the same `openspec/changes//` directory -- Rebase frequently on `origin/dev` in each worktree -- Use `git worktree list` daily to detect stale or incorrect branch/path attachments - -Local cleanup after merge to `dev`: - -```bash -git fetch origin -git worktree remove ../specfact-cli-worktrees/feature/ -git branch -d feature/ -git worktree prune -``` - -If remote cleanup is needed: - -```bash -git push origin --delete feature/ -``` - -### Pre-Commit Checklist - -Run all steps in order before committing. Every step must pass with no errors. - -1. `hatch run format` # ruff format + autofix -2. `hatch run type-check` # basedpyright strict -3. `hatch run lint` # full lint suite -4. `hatch run yaml-lint` # YAML + markdown validation -5. `hatch run contract-test` # contract-first validation -6. `hatch run smart-test` # targeted test run (use `smart-test-full` for larger modifications) - -### Clean-Code Review Gate - -specfact-cli enforces the 7-principle clean-code charter through the `specfact code review run` gate. The canonical charter lives in `skills/specfact-code-review/SKILL.md` (in `nold-ai/specfact-cli-modules`). This repo consumes the expanded clean-code categories from that review module: - -| Category | Principle covered | -|----------|-------------------| -| `naming` | Meaningful naming, exception-pattern rules | -| `kiss` | Keep It Simple: LOC, nesting-depth, parameter-count (Phase A: >80 warning / >120 error) | -| `yagni` | You Aren't Gonna Need It: unused-abstraction detection | -| `dry` | Don't Repeat Yourself: clone-detection and duplication checks | -| `solid` | SOLID principles: dependency-role and single-responsibility checks | - -Zero regressions in any of these categories are required before merge. Run the review gate with: - -```bash -hatch run specfact code review run --json --out .specfact/code-review.json -``` - -**Phase A thresholds are active.** Phase B thresholds (>40 / >80 LOC) are deferred to a later cleanup change and are not yet enforced. - -### OpenSpec Workflow - -Before modifying application code, **always** verify that an active OpenSpec change in `openspec/changes/` **explicitly covers the requested modification**. This is the spec-driven workflow defined in `openspec/config.yaml`. Skip only when the user explicitly says `"skip openspec"` or `"implement without openspec change"`. - -**Claude MUST NOT apply any code edits** when a fix, change, modification, or edit to any codebase file is requested unless an active OpenSpec change exists that explicitly covers the requested scope. If no such change exists, ask for clarification: - -- **a) New change** β€” create a new OpenSpec change proposal (`/opsx:new`) -- **b) Modify existing** β€” select and continue an existing change in `openspec/changes/` -- **c) Delta** β€” add a targeted delta to an existing change's specs - -The existence of *any* open change is not sufficient β€” the change must specifically address the requested modification. Do not proceed until one of the above is resolved. - -Use the `specfact-openspec-workflows` skill as the default execution path for OpenSpec lifecycle work. - -- When a Markdown plan exists and the intent is to create a change from that plan, use `.cursor/commands/wf-create-change-from-plan.md` (`/wf-change-from-plan`) to generate the proposal/tasks/spec deltas. -- For plans targeting an internal repository, still run the same workflow but follow its repo rules (for example, skip public GitHub issue creation where required). -- After any change is created or modified, run `.cursor/commands/wf-validate-change.md` (`/wf-validate-change`) and capture its output in `openspec/changes//CHANGE_VALIDATION.md`. -- Treat validation output as required context for dependency and interface impact, including any workflow-provided GitHub issue sync context. - -### Hard Gate: Strict TDD Order (Non-Negotiable) - -For any behavior change, the implementation order is mandatory and must be auditable: - -1. Update or add spec deltas first. -2. Add/modify tests next, mapped to spec scenarios. -3. Run tests and capture a **failing** result before implementation. -4. Only then modify production code. -5. Re-run tests and quality gates until passing. - -Required evidence: - -- Create/update `openspec/changes//TDD_EVIDENCE.md` with: - - test command(s) and timestamp for the pre-implementation failing run - - short failure summary - - test command(s) and timestamp for the post-implementation passing run - -Claude enforcement: - -- Claude MUST NOT edit production code for new/changed behavior until failing-test evidence is recorded. -- If this order cannot be followed, stop and ask the user for explicit override before proceeding. - -#### Change Order (`openspec/CHANGE_ORDER.md`) - -`openspec/CHANGE_ORDER.md` is the **single source of truth** for change sequencing, module grouping, and inter-change dependencies. Always use it to avoid redundant analysis of `openspec/changes/` folders. - -**Read it first** β€” before creating, implementing, or archiving any change, consult `CHANGE_ORDER.md` to: -- Check which changes are already archived (implemented) and their dates -- Verify hard blockers are resolved before starting implementation -- Understand where a new change fits in module order and wave sequencing - -**Keep it updated** β€” whenever a change lifecycle event occurs, update `CHANGE_ORDER.md` in the same commit: -- **New change created**: add a row to the correct module group table with folder name, GitHub issue link, and blocked-by dependencies -- **Change archived**: move the entry from "Pending" to "Implemented (archived)" with the archive date; update wave status if a wave is now complete -- **Change modified/renamed**: update the folder name and any affected dependency references -- **Blocker resolved**: update the "Blocked by" column (append βœ… to resolved blockers) - -### Version Updates - -When bumping version, sync across: `pyproject.toml`, `setup.py`, `src/specfact_cli/__init__.py`. CI/CD auto-publishes to PyPI on merge to `main` only if version exceeds the published one. - -**Version semantics (SemVer):** -- `feature/*` branches β†’ **minor** increment (e.g. `0.5.0 β†’ 0.6.0`) -- `bugfix/*` / `hotfix/*` branches β†’ **patch** increment (e.g. `0.5.0 β†’ 0.5.1`) -- Breaking changes or major milestones β†’ **major** increment (requires explicit confirmation) - -Always propose the increment type based on the branch name and ask for confirmation before applying the bump. - -### Changelog - -Keep `CHANGELOG.md` updated with every meaningful change. Update it in the same commit that bumps the version β€” never let them diverge. - -- Follow [Keep a Changelog](https://keepachangelog.com/) format: `Added`, `Changed`, `Fixed`, `Removed`, `Security` -- Each version entry must match the version in `pyproject.toml` -- Unreleased changes accumulate under `## [Unreleased]` until a version bump - -### Commits - -Follow Conventional Commits: `feat:`, `fix:`, `docs:`, `test:`, `refactor:`. - -#### Commit Signing (GPG) - -- This repository may enforce signed commits (`commit.gpgsign=true`). -- If an agent-run commit fails with `gpg failed to sign the data` in a non-interactive shell, Claude MUST: - 1. Stage all intended files. - 2. Provide the exact `git commit -S -m ""` command for the user to run locally. - 3. Continue with push/PR steps after the user confirms the signed commit exists. -- Claude MUST NOT bypass signing with `--no-gpg-sign` unless the user explicitly requests that override. - -### Documentation - -Keep docs current with every code change that affects user-facing behaviour. - -- Docs source lives in `docs/` and is published to [docs.specfact.io](https://docs.specfact.io) via GitHub Pages (Jekyll) -- **Preserve all front-matter** on every edit (`title`, `layout`, `nav_order`, `permalink`, etc.) β€” check `docs/_layouts/default.html` and `docs/index.md` before adding or removing front-matter keys -- When a command, option, or behaviour changes, update the corresponding doc page in the same PR -- Broken or outdated docs for users are P0 β€” prefer a small doc fix over shipping undocumented changes - -### README Maintenance - -`README.md` (repo root) and the docs landing page (`docs/index.md` or `docs/README.md`) must stay in sync with what SpecFact actually does. - -- On larger refactorings or feature additions, reconsider the README from an **external / new-user perspective**: lead with value and USP, not internal architecture -- A first-time reader should understand what SpecFact does, why they'd use it, and how to get started within the first screen -- Do not let the README drift from the actual CLI interface or command list - -## Backlog Command Topology - -Keep backlog functionality grouped under the common top-level `backlog` command: - -- `specfact backlog ceremony standup` -- `specfact backlog ceremony refinement` -- `specfact backlog analyze-deps` -- `specfact backlog delta status|impact|cost-estimate|rollback-analysis` -- `specfact backlog verify-readiness` - -Project-scoped orchestration belongs under `project`: - -- `specfact project link-backlog` -- `specfact project health-check` -- `specfact project devops-flow --stage --action <...>` -- `specfact project snapshot|regenerate|export-roadmap` - -## Code Conventions - -- Python 3.11+, line length 120, Google-style docstrings -- `snake_case` for files/modules, `PascalCase` for classes, `UPPER_SNAKE_CASE` for constants -- All data structures use Pydantic `BaseModel` with `Field(...)` and descriptions -- CLI commands use `typer.Typer()` + `rich.console.Console()` -- Only write high-value comments; avoid verbose or redundant commentary -- `rich~=13.5.2` is pinned for semgrep compatibility β€” do not upgrade without checking - -## CLI Command Pattern - -```python -import typer -from beartype import beartype -from icontract import require, ensure -from rich.console import Console - -app = typer.Typer() -console = Console() - -@app.command() -@require(lambda repo_path: repo_path.exists(), "Repository path must exist") -@beartype -def my_command( - repo_path: Path = typer.Argument(..., help="Path to repository"), -) -> None: - """Command docstring.""" - console.print("[bold]Processing...[/bold]") -``` - -## Testing - -**Contract-first approach**: `@icontract` contracts on public APIs are the primary coverage mechanism (target 80%+ API coverage). Redundant unit tests that merely assert input validation or type checks should be removed β€” contracts and beartype handle that. - -Test structure mirrors source: `tests/unit/`, `tests/integration/`, `tests/e2e/`. Use `@pytest.mark.asyncio` for async tests. Guard environment-sensitive logic with `os.environ.get("TEST_MODE") == "true"`. - -## CI/CD - -Key workflows in `.github/workflows/`: -- `tests.yml` β€” contract-first test execution -- `specfact.yml` β€” contract validation on PR/push (`hatch run specfact repro --verbose`) -- `pr-orchestrator.yml` β€” coordinates PR workflows -- `build-and-push.yml` β€” Docker image building (depends on all above passing) +Claude must preserve the clean-code compliance gate and its category references. The canonical review surface enforces `naming`, `kiss`, `yagni`, `dry`, and `solid` and treats clean-code regressions as blocking until they are fixed or explicitly justified. diff --git a/docs/.doc-frontmatter-enforced b/docs/.doc-frontmatter-enforced index bfca20a4..956e6474 100644 --- a/docs/.doc-frontmatter-enforced +++ b/docs/.doc-frontmatter-enforced @@ -6,3 +6,4 @@ docs/core-cli/init.md docs/reference/documentation-url-contract.md docs/contributing/docs-sync.md docs/contributing/frontmatter-schema.md +docs/agent-rules/*.md diff --git a/docs/_data/nav.yml b/docs/_data/nav.yml index 0f944347..0eb2f4b6 100644 --- a/docs/_data/nav.yml +++ b/docs/_data/nav.yml @@ -91,6 +91,27 @@ url: /guides/openspec-journey/ expertise: [intermediate] +- section: Agent Governance + items: + - title: Rule Index + url: /contributing/agent-rules/ + expertise: [advanced] + - title: Non-Negotiable Checklist + url: /contributing/agent-rules/non-negotiable-checklist/ + expertise: [advanced] + - title: Session Bootstrap + url: /contributing/agent-rules/session-bootstrap/ + expertise: [advanced] + - title: OpenSpec and TDD + url: /contributing/agent-rules/openspec-and-tdd/ + expertise: [advanced] + - title: GitHub Change Governance + url: /contributing/agent-rules/github-change-governance/ + expertise: [advanced] + - title: Quality Gates and Review + url: /contributing/agent-rules/quality-gates-and-review/ + expertise: [advanced] + - section: Integrations items: - title: Integrations Overview diff --git a/docs/agent-rules/05-non-negotiable-checklist.md b/docs/agent-rules/05-non-negotiable-checklist.md new file mode 100644 index 00000000..7716dd78 --- /dev/null +++ b/docs/agent-rules/05-non-negotiable-checklist.md @@ -0,0 +1,50 @@ +--- +layout: default +title: Agent non-negotiable checklist +permalink: /contributing/agent-rules/non-negotiable-checklist/ +description: Always-load SHALL gates that apply to every implementation session in the repository. +keywords: [agents, governance, checklist, tdd, worktree] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - docs/agent-rules/** + - openspec/CHANGE_ORDER.md + - openspec/config.yaml +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-non-negotiable-checklist +always_load: true +applies_when: + - session-bootstrap + - implementation +priority: 5 +blocking: true +user_interaction_required: true +stop_conditions: + - main checkout implementation attempted without override + - no valid OpenSpec change covers requested modification + - stale or ambiguous change requires refinement + - failing-before evidence missing for behavior change +depends_on: + - agent-rules-index +--- + +# Agent non-negotiable checklist + +- SHALL work in a git worktree unless the user explicitly overrides that rule. +- SHALL not implement from the main checkout by default. +- SHALL treat a provided OpenSpec change id as candidate scope, not automatic permission to proceed. +- SHALL verify selected change validity against current repository reality and dependency state before implementation. +- SHALL not auto-refine stale, superseded, or ambiguous changes without the user. +- SHALL consult `openspec/CHANGE_ORDER.md` before creating, implementing, or archiving a change. +- SHALL consult `.specfact/backlog/github_hierarchy_cache.md` before manual GitHub hierarchy lookup and SHALL refresh it when missing or stale. +- SHALL require public GitHub metadata completeness before implementation when linked issue workflow applies: parent, labels, project assignment, blockers, and blocked-by relationships. +- SHALL check whether a linked GitHub issue is already `in progress` and SHALL pause for clarification if concurrent work is possible. +- SHALL perform `spec -> tests -> failing evidence -> code -> passing evidence` in that order for behavior changes. +- SHALL run required verification and quality gates for the touched scope before finalization. +- SHALL fix SpecFact code review findings, including warnings, unless a rare and explicit exception is documented. +- SHALL enforce module signatures and version bumps when signed module assets or manifests are affected. +- SHALL preserve existing instructions by moving them to canonical rule files before shortening the bootstrap surfaces. diff --git a/docs/agent-rules/10-session-bootstrap.md b/docs/agent-rules/10-session-bootstrap.md new file mode 100644 index 00000000..dc34601e --- /dev/null +++ b/docs/agent-rules/10-session-bootstrap.md @@ -0,0 +1,54 @@ +--- +layout: default +title: Agent session bootstrap +permalink: /contributing/agent-rules/session-bootstrap/ +description: Deterministic startup sequence for repository sessions after AGENTS.md is loaded. +keywords: [agents, bootstrap, worktree, cache, instructions] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - docs/agent-rules/** + - .specfact/backlog/github_hierarchy_cache.md + - scripts/sync_github_hierarchy_cache.py +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-session-bootstrap +always_load: true +applies_when: + - session-bootstrap +priority: 10 +blocking: true +user_interaction_required: true +stop_conditions: + - unsupported branch or worktree context + - cache-dependent GitHub work without refreshed hierarchy cache +depends_on: + - agent-rules-index + - agent-rules-non-negotiable-checklist +--- + +# Agent session bootstrap + +## Required startup checks + +1. Detect repository root, active branch, and whether the session is running in a worktree. +2. If the session is on `dev` or `main`, do not implement until the user explicitly allows it or a worktree is created. +3. Read `AGENTS.md`, then load the rule index and non-negotiable checklist. +4. Determine whether the task is read-only, artifact-only, or implementation work. +5. If GitHub hierarchy data is required, confirm `.specfact/backlog/github_hierarchy_cache.md` is present and fresh enough for the task. +6. If the cache is missing or stale, refresh it with `python scripts/sync_github_hierarchy_cache.py`. +7. Load the additional rule files required by the task signal from the index. + +## Stop and continue behavior + +- If the session is on the main checkout and the user did not override, stop implementation and create or switch to a worktree. +- If the requested work is tied to stale or ambiguous change metadata, continue only in read-only investigation mode until the user clarifies. +- If GitHub hierarchy metadata is needed and the cache cannot answer after refresh, manual GitHub lookup is allowed. +- If the task is purely explanatory or read-only, full implementation gates do not need to run. + +## Why this file exists + +This file keeps session bootstrap deterministic after `AGENTS.md` becomes compact. It is small enough to load every time, but specific enough to prevent drift across models and sessions. diff --git a/docs/agent-rules/20-repository-context.md b/docs/agent-rules/20-repository-context.md new file mode 100644 index 00000000..fc276a32 --- /dev/null +++ b/docs/agent-rules/20-repository-context.md @@ -0,0 +1,67 @@ +--- +layout: default +title: Agent repository context +permalink: /contributing/agent-rules/repository-context/ +description: Project overview, key commands, architecture, and logging guidance preserved from the previous AGENTS.md. +keywords: [agents, commands, architecture, logging, project-overview] +audience: [team, enterprise] +expertise_level: [intermediate, advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - docs/agent-rules/** + - src/specfact_cli/** + - pyproject.toml +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-repository-context +always_load: false +applies_when: + - repository-orientation + - command-lookup +priority: 20 +blocking: false +user_interaction_required: false +stop_conditions: + - none +depends_on: + - agent-rules-index +--- + +# Agent repository context + +## Project overview + +SpecFact CLI is a Python CLI tool for agile DevOps teams. It keeps backlogs, specs, tests, and code in sync with contract-driven development, validation, and enforcement. It is built with Typer and Rich, uses Hatch as the build system, and targets Python 3.11+. + +## Essential commands + +```bash +pip install -e ".[dev]" +hatch shell +hatch run format +hatch run type-check +hatch run contract-test +hatch test --cover -v +hatch run lint +hatch run yaml-lint +hatch run lint-workflows +hatch run scan-all +hatch run specfact code review run --json --out .specfact/code-review.json +``` + +## Architecture + +- Modular command registry with lazy loading under `src/specfact_cli/modules/` +- Pydantic models in `models/` +- Parsers and analyzers in `parsers/` and `analyzers/` +- Jinja2-backed generation under `generators/` +- Validation logic under `validators/` +- Tool integrations through bridge adapters in `adapters/` +- Operational modes under `modes/` +- Templates, prompts, schemas, and mappings under `resources/` + +## Logging + +Use `from specfact_cli.common import get_bridge_logger` in production paths and avoid `print()` in `src/`. Debug logs go to `~/.specfact/logs/specfact-debug.log` when `--debug` is passed. diff --git a/docs/agent-rules/30-worktrees-and-branching.md b/docs/agent-rules/30-worktrees-and-branching.md new file mode 100644 index 00000000..b746acdb --- /dev/null +++ b/docs/agent-rules/30-worktrees-and-branching.md @@ -0,0 +1,56 @@ +--- +layout: default +title: Agent worktrees and branching +permalink: /contributing/agent-rules/worktrees-and-branching/ +description: Branch protection, worktree policy, and conflict-avoidance rules for implementation work. +keywords: [agents, worktrees, git, branching, conflicts] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - docs/agent-rules/** + - scripts/worktree.sh + - openspec/CHANGE_ORDER.md +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-worktrees-and-branching +always_load: false +applies_when: + - implementation + - branch-management +priority: 30 +blocking: true +user_interaction_required: true +stop_conditions: + - implementation requested from dev or main without override + - conflicting worktree ownership detected +depends_on: + - agent-rules-index + - agent-rules-non-negotiable-checklist +--- + +# Agent worktrees and branching + +## Branch protection + +`dev` and `main` are protected. Work on `feature/*`, `bugfix/*`, `hotfix/*`, or `chore/*` branches and submit PRs to `dev`. + +## Worktree policy + +- The primary checkout remains the canonical `dev` workspace. +- Use `scripts/worktree.sh create feature/` to create implementation worktrees. +- Never create a worktree for `dev` or `main`. +- One branch maps to one worktree path at a time. +- Keep one active OpenSpec change scope per branch where possible. +- Create a dedicated virtual environment inside each worktree. +- Bootstrap Hatch once per new worktree with `hatch env create`. +- Run quick pre-flight checks from the worktree root with `hatch run smart-test-status` and `hatch run contract-test-status`. + +## Conflict avoidance + +- Check `openspec/CHANGE_ORDER.md` before creating a new worktree. +- Avoid concurrent branches editing the same `openspec/changes//` directory. +- Rebase frequently on `origin/dev`. +- Use `git worktree list` to detect stale or incorrect attachments. diff --git a/docs/agent-rules/40-openspec-and-tdd.md b/docs/agent-rules/40-openspec-and-tdd.md new file mode 100644 index 00000000..47c124e6 --- /dev/null +++ b/docs/agent-rules/40-openspec-and-tdd.md @@ -0,0 +1,60 @@ +--- +layout: default +title: Agent OpenSpec and TDD +permalink: /contributing/agent-rules/openspec-and-tdd/ +description: OpenSpec selection, change validation, and strict TDD order for behavior changes. +keywords: [agents, openspec, tdd, change-validation, evidence] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - openspec/config.yaml + - openspec/CHANGE_ORDER.md + - docs/agent-rules/** +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-openspec-and-tdd +always_load: false +applies_when: + - implementation + - openspec-change-selection +priority: 40 +blocking: true +user_interaction_required: true +stop_conditions: + - no valid OpenSpec change + - change stale or superseded + - failing-before evidence missing +depends_on: + - agent-rules-index + - agent-rules-non-negotiable-checklist +--- + +# Agent OpenSpec and TDD + +## OpenSpec workflow + +- Before modifying application code, verify that an active OpenSpec change explicitly covers the requested modification. +- Skip only when the user explicitly says `skip openspec` or `implement without openspec change`. +- The existence of any open change is not sufficient; the change must cover the requested scope. +- If no change exists, clarify whether the work needs a new change, a modified existing change, or a delta. + +## Change validity + +- Never implement from a change id alone. +- Revalidate the selected change against current repository reality, dependency state, and possible superseding work. +- Use `openspec validate --strict` and, where appropriate, the workflow validator to capture dependency and interface impact. + +## Strict TDD order + +1. Update or add spec deltas first. +2. Add or modify tests mapped to spec scenarios. +3. Run tests and capture a failing result before production edits. +4. Only then modify production code. +5. Re-run tests and quality gates until passing. + +## Evidence + +Record the failing-before and passing-after runs in `openspec/changes//TDD_EVIDENCE.md`. Behavior work is blocked until failing-first evidence exists. diff --git a/docs/agent-rules/50-quality-gates-and-review.md b/docs/agent-rules/50-quality-gates-and-review.md new file mode 100644 index 00000000..373e94cb --- /dev/null +++ b/docs/agent-rules/50-quality-gates-and-review.md @@ -0,0 +1,68 @@ +--- +layout: default +title: Agent quality gates and review +permalink: /contributing/agent-rules/quality-gates-and-review/ +description: Required formatting, typing, contract, review, and signature gates for touched scope. +keywords: [agents, quality, review, contracts, signatures] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - pyproject.toml + - scripts/check_doc_frontmatter.py + - scripts/pre_commit_code_review.py + - scripts/verify-modules-signature.py + - docs/agent-rules/** +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-quality-gates-and-review +always_load: false +applies_when: + - implementation + - verification + - finalization +priority: 50 +blocking: true +user_interaction_required: false +stop_conditions: + - required quality gate failed + - specfact code review findings unresolved + - module signature verification failed +depends_on: + - agent-rules-index + - agent-rules-openspec-and-tdd +--- + +# Agent quality gates and review + +## Pre-commit order + +1. `hatch run format` +2. `hatch run type-check` +3. `hatch run lint` +4. `hatch run yaml-lint` +5. `hatch run contract-test` +6. `hatch run smart-test` + +## SpecFact code review JSON + +- Treat `.specfact/code-review.json` as mandatory evidence before an OpenSpec change is complete. +- Re-run the review when the report is missing or stale. +- Resolve every finding at any severity unless a rare, explicit exception is documented. +- Record the review command and timestamps in `TDD_EVIDENCE.md` or the PR description when quality gates are part of the change. + +## Clean-code review gate + +The repository enforces the clean-code charter through `specfact code review run`. Zero regressions in `naming`, `kiss`, `yagni`, `dry`, and `solid` are required before merge. + +## Module signature gate + +Before PR creation, every change that affects signed module assets or manifests must pass: + +```bash +hatch run ./scripts/verify-modules-signature.py --require-signature +``` + +If verification fails because module contents changed, re-sign the affected manifests and bump the module version before re-running verification. diff --git a/docs/agent-rules/60-github-change-governance.md b/docs/agent-rules/60-github-change-governance.md new file mode 100644 index 00000000..862cb26b --- /dev/null +++ b/docs/agent-rules/60-github-change-governance.md @@ -0,0 +1,59 @@ +--- +layout: default +title: Agent GitHub change governance +permalink: /contributing/agent-rules/github-change-governance/ +description: Cache-first GitHub issue governance for parent lookup, metadata completeness, and concurrency ambiguity checks. +keywords: [agents, github, hierarchy-cache, blockers, labels, project] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - openspec/CHANGE_ORDER.md + - scripts/sync_github_hierarchy_cache.py + - .specfact/backlog/github_hierarchy_cache.md + - docs/agent-rules/** +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-github-change-governance +always_load: false +applies_when: + - github-public-work + - change-readiness +priority: 60 +blocking: true +user_interaction_required: true +stop_conditions: + - parent or blocker metadata missing + - labels or project assignment missing + - linked issue already in progress +depends_on: + - agent-rules-index + - agent-rules-session-bootstrap + - agent-rules-openspec-and-tdd +--- + +# Agent GitHub change governance + +## Hierarchy cache + +`.specfact/backlog/github_hierarchy_cache.md` is the local lookup source for current Epic and Feature hierarchy metadata in this repository. It is ephemeral local state and must not be committed. + +- Consult the cache first before creating a new change issue, syncing an existing change, or resolving parent or blocker metadata. +- If the cache is missing or stale, rerun `python scripts/sync_github_hierarchy_cache.py`. +- Use manual GitHub lookup only when the cache cannot answer the question after refresh. + +## Public-work readiness checks + +Before implementation on a publicly tracked change issue: + +- Verify the linked issue exists. +- Verify its parent relationship is correct against current cache-backed GitHub reality. +- Verify required labels are present. +- Verify project assignment is present. +- Verify blockers and blocked-by relationships are complete. + +## Concurrency ambiguity + +If the linked GitHub issue is already `in progress`, treat that as a blocking ambiguity. Pause implementation and ask the user to clarify whether the change is already being worked in another session. Read-only investigation may continue while implementation remains blocked. diff --git a/docs/agent-rules/70-release-commit-and-docs.md b/docs/agent-rules/70-release-commit-and-docs.md new file mode 100644 index 00000000..d093c058 --- /dev/null +++ b/docs/agent-rules/70-release-commit-and-docs.md @@ -0,0 +1,59 @@ +--- +layout: default +title: Agent release, commit, and docs rules +permalink: /contributing/agent-rules/release-commit-and-docs/ +description: Versioning, changelog, documentation, README, and commit-signing rules preserved from the previous AGENTS.md. +keywords: [agents, versioning, changelog, docs, commits] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - CHANGELOG.md + - README.md + - docs/** + - pyproject.toml + - setup.py + - src/specfact_cli/__init__.py +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-release-commit-and-docs +always_load: false +applies_when: + - finalization + - release + - documentation-update +priority: 70 +blocking: false +user_interaction_required: true +stop_conditions: + - version bump requested without confirmation +depends_on: + - agent-rules-index + - agent-rules-quality-gates-and-review +--- + +# Agent release, commit, and docs rules + +## Versioning + +- Keep version updates in sync across `pyproject.toml`, `setup.py`, and `src/specfact_cli/__init__.py`. +- `feature/*` branches imply a minor bump, `bugfix/*` and `hotfix/*` imply a patch bump, and major bumps require explicit confirmation. + +## Changelog + +- Update `CHANGELOG.md` in the same commit as the version bump. +- Follow Keep a Changelog sections: `Added`, `Changed`, `Fixed`, `Removed`, `Security`. + +## Commits + +- Use Conventional Commits. +- If signed commits fail in a non-interactive shell, stage files and hand the exact `git commit -S -m ""` command to the user instead of bypassing signing. + +## Documentation and README + +- Keep docs current with every user-facing behavior change. +- Preserve all Jekyll frontmatter on docs edits. +- Update navigation when adding or moving pages. +- Keep `README.md` and the docs landing page aligned with what SpecFact actually does. diff --git a/docs/agent-rules/80-current-guidance-catalog.md b/docs/agent-rules/80-current-guidance-catalog.md new file mode 100644 index 00000000..3f497a22 --- /dev/null +++ b/docs/agent-rules/80-current-guidance-catalog.md @@ -0,0 +1,71 @@ +--- +layout: default +title: Agent migrated guidance catalog +permalink: /contributing/agent-rules/migrated-guidance-catalog/ +description: Preserved guidance moved out of the previous long AGENTS.md before further tailoring and decomposition. +keywords: [agents, migrated-guidance, code-conventions, ci, testing] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - docs/agent-rules/** + - src/specfact_cli/** + - tests/** + - .github/workflows/** +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-migrated-guidance-catalog +always_load: false +applies_when: + - detailed-reference +priority: 80 +blocking: false +user_interaction_required: false +stop_conditions: + - none +depends_on: + - agent-rules-index +--- + +# Agent migrated guidance catalog + +This file preserves current instructions that were previously inline in the long `AGENTS.md` but are not yet fully split into narrower docs. Nothing here was intentionally dropped during the compact-governance migration. + +## Developing specfact-cli-modules + +Bundle code in **specfact-cli-modules** imports from `specfact_cli`. For local IDE work in the modules repo, run `hatch env create` there, keep `specfact-cli` available at `../specfact-cli`, and select the modules repo `.venv` in the IDE. + +## Code conventions + +- Python 3.11+, line length 120, Google-style docstrings +- `snake_case` for files, modules, and functions +- `PascalCase` for classes +- `UPPER_SNAKE_CASE` for constants +- All data structures use Pydantic `BaseModel` with `Field(...)` and descriptions +- CLI commands use `typer.Typer()` and `rich.console.Console()` + +## CLI command pattern + +Use `@beartype`, `@require`, and `@ensure` on public command functions and keep command implementations typed and contract-bound. + +## Backlog command topology + +- `specfact backlog ceremony standup` +- `specfact backlog ceremony refinement` +- `specfact backlog analyze-deps` +- `specfact backlog delta status|impact|cost-estimate|rollback-analysis` +- `specfact backlog verify-readiness` +- `specfact project link-backlog` +- `specfact project health-check` +- `specfact project devops-flow --stage --action <...>` +- `specfact project snapshot|regenerate|export-roadmap` + +## Testing + +Contract-first coverage remains the primary testing philosophy. Test structure mirrors source under `tests/unit/`, `tests/integration/`, and `tests/e2e/`. Guard environment-sensitive logic with `os.environ.get("TEST_MODE") == "true"`. + +## CI/CD + +Key workflows in `.github/workflows/` include `tests.yml`, `specfact.yml`, `pr-orchestrator.yml`, and `build-and-push.yml`. diff --git a/docs/agent-rules/INDEX.md b/docs/agent-rules/INDEX.md new file mode 100644 index 00000000..dd4f892c --- /dev/null +++ b/docs/agent-rules/INDEX.md @@ -0,0 +1,87 @@ +--- +layout: default +title: Agent rules index +permalink: /contributing/agent-rules/ +description: Canonical deterministic loader for repository governance instructions used by AGENTS.md and other AI instruction surfaces. +keywords: [agents, governance, instructions, openspec, worktree] +audience: [team, enterprise] +expertise_level: [advanced] +doc_owner: specfact-cli +tracks: + - AGENTS.md + - CLAUDE.md + - .github/copilot-instructions.md + - .cursor/rules/session_startup_instructions.mdc + - docs/agent-rules/** + - scripts/check_doc_frontmatter.py +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +id: agent-rules-index +always_load: true +applies_when: + - session-bootstrap +priority: 0 +blocking: true +user_interaction_required: false +stop_conditions: + - canonical rule index missing +depends_on: [] +--- + +# Agent rules index + +This page is the canonical loader for repository governance instructions. `AGENTS.md` stays small and mandatory, but the detailed rules live here and in the linked rule files so new sessions do not have to absorb the full policy corpus up front. + +## Bootstrap sequence + +1. Read `AGENTS.md`. +2. Load this index. +3. Load [`05-non-negotiable-checklist.md`](./05-non-negotiable-checklist.md). +4. Detect repository, branch, and worktree state. +5. Reject implementation from the `dev` or `main` checkout unless the user explicitly overrides that rule. +6. If GitHub hierarchy metadata is needed and `.specfact/backlog/github_hierarchy_cache.md` is missing or stale, refresh it with `python scripts/sync_github_hierarchy_cache.py`. +7. Load additional rule files from the applicability matrix below before implementation. + +## Precedence + +1. Direct system and developer instructions +2. Explicit user override where repository governance allows it +3. `AGENTS.md` +4. `docs/agent-rules/05-non-negotiable-checklist.md` +5. Other `docs/agent-rules/*.md` files selected through this index +6. Change-local OpenSpec artifacts and workflow notes + +## Always-load rules + +| Order | File | Purpose | +| --- | --- | --- | +| 0 | `INDEX.md` | Deterministic rule dispatch and precedence | +| 5 | `05-non-negotiable-checklist.md` | Invariant SHALL gates | +| 10 | `10-session-bootstrap.md` | Startup checks and stop conditions | + +## Applicability matrix + +| Task signal | Required rule files | Optional rule files | +| --- | --- | --- | +| Any implementation request | `10-session-bootstrap.md`, `40-openspec-and-tdd.md`, `50-quality-gates-and-review.md` | `20-repository-context.md` | +| Code or docs changes on a branch | `30-worktrees-and-branching.md` | `80-current-guidance-catalog.md` | +| Public GitHub issue work | `60-github-change-governance.md` | `30-worktrees-and-branching.md` | +| Release or finalization work | `70-release-commit-and-docs.md`, `50-quality-gates-and-review.md` | `80-current-guidance-catalog.md` | +| Repo orientation or command lookup | `20-repository-context.md` | `80-current-guidance-catalog.md` | + +## Canonical rule files + +- [`05-non-negotiable-checklist.md`](./05-non-negotiable-checklist.md): always-load SHALL gates +- [`10-session-bootstrap.md`](./10-session-bootstrap.md): startup checks, compact context loading, and stop/continue behavior +- [`20-repository-context.md`](./20-repository-context.md): project overview, commands, architecture, and logging +- [`30-worktrees-and-branching.md`](./30-worktrees-and-branching.md): branch protection, worktree policy, and conflict avoidance +- [`40-openspec-and-tdd.md`](./40-openspec-and-tdd.md): OpenSpec selection, change validity, and strict TDD order +- [`50-quality-gates-and-review.md`](./50-quality-gates-and-review.md): required gates, code review JSON, clean-code enforcement, module signatures +- [`60-github-change-governance.md`](./60-github-change-governance.md): cache-first GitHub metadata, dependency completeness, and `in progress` ambiguity handling +- [`70-release-commit-and-docs.md`](./70-release-commit-and-docs.md): versioning, changelog, docs, README, and commit signing +- [`80-current-guidance-catalog.md`](./80-current-guidance-catalog.md): preserved migrated guidance not yet split into narrower documents + +## Preservation note + +The prior long `AGENTS.md` content has been preserved by reference in these rule files. The goal of this migration is to reduce startup token cost without silently dropping repository instructions. diff --git a/docs/contributing/frontmatter-schema.md b/docs/contributing/frontmatter-schema.md index a886161e..1ad6776c 100644 --- a/docs/contributing/frontmatter-schema.md +++ b/docs/contributing/frontmatter-schema.md @@ -31,6 +31,21 @@ This page is the **authoritative schema** for the ownership and tracking fields Runtime validation uses a Pydantic model (`DocFrontmatter` in `scripts/check_doc_frontmatter.py`): missing keys, wrong types, bad globs, unresolved `doc_owner`, and invalid exempt/reason pairs fail the check. +## Additional fields for `docs/agent-rules/` + +Files under `docs/agent-rules/` carry extra governance metadata on top of the standard doc-sync fields so bootstrap loaders can make deterministic decisions without reading every rule file in full. + +| Field | Type | Rules | +| --- | --- | --- | +| `id` | string | Stable rule identifier used by references and dependencies. | +| `always_load` | boolean | `true` when the rule must be loaded during every applicable bootstrap. | +| `applies_when` | list of strings | Non-empty task signals such as `session-bootstrap`, `implementation`, or `github-public-work`. | +| `priority` | integer | Non-negative ordering value used for deterministic rule loading. | +| `blocking` | boolean | Whether the rule can stop progress when its conditions are unmet. | +| `user_interaction_required` | boolean | Whether unmet conditions require user clarification before implementation continues. | +| `stop_conditions` | list of strings | Non-empty human-readable blocking conditions enforced by the rule. | +| `depends_on` | list of strings | Other rule ids that must load first. Empty list is allowed. | + ## Cross-repo notes - **Core vs modules:** Canonical user-facing docs for bundles and marketplace content live on [modules.specfact.io](https://modules.specfact.io/). Linking and URL rules are described in [Documentation URL contract](../reference/documentation-url-contract.md). diff --git a/openspec/CHANGE_ORDER.md b/openspec/CHANGE_ORDER.md index c164f229..3ab36b26 100644 --- a/openspec/CHANGE_ORDER.md +++ b/openspec/CHANGE_ORDER.md @@ -182,6 +182,7 @@ Cross-repo dependency: `docs-07-core-handoff-conversion` depends on `specfact-cl |--------|-------|---------------|----------|------------| | governance | 01 | cross-repo-issue-realignment | [#484](https://github.com/nold-ai/specfact-cli/issues/484) | agile-01 βœ…; module-migration-11 [#408](https://github.com/nold-ai/specfact-cli/issues/408); backlog-module-ownership-cleanup | | governance | 02 | governance-02-github-hierarchy-cache | [#491](https://github.com/nold-ai/specfact-cli/issues/491) | governance-01 [#484](https://github.com/nold-ai/specfact-cli/issues/484); Parent Feature: [#486](https://github.com/nold-ai/specfact-cli/issues/486) | +| governance | 03 | governance-03-deterministic-agent-governance-loading | TBD | governance-02 [#491](https://github.com/nold-ai/specfact-cli/issues/491) | ### Cross-cutting foundations (no hard dependencies β€” implement early) diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/TDD_EVIDENCE.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/TDD_EVIDENCE.md new file mode 100644 index 00000000..838ea65a --- /dev/null +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/TDD_EVIDENCE.md @@ -0,0 +1,39 @@ +# TDD Evidence + +## Failing-before evidence + +- Timestamp: `2026-04-10T22:22:22+02:00` +- Command: + +```bash +python3 -m pytest tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py tests/unit/docs/test_agent_rules_governance.py -q +``` + +- Result: failed as expected before implementation. +- Failure summary: + - `scripts/check_doc_frontmatter.py` did not expose `AgentRuleFrontmatter`. + - `docs/agent-rules/INDEX.md` and `docs/agent-rules/05-non-negotiable-checklist.md` did not exist yet. + - `AGENTS.md` did not yet reference the canonical rule docs. + - The doc frontmatter validator still accepted `docs/agent-rules/INDEX.md` without required governance fields such as `applies_when`. + +## Passing-after evidence + +- Timestamp: `2026-04-10T22:39:02+02:00` +- Commands: + +```bash +python3 -m pytest tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py tests/unit/docs/test_agent_rules_governance.py -q +python3 -m pytest tests/unit/scripts/test_doc_frontmatter/test_schema.py tests/unit/scripts/test_doc_frontmatter/test_validation.py tests/integration/scripts/test_doc_frontmatter/test_integration.py tests/unit/docs/test_docs_validation_scripts.py -q +python3 -m pytest tests/unit/specfact_cli/test_clean_code_principle_gates.py -q +hatch run format +hatch run yaml-lint +hatch run lint +hatch run contract-test +hatch run smart-test +openspec validate governance-03-deterministic-agent-governance-loading --strict +``` + +- Result: passing after implementation. +- Notes: + - `hatch run type-check` still reports the repository's existing warning baseline, so changed-file validation was verified separately with `basedpyright scripts/check_doc_frontmatter.py tests/helpers/doc_frontmatter_types.py tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py tests/unit/docs/test_agent_rules_governance.py`, which passed with `0 errors, 0 warnings, 0 notes`. + - `hatch run specfact code review run --json --out .specfact/code-review.json` is currently blocked in this worktree because the `nold-ai/specfact-codebase` module that provides the `specfact code review` command is not installed. The command fails immediately with a missing-module message rather than change-related findings. diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/design.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/design.md new file mode 100644 index 00000000..db675cad --- /dev/null +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/design.md @@ -0,0 +1,120 @@ +## Context + +The repository currently relies on a large `AGENTS.md` file to carry bootstrap rules, workflow gates, and long-form operational detail. That creates two problems: + +1. New sessions spend unnecessary context budget loading governance that is not always relevant. +2. Different AI models may compress or forget parts of the long document, causing inconsistent behavior around worktrees, change validation, cache refresh, TDD order, and finalization gates. + +The proposed rule system keeps `AGENTS.md` as the mandatory bootstrap surface, but reduces it to a small governance contract that points to a canonical `docs/agent-rules/INDEX.md` plus a mandatory non-negotiable checklist. Detailed rules move into focused Markdown artifacts with frontmatter so rule loading can be deterministic and selective. + +The deterministic bootstrap also needs to carry forward the GitHub issue-handling improvements already being introduced in repository governance: agents must not rely on stale plan text alone when linked change issues have live GitHub metadata that can invalidate readiness. Parent resolution, labels, project assignment, blockers, blocked-by links, and issue status must be handled as explicit governance checks rather than soft reminders. + +## Goals / Non-Goals + +**Goals:** +- Define a deterministic bootstrap path that every session follows before implementation work. +- Keep `AGENTS.md` small while preserving it as the mandatory governance layer. +- Introduce a frontmatter schema that makes rule applicability, priority, stop conditions, and user-interaction requirements machine-readable. +- Make rule loading selective so only relevant governance detail is loaded for a given task. +- Preserve existing hard gates such as worktree requirements, OpenSpec validation, cache-first GitHub lookup, TDD evidence, quality gates, and module signature enforcement. + +**Non-Goals:** +- Replacing OpenSpec lifecycle rules with a new workflow engine. +- Creating a generic policy engine for arbitrary repositories. +- Automatically resolving stale, ambiguous, or concurrent work situations without user input. +- Removing platform-specific alias files such as `CLAUDE.md` or `.github/copilot-instructions.md`. + +## Decisions + +### Decision: Keep `AGENTS.md` as a compact bootstrap contract + +`AGENTS.md` remains the first required instruction surface, but its role changes from comprehensive handbook to compact governance contract. It will: +- define the mandatory startup sequence +- point to the canonical rule index +- point to the always-load non-negotiable checklist +- define precedence for explicit user override versus repository governance + +This preserves compatibility with tools and models that already look for `AGENTS.md` while preventing governance sprawl inside that file. + +Alternative considered: +- Move everything to `docs/agent-rules/` and leave only a pointer in `AGENTS.md`. +- Rejected because many agents and IDE integrations are biased toward reading `AGENTS.md` first and may miss a too-thin pointer file. + +### Decision: Introduce a canonical rule index with deterministic loading semantics + +`docs/agent-rules/INDEX.md` becomes the dispatcher for governance rules. The index defines: +- the mandatory always-load rule set +- applicability signals for domain-specific files +- load order and precedence +- stop/continue semantics + +This keeps task routing deterministic instead of relying on the model to infer which long documents to read. + +Alternative considered: +- Let agents discover rule files heuristically by file names. +- Rejected because that is not deterministic across models and creates drift over time. + +### Decision: Use YAML frontmatter for every rule artifact + +Each `docs/agent-rules/*.md` file will include frontmatter fields such as: +- `id` +- `title` +- `always_load` +- `applies_when` +- `priority` +- `blocking` +- `user_interaction_required` +- `stop_conditions` +- `depends_on` + +This makes rule selection and enforcement durable across compacted sessions and across different AI models. + +Alternative considered: +- Encode the metadata inside Markdown prose only. +- Rejected because prose-only rule routing is easier to forget and harder to validate. + +### Decision: Make non-negotiable gates a standalone always-load artifact + +`docs/agent-rules/05-non-negotiable-checklist.md` will hold the invariant SHALL rules. It is always loaded after the index and before any domain-specific rules. This creates a small, stable enforcement nucleus that survives context compaction better than a large handbook. + +### Decision: Extend cache-first governance to session bootstrap + +The existing `github-hierarchy-cache` capability already requires cache-first guidance. This change extends it so the compact bootstrap path explicitly checks whether the local cache is missing or stale and refreshes it before governance work that depends on hierarchy metadata. + +### Decision: Make GitHub metadata completeness and issue-state ambiguity explicit readiness gates + +The compact governance system will treat GitHub issue metadata as part of deterministic implementation readiness for public work. Applicable rule files and the always-load checklist must explicitly require: +- parent resolution from cache-backed or refreshed GitHub reality +- labels and project assignment completeness +- blockers and blocked-by completeness +- a live issue-state check for `in progress` ambiguity + +If an issue is already marked `in progress`, the governance system must force a clarification stop before implementation continues. This keeps concurrent work from being silently duplicated across sessions. + +Alternative considered: +- Preserve these checks only as optional planning guidance in long-form prose. +- Rejected because those checks are exactly the kind of detail that gets dropped when contexts are compacted or when different models summarize instructions differently. + +## Risks / Trade-offs + +- [Rule sprawl moves from one file to many files] β†’ Mitigate with a strict index, a bounded always-load subset, and mandatory frontmatter validation. +- [Agents may read `AGENTS.md` but skip the index] β†’ Mitigate by making the bootstrap contract explicit and repetitive in the small `AGENTS.md`. +- [Applicability rules become ambiguous] β†’ Mitigate by defining exact task signals and precedence in the index. +- [Cross-model behavior still diverges if metadata is incomplete] β†’ Mitigate by requiring frontmatter fields and validation tests for every rule file. +- [Agents proceed from stale local change context while GitHub reality changed] β†’ Mitigate by making cache refresh, metadata completeness, and `in progress` state checks explicit blocking gates. +- [Documentation drift between `AGENTS.md`, rule files, and alias instructions] β†’ Mitigate by making alias surfaces reference canonical rule artifacts instead of embedding duplicated policy text. + +## Migration Plan + +1. Define the governance bootstrap contract and frontmatter schema in specs. +2. Replace the large `AGENTS.md` body with a compact bootstrap/governance layer. +3. Create `docs/agent-rules/INDEX.md`, `05-non-negotiable-checklist.md`, and the first domain rule files. +4. Update related alias or workflow instruction surfaces to reference the canonical rules rather than duplicating long guidance. +5. Add validation coverage for frontmatter schema, required always-load files, deterministic loading/precedence behavior, and GitHub readiness gates. +6. Verify the GitHub hierarchy cache guidance and issue-metadata readiness checks still work under the new bootstrap flow. + +## Open Questions + +- Whether rule-file validation should live in an existing docs/frontmatter validator or in a dedicated governance validator. +- Whether some high-frequency domain rules should also be always-load, or only index-selected. +- Whether platform-specific instruction generators should emit direct rule-file references or a stable alias that resolves through the same index. diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md new file mode 100644 index 00000000..723cbec5 --- /dev/null +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md @@ -0,0 +1,27 @@ +## Why + +`AGENTS.md` has become a heavy mixed-purpose instruction surface that front-loads too much repository policy into every new session. That increases token cost, makes cross-model behavior less deterministic, and raises the risk that important workflow gates are forgotten once context is compacted. + +## What Changes + +- Introduce a deterministic agent-governance rule system with a small bootstrap `AGENTS.md`, a canonical rule index, and focused rule artifacts loaded by applicability. +- Define a machine-readable frontmatter contract for governance rule files so multiple AI models can follow the same loading and stop-condition semantics. +- Require an always-load non-negotiable checklist plus explicit precedence and stop/continue behavior for worktree, change validation, TDD, verification, and finalization gates. +- Make GitHub governance completeness explicit in the deterministic readiness flow, including parent resolution, labels, project assignment, blockers / blocked-by relationships, and live issue-state ambiguity checks. +- Tighten cache-first bootstrap guidance so session startup refreshes the local GitHub hierarchy cache when it is missing or stale. +- Move long-form governance detail out of `AGENTS.md` into dedicated markdown artifacts while preserving `AGENTS.md` as the mandatory small governance layer. + +## Capabilities + +### New Capabilities +- `agent-governance-loading`: Deterministic bootstrap, rule discovery, rule frontmatter, precedence, and stop-condition behavior for AI instruction surfaces. + +### Modified Capabilities +- `github-hierarchy-cache`: Require cache freshness checks as part of the compact governance bootstrap flow. + +## Impact + +- Affected governance docs and instruction surfaces: `AGENTS.md`, new `docs/agent-rules/` artifacts, and possibly other lightweight instruction aliases that must reference the canonical rule system. +- Affected OpenSpec/runtime guidance: `openspec/config.yaml`, `openspec/CHANGE_ORDER.md`, and related workflow guidance for agents. +- Affected GitHub workflow guidance: cache-backed parent lookup, metadata completeness checks, and concurrency-ambiguity handling for linked change issues. +- Affected validation scope: documentation consistency, frontmatter schema enforcement, and deterministic session-bootstrap behavior across AI models. diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md new file mode 100644 index 00000000..81a7f24f --- /dev/null +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md @@ -0,0 +1,94 @@ +## ADDED Requirements + +### Requirement: Compact AGENTS bootstrap contract +The repository SHALL keep `AGENTS.md` as the mandatory bootstrap governance surface, but it SHALL remain compact and SHALL delegate long-form operational detail to canonical rule artifacts. + +#### Scenario: Session bootstrap reads compact governance contract +- **WHEN** an agent starts work in the repository +- **THEN** it reads `AGENTS.md` first +- **AND** `AGENTS.md` defines a mandatory bootstrap sequence rather than embedding the full long-form governance corpus +- **AND** the bootstrap sequence requires loading `docs/agent-rules/INDEX.md` +- **AND** the bootstrap sequence requires loading the canonical non-negotiable checklist before code implementation work + +#### Scenario: AGENTS stays compact while preserving enforcement +- **WHEN** repository governance is updated +- **THEN** `AGENTS.md` SHALL retain only the bootstrap contract, invariant governance rules, and canonical references needed for startup +- **AND** detailed workflow, validation, or finalization guidance SHALL live in dedicated rule artifacts rather than being duplicated inline + +### Requirement: Deterministic rule index and loading semantics +The repository SHALL provide a canonical rule index that deterministically decides which governance rule files must be loaded for a given task. + +#### Scenario: Always-load rule subset +- **WHEN** an agent loads the governance rule index +- **THEN** the index SHALL identify a mandatory always-load subset +- **AND** that subset SHALL include the non-negotiable checklist +- **AND** the index SHALL define the order in which always-load rules are processed + +#### Scenario: Applicability-based rule loading +- **WHEN** a task involves worktree management, OpenSpec change selection, GitHub issue coordination, TDD gating, quality verification, or finalization +- **THEN** the index SHALL map those task signals to specific `docs/agent-rules/*.md` files +- **AND** the index SHALL define which rule files are required versus optional for that task class +- **AND** the loading decision SHALL not depend on heuristic file-name guessing alone + +#### Scenario: Deterministic precedence +- **WHEN** governance instructions overlap across `AGENTS.md`, the rule index, rule files, and change-local artifacts +- **THEN** the repository SHALL define a single precedence order for which instruction wins +- **AND** the precedence order SHALL include explicit handling for direct user override where repository governance permits it + +### Requirement: Governance rule files use machine-readable frontmatter +Every dedicated governance rule artifact SHALL include machine-readable frontmatter that defines how and when the rule applies. + +#### Scenario: Required frontmatter fields are present +- **WHEN** a file under `docs/agent-rules/` is intended to govern agent behavior +- **THEN** it SHALL include frontmatter fields for rule identity, applicability, priority, blocking semantics, and stop conditions +- **AND** it SHALL declare whether the file is always loaded +- **AND** it SHALL declare whether user interaction is required when the rule blocks progress + +#### Scenario: Frontmatter drives deterministic behavior +- **WHEN** an agent evaluates a rule file with frontmatter +- **THEN** it can determine from metadata whether the rule is mandatory for the current task +- **AND** it can determine whether the rule requires a hard stop, read-only continuation, or interactive clarification +- **AND** it does not need to infer those semantics solely from unstructured prose + +### Requirement: Governance must define explicit stop and continue behavior +The governance system SHALL define explicit blocking behavior for stale changes, concurrency ambiguity, missing metadata, and TDD gate violations. + +#### Scenario: Blocking ambiguity requires user clarification +- **WHEN** a selected change is stale, superseded, ambiguous, or linked to GitHub work already in progress +- **THEN** the applicable rule SHALL require the agent to stop implementation work +- **AND** the rule SHALL state that the ambiguity must be surfaced to the user for clarification +- **AND** the rule SHALL define whether read-only investigation may continue while implementation remains blocked + +#### Scenario: TDD gate remains non-bypassable in compact governance +- **WHEN** a task changes behavior in code +- **THEN** the applicable rule SHALL still require spec updates, test creation, failing-test evidence, implementation, and passing evidence in that order +- **AND** compact governance SHALL not weaken or omit that sequence + +### Requirement: Public GitHub work must pass metadata completeness checks +The governance system SHALL define explicit readiness checks for linked GitHub change issues before implementation proceeds for public repository work. + +#### Scenario: Parent and dependency metadata must be complete +- **WHEN** an agent prepares to implement a publicly tracked change with a linked GitHub issue +- **THEN** the applicable governance rules SHALL require verifying the issue's parent relationship, blockers, and blocked-by relationships against current repository GitHub reality +- **AND** the parent lookup SHALL use the local hierarchy cache first and refresh the cache when repository-defined freshness rules require it +- **AND** implementation SHALL not proceed if the required parent or dependency metadata is missing or ambiguous + +#### Scenario: Labels and project assignment must be complete +- **WHEN** an agent prepares to implement a publicly tracked change with a linked GitHub issue +- **THEN** the applicable governance rules SHALL require verifying that the issue has the required labels and project assignment for repository workflow completeness +- **AND** implementation SHALL not proceed until that metadata is complete or the user explicitly directs an allowed exception path + +#### Scenario: Live GitHub issue state can block implementation +- **WHEN** an agent prepares to implement a publicly tracked change with a linked GitHub issue +- **AND** the issue is already marked `in progress` +- **THEN** the governance rules SHALL treat that state as a concurrency ambiguity +- **AND** the agent SHALL stop implementation work and ask the user to clarify whether the change is already being worked in another session +- **AND** the rules SHALL define whether only read-only investigation may continue while implementation remains blocked + +### Requirement: Canonical aliases prevent instruction drift +Repository instruction surfaces other than `AGENTS.md` SHALL reference the canonical governance rule system instead of embedding duplicate long-form policy text. + +#### Scenario: Alias instruction surfaces stay synchronized +- **WHEN** a contributor reads another repository instruction surface such as `CLAUDE.md` or generated IDE guidance +- **THEN** the surface SHALL reference the canonical rule system for governance semantics +- **AND** it SHALL avoid copying long-form governance content that could drift from the canonical source diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/github-hierarchy-cache/spec.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/github-hierarchy-cache/spec.md new file mode 100644 index 00000000..1e440ad5 --- /dev/null +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/github-hierarchy-cache/spec.md @@ -0,0 +1,19 @@ +## MODIFIED Requirements + +### Requirement: Repository governance must use cache-first hierarchy lookup + +Repository governance instructions SHALL direct contributors and agents to consult the local hierarchy cache before performing manual GitHub lookups for Epic or Feature parenting. + +#### Scenario: Cache-first governance guidance + +- **WHEN** a contributor reads `AGENTS.md` or `openspec/config.yaml` for GitHub issue setup guidance +- **THEN** the instructions tell them to consult the local hierarchy cache first +- **AND** the instructions define when the sync script must be rerun to refresh stale hierarchy metadata +- **AND** the instructions state that the cache is local ephemeral state and must not be committed + +#### Scenario: Session bootstrap refreshes missing or stale cache + +- **WHEN** an agent starts a governance-sensitive session that depends on GitHub hierarchy metadata +- **AND** the local hierarchy cache is missing or stale according to repository-defined freshness rules +- **THEN** the bootstrap guidance SHALL require rerunning the hierarchy cache sync script before continuing with issue-parenting or blocker-resolution work +- **AND** the compact governance flow SHALL treat the refresh as part of deterministic startup rather than an optional later reminder diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md new file mode 100644 index 00000000..c4101ac1 --- /dev/null +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md @@ -0,0 +1,36 @@ +# Tasks: governance-03-deterministic-agent-governance-loading + +## 1. Branch and governance preparation + +- [x] 1.1 Create dedicated worktree branch `feature/governance-03-deterministic-agent-governance-loading` from `dev` before implementation work: `scripts/worktree.sh create feature/governance-03-deterministic-agent-governance-loading`. +- [x] 1.2 Confirm governance-01 and governance-02 outputs remain the dependency baseline for this change and update `openspec/CHANGE_ORDER.md` metadata if sequencing notes need adjustment. +- [x] 1.3 Review current `AGENTS.md`, related instruction surfaces, and existing docs/frontmatter validators to identify the files that must participate in the compact-governance migration. + +## 2. Spec-first and test-first preparation + +- [x] 2.1 Finalize the `agent-governance-loading` and `github-hierarchy-cache` spec deltas and cross-check scenario completeness. +- [x] 2.2 Add or update tests/validators that cover rule-file frontmatter, deterministic always-load behavior, precedence handling, cache-refresh bootstrap rules, and GitHub metadata completeness / `in progress` ambiguity handling. +- [x] 2.3 Run targeted tests to capture failing-first behavior and record the results in `TDD_EVIDENCE.md` before production edits. + +## 3. Governance implementation + +- [x] 3.1 Replace the long-form `AGENTS.md` body with a compact bootstrap/governance contract that points to canonical rule artifacts. +- [x] 3.2 Create `docs/agent-rules/INDEX.md`, `docs/agent-rules/05-non-negotiable-checklist.md`, and the first domain rule files needed to cover bootstrap, change validation, TDD, quality gates, docs/versioning, and finalization. +- [x] 3.3 Implement or extend validation so governance rule files enforce the required frontmatter schema and deterministic metadata fields. +- [x] 3.4 Update related instruction surfaces and workflow guidance so they reference the canonical governance rule system instead of duplicating long-form policy text. +- [x] 3.5 Update cache-first governance guidance so session bootstrap refreshes `.specfact/backlog/github_hierarchy_cache.md` when it is missing or stale. +- [x] 3.6 Implement or extend governance logic and docs so public-work readiness checks cover parent resolution, labels, project assignment, blockers / blocked-by relationships, and `in progress` issue-state clarification. + +## 4. Validation and documentation + +- [x] 4.1 Re-run targeted and required quality gates until the compact-governance behavior and docs validation pass. +- [ ] 4.2 Run `hatch run specfact code review run --json --out .specfact/code-review.json` and resolve all findings, including warnings. +Blocked in the current worktree environment because the `nold-ai/specfact-codebase` module that provides `specfact code review` is not installed. +- [x] 4.3 Update user-facing documentation and navigation for the new governance artifact layout and explain how `AGENTS.md` now delegates to canonical rule files. +- [x] 4.4 Run `openspec validate governance-03-deterministic-agent-governance-loading --strict` and resolve all issues. + +## 5. Delivery + +- [x] 5.1 Refresh `TDD_EVIDENCE.md` with passing-after commands and timestamps. +- [x] 5.2 Update `openspec/CHANGE_ORDER.md` implementation status or dependency notes if anything changed during delivery. +- [ ] 5.3 Open a PR from `feature/governance-03-deterministic-agent-governance-loading` to `dev` with spec/test/code/docs/code-review evidence. diff --git a/scripts/check_doc_frontmatter.py b/scripts/check_doc_frontmatter.py index 98174eae..33c1c10e 100755 --- a/scripts/check_doc_frontmatter.py +++ b/scripts/check_doc_frontmatter.py @@ -11,7 +11,7 @@ import subprocess import sys from pathlib import Path -from typing import Any +from typing import Any, cast import typer import yaml @@ -33,6 +33,7 @@ TRACKED_DOC_DIRS = ("docs",) REQUIRED_ROOT_DOCS: tuple[str, ...] = ("USAGE-FAQ.md",) +AGENT_RULES_DIR = "docs/agent-rules/" EXEMPT_FILES = frozenset( { "docs/LICENSE.md", @@ -49,6 +50,18 @@ _OWNER_GLOB_METACHARS = frozenset("*?[]{}") REQUIRED_KEYS = ("title", "doc_owner", "tracks", "last_reviewed", "exempt", "exempt_reason") +AGENT_RULE_REQUIRED_KEYS = ( + *REQUIRED_KEYS, + "id", + "always_load", + "applies_when", + "priority", + "blocking", + "user_interaction_required", + "stop_conditions", + "depends_on", +) +RULE_ID_RE = re.compile(r"^[a-z0-9][a-z0-9-]*$") class DocFrontmatter(BaseModel): @@ -122,6 +135,51 @@ def _owner_and_exempt_rules(self) -> DocFrontmatter: DocFrontmatter.model_rebuild(_types_namespace={"datetime": datetime}) +class AgentRuleFrontmatter(DocFrontmatter): + """Validated frontmatter for deterministic governance rule documents.""" + + id: str = Field(..., description="Stable rule identifier") + always_load: bool = Field(..., description="Whether the rule must load for every applicable bootstrap") + applies_when: list[str] = Field(..., min_length=1, description="Task signals that require this rule") + priority: int = Field(..., ge=0, description="Deterministic loading order") + blocking: bool = Field(..., description="Whether the rule can block progress") + user_interaction_required: bool = Field(..., description="Whether the rule requires user clarification") + stop_conditions: list[str] = Field(..., min_length=1, description="Blocking conditions for the rule") + depends_on: list[str] = Field(..., description="Other rule ids that must load first") + + @field_validator("id", mode="before") + @classmethod + def _normalize_rule_id(cls, value: object) -> str: + if not isinstance(value, str): + raise ValueError("`id` must be a string") + rule_id = value.strip() + if not RULE_ID_RE.match(rule_id): + raise ValueError("`id` must be kebab-case") + return rule_id + + @field_validator("applies_when", "stop_conditions", "depends_on", mode="before") + @classmethod + def _string_list_fields(cls, value: object, info: ValidationInfo) -> list[str]: + if not isinstance(value, list) or not all(isinstance(x, str) for x in value): + raise ValueError(f"`{info.field_name}` must be a list of strings") + string_values = cast(list[str], value) + normalized = [x.strip() for x in string_values] + if info.field_name != "depends_on" and any(not x for x in normalized): + raise ValueError(f"`{info.field_name}` entries must be non-empty") + if info.field_name == "depends_on": + return [x for x in normalized if x] + return normalized + + @model_validator(mode="after") + def _always_load_requires_bootstrap_signal(self) -> AgentRuleFrontmatter: + if self.always_load and not {"session-bootstrap", "implementation", "all"} & set(self.applies_when): + raise ValueError("always-load rules must apply to bootstrap, implementation, or all tasks") + return self + + +AgentRuleFrontmatter.model_rebuild(_types_namespace={"datetime": datetime}) + + def _format_doc_frontmatter_errors(exc: ValidationError) -> list[str]: """Turn Pydantic errors into the same style as legacy manual validation.""" out: list[str] = [] @@ -301,6 +359,28 @@ def validate_glob_patterns(patterns: list[str]) -> bool: @ensure(lambda result: isinstance(result, str), "Must return string") def suggest_frontmatter(path: Path) -> str: """Return a suggested frontmatter block for a document.""" + if _rel_posix(path).startswith(AGENT_RULES_DIR): + return f"""--- +title: "{path.stem.replace("-", " ").title()}" +id: {path.stem.lower()} +doc_owner: specfact-cli +tracks: + - AGENTS.md + - docs/agent-rules/** +last_reviewed: {datetime.date.today().isoformat()} +exempt: false +exempt_reason: "" +always_load: false +applies_when: + - detailed-reference +priority: 50 +blocking: false +user_interaction_required: false +stop_conditions: + - none +depends_on: [] +--- +""" return f"""--- title: "{path.stem}" doc_owner: specfact-cli @@ -438,6 +518,23 @@ def _validate_record(fm: dict[str, Any]) -> list[str]: return [] +def _is_agent_rule_doc(path: Path) -> bool: + return _rel_posix(path).startswith(AGENT_RULES_DIR) + + +def _validate_record_for_path(path: Path, fm: dict[str, Any]) -> list[str]: + required_keys = AGENT_RULE_REQUIRED_KEYS if _is_agent_rule_doc(path) else REQUIRED_KEYS + missing = [f"missing `{key}`" for key in required_keys if key not in fm] + if missing: + return missing + model = AgentRuleFrontmatter if _is_agent_rule_doc(path) else DocFrontmatter + try: + model.model_validate(fm) + except ValidationError as exc: + return _format_doc_frontmatter_errors(exc) + return [] + + def _discover_paths_to_check(all_docs: bool) -> list[Path] | None: """Return files to validate, or None when the run should exit 0 early (skip).""" if all_docs: @@ -476,7 +573,7 @@ def _collect_failures( except (OSError, yaml.YAMLError) as exc: failures.append(f" βœ— YAML parse error: {rel}: {exc}") continue - errs = _validate_record(fm) + errs = _validate_record_for_path(file_path, fm) if errs: msg = f" βœ— INVALID frontmatter: {rel}\n - " + "\n - ".join(errs) if fix_hint: diff --git a/tests/helpers/doc_frontmatter_types.py b/tests/helpers/doc_frontmatter_types.py index 310eadff..c189a0c0 100644 --- a/tests/helpers/doc_frontmatter_types.py +++ b/tests/helpers/doc_frontmatter_types.py @@ -24,6 +24,7 @@ class CheckDocFrontmatterModule(Protocol): """Structural type for ``scripts/check_doc_frontmatter.py`` loaded via importlib.""" DocFrontmatter: type[DocFrontmatterModel] + AgentRuleFrontmatter: type[AgentRuleFrontmatterModel] parse_frontmatter: Callable[[Path], dict[str, Any]] resolve_owner: Callable[[str], bool] validate_glob_patterns: Callable[[list[str]], bool] @@ -53,3 +54,22 @@ class DocFrontmatterModel(Protocol): @classmethod def model_validate(cls, data: dict[str, object]) -> DocFrontmatterRecord: raise NotImplementedError + + +@runtime_checkable +class AgentRuleFrontmatterRecord(DocFrontmatterRecord, Protocol): + """Validated agent-rule record shape used by tests.""" + + id: str + always_load: bool + applies_when: list[str] + priority: int + + +@runtime_checkable +class AgentRuleFrontmatterModel(Protocol): + """Model type exposing ``model_validate`` for agent-rule docs.""" + + @classmethod + def model_validate(cls, data: dict[str, object]) -> AgentRuleFrontmatterRecord: + raise NotImplementedError diff --git a/tests/unit/docs/test_agent_rules_governance.py b/tests/unit/docs/test_agent_rules_governance.py new file mode 100644 index 00000000..c7a22c0f --- /dev/null +++ b/tests/unit/docs/test_agent_rules_governance.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +from pathlib import Path + +import yaml + + +REPO_ROOT = Path(__file__).resolve().parents[3] + + +def _read_frontmatter(path: Path) -> dict[str, object]: + text = path.read_text(encoding="utf-8") + assert text.startswith("---\n") + _, body = text.split("---\n", 1) + frontmatter, _ = body.split("\n---\n", 1) + loaded = yaml.safe_load(frontmatter) + assert isinstance(loaded, dict) + return loaded + + +def test_agent_rules_index_and_checklist_exist() -> None: + index_path = REPO_ROOT / "docs" / "agent-rules" / "INDEX.md" + checklist_path = REPO_ROOT / "docs" / "agent-rules" / "05-non-negotiable-checklist.md" + + assert index_path.exists() + assert checklist_path.exists() + + +def test_agent_rules_index_has_deterministic_bootstrap_metadata() -> None: + frontmatter = _read_frontmatter(REPO_ROOT / "docs" / "agent-rules" / "INDEX.md") + applies_when = frontmatter["applies_when"] + assert isinstance(applies_when, list) + + assert frontmatter["id"] == "agent-rules-index" + assert frontmatter["always_load"] is True + assert "session-bootstrap" in applies_when + assert frontmatter["priority"] == 0 + + +def test_non_negotiable_checklist_is_always_loaded() -> None: + frontmatter = _read_frontmatter(REPO_ROOT / "docs" / "agent-rules" / "05-non-negotiable-checklist.md") + depends_on = frontmatter["depends_on"] + assert isinstance(depends_on, list) + + assert frontmatter["id"] == "agent-rules-non-negotiable-checklist" + assert frontmatter["always_load"] is True + assert "agent-rules-index" in depends_on + + +def test_agents_references_canonical_rule_docs() -> None: + agents_text = (REPO_ROOT / "AGENTS.md").read_text(encoding="utf-8") + + assert "docs/agent-rules/INDEX.md" in agents_text + assert "docs/agent-rules/05-non-negotiable-checklist.md" in agents_text diff --git a/tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py b/tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py new file mode 100644 index 00000000..70679fdc --- /dev/null +++ b/tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 +"""Tests for agent-rule frontmatter validation.""" + +from __future__ import annotations + +import tempfile +from pathlib import Path + +import pytest + +from tests.helpers.doc_frontmatter import write_enforced +from tests.helpers.doc_frontmatter_types import CheckDocFrontmatterModule + + +VALID_AGENT_RULE_FRONTMATTER = """--- +title: "Agent Rules Index" +id: agent-rules-index +doc_owner: specfact-cli +tracks: + - AGENTS.md + - docs/agent-rules/** +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +always_load: true +applies_when: + - session-bootstrap +priority: 0 +blocking: true +user_interaction_required: false +stop_conditions: + - canonical rule index missing +depends_on: [] +--- + +# Agent Rules Index +""" + + +class TestAgentRuleFrontmatterModel: + """Pydantic model for deterministic agent-rule frontmatter.""" + + def test_model_validate_accepts_valid_rule_dict( + self, check_doc_frontmatter_module: CheckDocFrontmatterModule + ) -> None: + agent_rule_model = check_doc_frontmatter_module.AgentRuleFrontmatter + data = { + "title": "Agent Rules Index", + "id": "agent-rules-index", + "doc_owner": "specfact-cli", + "tracks": ["AGENTS.md", "docs/agent-rules/**"], + "last_reviewed": "2026-04-10", + "exempt": False, + "exempt_reason": "", + "always_load": True, + "applies_when": ["session-bootstrap"], + "priority": 0, + "blocking": True, + "user_interaction_required": False, + "stop_conditions": ["canonical rule index missing"], + "depends_on": [], + } + + rec = agent_rule_model.model_validate(data) + assert rec.id == "agent-rules-index" + assert rec.always_load is True + assert rec.priority == 0 + assert rec.applies_when == ["session-bootstrap"] + + +class TestAgentRuleFrontmatterValidation: + """Integration-style validation of docs/agent-rules files.""" + + def test_validation_accepts_valid_agent_rule_file( + self, monkeypatch: pytest.MonkeyPatch, check_doc_frontmatter_module: CheckDocFrontmatterModule + ) -> None: + validation_main = check_doc_frontmatter_module.main + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir) + monkeypatch.setenv("DOC_FRONTMATTER_ROOT", str(root)) + rules_dir = root / "docs" / "agent-rules" + rules_dir.mkdir(parents=True) + (rules_dir / "INDEX.md").write_text(VALID_AGENT_RULE_FRONTMATTER, encoding="utf-8") + write_enforced(root, "docs/agent-rules/INDEX.md") + + result = validation_main([]) + assert result == 0 + + def test_validation_rejects_missing_agent_rule_fields( + self, + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], + check_doc_frontmatter_module: CheckDocFrontmatterModule, + ) -> None: + validation_main = check_doc_frontmatter_module.main + with tempfile.TemporaryDirectory() as temp_dir: + root = Path(temp_dir) + monkeypatch.setenv("DOC_FRONTMATTER_ROOT", str(root)) + rules_dir = root / "docs" / "agent-rules" + rules_dir.mkdir(parents=True) + (rules_dir / "INDEX.md").write_text( + """--- +title: "Agent Rules Index" +id: agent-rules-index +doc_owner: specfact-cli +tracks: + - AGENTS.md +last_reviewed: 2026-04-10 +exempt: false +exempt_reason: "" +always_load: true +priority: 0 +blocking: true +user_interaction_required: false +stop_conditions: + - canonical rule index missing +depends_on: [] +--- + +# Agent Rules Index +""", + encoding="utf-8", + ) + write_enforced(root, "docs/agent-rules/INDEX.md") + + result = validation_main([]) + assert result == 1 + err = capsys.readouterr().err + assert "docs/agent-rules/INDEX.md" in err + assert "applies_when" in err From b46e6b64ea5c0a7b16a8c3a24dd1451b492f35b8 Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Fri, 10 Apr 2026 22:44:21 +0200 Subject: [PATCH 2/6] docs: mark governance PR task complete --- .../tasks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md index c4101ac1..a0f48494 100644 --- a/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md @@ -33,4 +33,4 @@ Blocked in the current worktree environment because the `nold-ai/specfact-codeba - [x] 5.1 Refresh `TDD_EVIDENCE.md` with passing-after commands and timestamps. - [x] 5.2 Update `openspec/CHANGE_ORDER.md` implementation status or dependency notes if anything changed during delivery. -- [ ] 5.3 Open a PR from `feature/governance-03-deterministic-agent-governance-loading` to `dev` with spec/test/code/docs/code-review evidence. +- [x] 5.3 Open a PR from `feature/governance-03-deterministic-agent-governance-loading` to `dev` with spec/test/code/docs/code-review evidence. From 2f16df0b20f4cf483b3c8703693b5458bff2b845 Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Fri, 10 Apr 2026 22:52:26 +0200 Subject: [PATCH 3/6] docs: sync governance-03 github issue metadata --- openspec/CHANGE_ORDER.md | 2 +- .../proposal.md | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openspec/CHANGE_ORDER.md b/openspec/CHANGE_ORDER.md index 3ab36b26..012acb32 100644 --- a/openspec/CHANGE_ORDER.md +++ b/openspec/CHANGE_ORDER.md @@ -182,7 +182,7 @@ Cross-repo dependency: `docs-07-core-handoff-conversion` depends on `specfact-cl |--------|-------|---------------|----------|------------| | governance | 01 | cross-repo-issue-realignment | [#484](https://github.com/nold-ai/specfact-cli/issues/484) | agile-01 βœ…; module-migration-11 [#408](https://github.com/nold-ai/specfact-cli/issues/408); backlog-module-ownership-cleanup | | governance | 02 | governance-02-github-hierarchy-cache | [#491](https://github.com/nold-ai/specfact-cli/issues/491) | governance-01 [#484](https://github.com/nold-ai/specfact-cli/issues/484); Parent Feature: [#486](https://github.com/nold-ai/specfact-cli/issues/486) | -| governance | 03 | governance-03-deterministic-agent-governance-loading | TBD | governance-02 [#491](https://github.com/nold-ai/specfact-cli/issues/491) | +| governance | 03 | governance-03-deterministic-agent-governance-loading | [#494](https://github.com/nold-ai/specfact-cli/issues/494) | governance-02 [#491](https://github.com/nold-ai/specfact-cli/issues/491); Parent Feature: [#486](https://github.com/nold-ai/specfact-cli/issues/486) | ### Cross-cutting foundations (no hard dependencies β€” implement early) diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md index 723cbec5..739a23a4 100644 --- a/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md @@ -25,3 +25,9 @@ - Affected OpenSpec/runtime guidance: `openspec/config.yaml`, `openspec/CHANGE_ORDER.md`, and related workflow guidance for agents. - Affected GitHub workflow guidance: cache-backed parent lookup, metadata completeness checks, and concurrency-ambiguity handling for linked change issues. - Affected validation scope: documentation consistency, frontmatter schema enforcement, and deterministic session-bootstrap behavior across AI models. + +## Tracking + +- GitHub Issue: [#494](https://github.com/nold-ai/specfact-cli/issues/494) +- Parent Feature: [#486](https://github.com/nold-ai/specfact-cli/issues/486) +- Blocked by: [#491](https://github.com/nold-ai/specfact-cli/issues/491) From f635ea29a8b0ef70ccabe04cfcc3df83d689a9ca Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Fri, 10 Apr 2026 23:06:35 +0200 Subject: [PATCH 4/6] fix: restore dev branch governance block --- docs/agent-rules/05-non-negotiable-checklist.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/agent-rules/05-non-negotiable-checklist.md b/docs/agent-rules/05-non-negotiable-checklist.md index 7716dd78..75a9b3fa 100644 --- a/docs/agent-rules/05-non-negotiable-checklist.md +++ b/docs/agent-rules/05-non-negotiable-checklist.md @@ -35,7 +35,7 @@ depends_on: # Agent non-negotiable checklist - SHALL work in a git worktree unless the user explicitly overrides that rule. -- SHALL not implement from the main checkout by default. +- SHALL not implement from the `dev` or `main` checkout by default. - SHALL treat a provided OpenSpec change id as candidate scope, not automatic permission to proceed. - SHALL verify selected change validity against current repository reality and dependency state before implementation. - SHALL not auto-refine stale, superseded, or ambiguous changes without the user. From 48b2d7aec6a4bf63db49fd2eea879042dcde35dc Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Fri, 10 Apr 2026 23:24:53 +0200 Subject: [PATCH 5/6] Apply review findings --- AGENTS.md | 1 + docs/agent-rules/10-session-bootstrap.md | 2 +- docs/agent-rules/20-repository-context.md | 2 +- .../agent-rules/30-worktrees-and-branching.md | 2 +- .../80-current-guidance-catalog.md | 2 +- docs/agent-rules/INDEX.md | 9 +- docs/contributing/frontmatter-schema.md | 6 +- .../proposal.md | 6 +- .../specs/agent-governance-loading/spec.md | 19 ++++ .../tasks.md | 9 +- scripts/check_doc_frontmatter.py | 86 ++++++++++++++++--- tests/helpers/doc_frontmatter_types.py | 10 ++- .../unit/docs/test_agent_rules_governance.py | 30 +++---- .../test_agent_rule_frontmatter.py | 2 +- 14 files changed, 141 insertions(+), 45 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 31c1ca70..cc048988 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -39,6 +39,7 @@ This file is the mandatory bootstrap governance surface for coding agents workin ## Canonical rule docs - [docs/agent-rules/INDEX.md](docs/agent-rules/INDEX.md) +- [docs/agent-rules/05-non-negotiable-checklist.md](docs/agent-rules/05-non-negotiable-checklist.md) - [docs/agent-rules/10-session-bootstrap.md](docs/agent-rules/10-session-bootstrap.md) - [docs/agent-rules/20-repository-context.md](docs/agent-rules/20-repository-context.md) - [docs/agent-rules/30-worktrees-and-branching.md](docs/agent-rules/30-worktrees-and-branching.md) diff --git a/docs/agent-rules/10-session-bootstrap.md b/docs/agent-rules/10-session-bootstrap.md index dc34601e..19b0bc5d 100644 --- a/docs/agent-rules/10-session-bootstrap.md +++ b/docs/agent-rules/10-session-bootstrap.md @@ -36,7 +36,7 @@ depends_on: 1. Detect repository root, active branch, and whether the session is running in a worktree. 2. If the session is on `dev` or `main`, do not implement until the user explicitly allows it or a worktree is created. -3. Read `AGENTS.md`, then load the rule index and non-negotiable checklist. +3. Confirm `AGENTS.md` is already loaded, then load the rule index and non-negotiable checklist. 4. Determine whether the task is read-only, artifact-only, or implementation work. 5. If GitHub hierarchy data is required, confirm `.specfact/backlog/github_hierarchy_cache.md` is present and fresh enough for the task. 6. If the cache is missing or stale, refresh it with `python scripts/sync_github_hierarchy_cache.py`. diff --git a/docs/agent-rules/20-repository-context.md b/docs/agent-rules/20-repository-context.md index fc276a32..ee8f5a7d 100644 --- a/docs/agent-rules/20-repository-context.md +++ b/docs/agent-rules/20-repository-context.md @@ -33,7 +33,7 @@ depends_on: ## Project overview -SpecFact CLI is a Python CLI tool for agile DevOps teams. It keeps backlogs, specs, tests, and code in sync with contract-driven development, validation, and enforcement. It is built with Typer and Rich, uses Hatch as the build system, and targets Python 3.11+. +SpecFact CLI is a Python CLI tool for agile DevOps teams. It keeps backlogs, specs, tests, and code in sync with contract-driven development, validation, and enforcement. It is built with Typer and Rich, uses Hatch as the build system, and targets Python 3.12 (supports Python 3.11+ at runtime). ## Essential commands diff --git a/docs/agent-rules/30-worktrees-and-branching.md b/docs/agent-rules/30-worktrees-and-branching.md index b746acdb..580bf520 100644 --- a/docs/agent-rules/30-worktrees-and-branching.md +++ b/docs/agent-rules/30-worktrees-and-branching.md @@ -40,7 +40,7 @@ depends_on: ## Worktree policy - The primary checkout remains the canonical `dev` workspace. -- Use `scripts/worktree.sh create feature/` to create implementation worktrees. +- Use `scripts/worktree.sh create /` to create implementation worktrees (`feature`, `bugfix`, `hotfix`, or `chore` for ``). - Never create a worktree for `dev` or `main`. - One branch maps to one worktree path at a time. - Keep one active OpenSpec change scope per branch where possible. diff --git a/docs/agent-rules/80-current-guidance-catalog.md b/docs/agent-rules/80-current-guidance-catalog.md index 3f497a22..f1a5c5d5 100644 --- a/docs/agent-rules/80-current-guidance-catalog.md +++ b/docs/agent-rules/80-current-guidance-catalog.md @@ -39,7 +39,7 @@ Bundle code in **specfact-cli-modules** imports from `specfact_cli`. For local I ## Code conventions -- Python 3.11+, line length 120, Google-style docstrings +- Python 3.12 target (3.11+ runtime), line length 120, Google-style docstrings - `snake_case` for files, modules, and functions - `PascalCase` for classes - `UPPER_SNAKE_CASE` for constants diff --git a/docs/agent-rules/INDEX.md b/docs/agent-rules/INDEX.md index dd4f892c..455d5c7b 100644 --- a/docs/agent-rules/INDEX.md +++ b/docs/agent-rules/INDEX.md @@ -38,10 +38,11 @@ This page is the canonical loader for repository governance instructions. `AGENT 1. Read `AGENTS.md`. 2. Load this index. 3. Load [`05-non-negotiable-checklist.md`](./05-non-negotiable-checklist.md). -4. Detect repository, branch, and worktree state. -5. Reject implementation from the `dev` or `main` checkout unless the user explicitly overrides that rule. -6. If GitHub hierarchy metadata is needed and `.specfact/backlog/github_hierarchy_cache.md` is missing or stale, refresh it with `python scripts/sync_github_hierarchy_cache.py`. -7. Load additional rule files from the applicability matrix below before implementation. +4. Load [`10-session-bootstrap.md`](./10-session-bootstrap.md) (always-load; deterministic startup orchestration before enforcement). +5. Detect repository, branch, and worktree state. +6. Reject implementation from the `dev` or `main` checkout unless the user explicitly overrides that rule. +7. If GitHub hierarchy metadata is needed and `.specfact/backlog/github_hierarchy_cache.md` is missing or stale, refresh it with `python scripts/sync_github_hierarchy_cache.py`. +8. Load additional rule files from the applicability matrix below before implementation (beyond the always-load set, which already includes this index, the checklist, and session bootstrap). ## Precedence diff --git a/docs/contributing/frontmatter-schema.md b/docs/contributing/frontmatter-schema.md index 1ad6776c..48b37db0 100644 --- a/docs/contributing/frontmatter-schema.md +++ b/docs/contributing/frontmatter-schema.md @@ -37,9 +37,9 @@ Files under `docs/agent-rules/` carry extra governance metadata on top of the st | Field | Type | Rules | | --- | --- | --- | -| `id` | string | Stable rule identifier used by references and dependencies. | -| `always_load` | boolean | `true` when the rule must be loaded during every applicable bootstrap. | -| `applies_when` | list of strings | Non-empty task signals such as `session-bootstrap`, `implementation`, or `github-public-work`. | +| `id` | string | Stable rule identifier used by references and dependencies; must be **kebab-case** (lowercase words separated by hyphens; see `RULE_ID_RE` in `scripts/check_doc_frontmatter.py`). | +| `always_load` | boolean | `true` when the rule must be loaded during every applicable bootstrap. When `true`, runtime validation requires that `applies_when` intersects `session-bootstrap`, `implementation`, or `all` (see `_always_load_requires_bootstrap_signal` in the script). | +| `applies_when` | list of strings | Non-empty task signals such as `session-bootstrap`, `implementation`, `all`, or `github-public-work`. If `always_load` is `true`, at least one entry must be `session-bootstrap`, `implementation`, or `all`. | | `priority` | integer | Non-negative ordering value used for deterministic rule loading. | | `blocking` | boolean | Whether the rule can stop progress when its conditions are unmet. | | `user_interaction_required` | boolean | Whether unmet conditions require user clarification before implementation continues. | diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md index 739a23a4..4d6f23a2 100644 --- a/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/proposal.md @@ -22,9 +22,9 @@ ## Impact - Affected governance docs and instruction surfaces: `AGENTS.md`, new `docs/agent-rules/` artifacts, and possibly other lightweight instruction aliases that must reference the canonical rule system. -- Affected OpenSpec/runtime guidance: `openspec/config.yaml`, `openspec/CHANGE_ORDER.md`, and related workflow guidance for agents. -- Affected GitHub workflow guidance: cache-backed parent lookup, metadata completeness checks, and concurrency-ambiguity handling for linked change issues. -- Affected validation scope: documentation consistency, frontmatter schema enforcement, and deterministic session-bootstrap behavior across AI models. +- OpenSpec/runtime guidance: `openspec/config.yaml`, `openspec/CHANGE_ORDER.md`, and related workflow guidance for agents. +- GitHub workflow guidance: cache-backed parent lookup, metadata completeness checks, and concurrency-ambiguity handling for linked change issues. +- Validation scope: documentation consistency, frontmatter schema enforcement, and deterministic session-bootstrap behavior across AI models. ## Tracking diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md index 81a7f24f..f8711fe7 100644 --- a/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/specs/agent-governance-loading/spec.md @@ -1,9 +1,11 @@ ## ADDED Requirements ### Requirement: Compact AGENTS bootstrap contract + The repository SHALL keep `AGENTS.md` as the mandatory bootstrap governance surface, but it SHALL remain compact and SHALL delegate long-form operational detail to canonical rule artifacts. #### Scenario: Session bootstrap reads compact governance contract + - **WHEN** an agent starts work in the repository - **THEN** it reads `AGENTS.md` first - **AND** `AGENTS.md` defines a mandatory bootstrap sequence rather than embedding the full long-form governance corpus @@ -11,74 +13,89 @@ The repository SHALL keep `AGENTS.md` as the mandatory bootstrap governance surf - **AND** the bootstrap sequence requires loading the canonical non-negotiable checklist before code implementation work #### Scenario: AGENTS stays compact while preserving enforcement + - **WHEN** repository governance is updated - **THEN** `AGENTS.md` SHALL retain only the bootstrap contract, invariant governance rules, and canonical references needed for startup - **AND** detailed workflow, validation, or finalization guidance SHALL live in dedicated rule artifacts rather than being duplicated inline ### Requirement: Deterministic rule index and loading semantics + The repository SHALL provide a canonical rule index that deterministically decides which governance rule files must be loaded for a given task. #### Scenario: Always-load rule subset + - **WHEN** an agent loads the governance rule index - **THEN** the index SHALL identify a mandatory always-load subset - **AND** that subset SHALL include the non-negotiable checklist - **AND** the index SHALL define the order in which always-load rules are processed #### Scenario: Applicability-based rule loading + - **WHEN** a task involves worktree management, OpenSpec change selection, GitHub issue coordination, TDD gating, quality verification, or finalization - **THEN** the index SHALL map those task signals to specific `docs/agent-rules/*.md` files - **AND** the index SHALL define which rule files are required versus optional for that task class - **AND** the loading decision SHALL not depend on heuristic file-name guessing alone #### Scenario: Deterministic precedence + - **WHEN** governance instructions overlap across `AGENTS.md`, the rule index, rule files, and change-local artifacts - **THEN** the repository SHALL define a single precedence order for which instruction wins - **AND** the precedence order SHALL include explicit handling for direct user override where repository governance permits it ### Requirement: Governance rule files use machine-readable frontmatter + Every dedicated governance rule artifact SHALL include machine-readable frontmatter that defines how and when the rule applies. #### Scenario: Required frontmatter fields are present + - **WHEN** a file under `docs/agent-rules/` is intended to govern agent behavior - **THEN** it SHALL include frontmatter fields for rule identity, applicability, priority, blocking semantics, and stop conditions - **AND** it SHALL declare whether the file is always loaded - **AND** it SHALL declare whether user interaction is required when the rule blocks progress #### Scenario: Frontmatter drives deterministic behavior + - **WHEN** an agent evaluates a rule file with frontmatter - **THEN** it can determine from metadata whether the rule is mandatory for the current task - **AND** it can determine whether the rule requires a hard stop, read-only continuation, or interactive clarification - **AND** it does not need to infer those semantics solely from unstructured prose ### Requirement: Governance must define explicit stop and continue behavior + The governance system SHALL define explicit blocking behavior for stale changes, concurrency ambiguity, missing metadata, and TDD gate violations. #### Scenario: Blocking ambiguity requires user clarification + - **WHEN** a selected change is stale, superseded, ambiguous, or linked to GitHub work already in progress - **THEN** the applicable rule SHALL require the agent to stop implementation work - **AND** the rule SHALL state that the ambiguity must be surfaced to the user for clarification - **AND** the rule SHALL define whether read-only investigation may continue while implementation remains blocked #### Scenario: TDD gate remains non-bypassable in compact governance + - **WHEN** a task changes behavior in code - **THEN** the applicable rule SHALL still require spec updates, test creation, failing-test evidence, implementation, and passing evidence in that order - **AND** compact governance SHALL not weaken or omit that sequence ### Requirement: Public GitHub work must pass metadata completeness checks + The governance system SHALL define explicit readiness checks for linked GitHub change issues before implementation proceeds for public repository work. #### Scenario: Parent and dependency metadata must be complete + - **WHEN** an agent prepares to implement a publicly tracked change with a linked GitHub issue - **THEN** the applicable governance rules SHALL require verifying the issue's parent relationship, blockers, and blocked-by relationships against current repository GitHub reality - **AND** the parent lookup SHALL use the local hierarchy cache first and refresh the cache when repository-defined freshness rules require it - **AND** implementation SHALL not proceed if the required parent or dependency metadata is missing or ambiguous #### Scenario: Labels and project assignment must be complete + - **WHEN** an agent prepares to implement a publicly tracked change with a linked GitHub issue - **THEN** the applicable governance rules SHALL require verifying that the issue has the required labels and project assignment for repository workflow completeness - **AND** implementation SHALL not proceed until that metadata is complete or the user explicitly directs an allowed exception path #### Scenario: Live GitHub issue state can block implementation + - **WHEN** an agent prepares to implement a publicly tracked change with a linked GitHub issue - **AND** the issue is already marked `in progress` - **THEN** the governance rules SHALL treat that state as a concurrency ambiguity @@ -86,9 +103,11 @@ The governance system SHALL define explicit readiness checks for linked GitHub c - **AND** the rules SHALL define whether only read-only investigation may continue while implementation remains blocked ### Requirement: Canonical aliases prevent instruction drift + Repository instruction surfaces other than `AGENTS.md` SHALL reference the canonical governance rule system instead of embedding duplicate long-form policy text. #### Scenario: Alias instruction surfaces stay synchronized + - **WHEN** a contributor reads another repository instruction surface such as `CLAUDE.md` or generated IDE guidance - **THEN** the surface SHALL reference the canonical rule system for governance semantics - **AND** it SHALL avoid copying long-form governance content that could drift from the canonical source diff --git a/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md b/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md index a0f48494..e4b074f3 100644 --- a/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md +++ b/openspec/changes/governance-03-deterministic-agent-governance-loading/tasks.md @@ -2,9 +2,12 @@ ## 1. Branch and governance preparation -- [x] 1.1 Create dedicated worktree branch `feature/governance-03-deterministic-agent-governance-loading` from `dev` before implementation work: `scripts/worktree.sh create feature/governance-03-deterministic-agent-governance-loading`. -- [x] 1.2 Confirm governance-01 and governance-02 outputs remain the dependency baseline for this change and update `openspec/CHANGE_ORDER.md` metadata if sequencing notes need adjustment. -- [x] 1.3 Review current `AGENTS.md`, related instruction surfaces, and existing docs/frontmatter validators to identify the files that must participate in the compact-governance migration. +- [x] 1.1 Create dedicated worktree branch `feature/governance-03-deterministic-agent-governance-loading` from `origin/dev` before implementation work: `scripts/worktree.sh create feature/governance-03-deterministic-agent-governance-loading`. +- [x] 1.2 In the new worktree directory, bootstrap Python tooling with `hatch env create`. +- [x] 1.3 Run pre-flight checks from the worktree root: `hatch run smart-test-status` and `hatch run contract-test-status`. +- [x] 1.4 Confirm governance-01 and governance-02 outputs remain the dependency baseline for this change and update `openspec/CHANGE_ORDER.md` metadata if sequencing notes need adjustment. +- [x] 1.5 Review current `AGENTS.md`, related instruction surfaces, and existing docs/frontmatter validators to identify the files that must participate in the compact-governance migration. +- [ ] 1.6 After the PR merges: run `git worktree remove`, `git branch -d`, and `git worktree prune` per `AGENTS.md`; delete the worktree-local `.venv` (or other env path) if you no longer need that checkout. ## 2. Spec-first and test-first preparation diff --git a/scripts/check_doc_frontmatter.py b/scripts/check_doc_frontmatter.py index 33c1c10e..e98f53cc 100755 --- a/scripts/check_doc_frontmatter.py +++ b/scripts/check_doc_frontmatter.py @@ -6,6 +6,7 @@ import datetime import fnmatch import functools +import json import os import re import subprocess @@ -207,6 +208,31 @@ def _enforced_path() -> Path: return _root() / "docs" / ".doc-frontmatter-enforced" +def _rel_posix(path: Path) -> str: + try: + return path.resolve().relative_to(_root().resolve()).as_posix() + except ValueError: + return str(path).replace("\\", "/") + + +def _agent_rules_path_slug(rel_under_rules: str) -> str: + """Build URL-style slug from path under ``docs/agent-rules/`` (matches existing rule ids).""" + tail = rel_under_rules[:-3] if rel_under_rules.endswith(".md") else rel_under_rules + parts = tail.split("/") + cleaned = [re.sub(r"^\d+-", "", segment) for segment in parts] + return "-".join(cleaned).lower().replace("_", "-") + + +def _agent_rules_canonical_id(rel_under_rules: str) -> str: + return f"agent-rules-{_agent_rules_path_slug(rel_under_rules)}" + + +def _agent_rules_default_permalink(slug: str) -> str: + if slug == "index": + return "/contributing/agent-rules/" + return f"/contributing/agent-rules/{slug}/" + + def _path_is_existing_file(path: Path) -> bool: return path.is_file() @@ -359,10 +385,57 @@ def validate_glob_patterns(patterns: list[str]) -> bool: @ensure(lambda result: isinstance(result, str), "Must return string") def suggest_frontmatter(path: Path) -> str: """Return a suggested frontmatter block for a document.""" - if _rel_posix(path).startswith(AGENT_RULES_DIR): + rel = _rel_posix(path) + if rel.startswith(AGENT_RULES_DIR): + rel_under = rel[len(AGENT_RULES_DIR) :] + rule_slug = _agent_rules_path_slug(rel_under) + canonical_id = _agent_rules_canonical_id(rel_under) + default_permalink = _agent_rules_default_permalink(rule_slug) + layout_val = "default" + permalink_val = default_permalink + description_val: str | None = None + keywords_val: list[str] | None = None + audience_val: list[str] | None = None + expertise_val: list[str] | None = None + if path.is_file(): + try: + existing = parse_frontmatter(path) + except OSError: + existing = {} + else: + lv = existing.get("layout") + if isinstance(lv, str) and lv.strip(): + layout_val = lv.strip() + pv = existing.get("permalink") + if isinstance(pv, str) and pv.strip(): + permalink_val = pv.strip() + dv = existing.get("description") + if isinstance(dv, str) and dv.strip(): + description_val = dv.strip() + kv = existing.get("keywords") + if isinstance(kv, list) and all(isinstance(x, str) for x in kv): + keywords_val = list(kv) + av = existing.get("audience") + if isinstance(av, list) and all(isinstance(x, str) for x in av): + audience_val = list(av) + ev = existing.get("expertise_level") + if isinstance(ev, list) and all(isinstance(x, str) for x in ev): + expertise_val = list(ev) + title_guess = path.stem.replace("-", " ").title().replace('"', '\\"') + optional_lines = "" + if description_val is not None: + optional_lines += f"description: {json.dumps(description_val)}\n" + if keywords_val is not None: + optional_lines += f"keywords: {json.dumps(keywords_val)}\n" + if audience_val is not None: + optional_lines += f"audience: {json.dumps(audience_val)}\n" + if expertise_val is not None: + optional_lines += f"expertise_level: {json.dumps(expertise_val)}\n" return f"""--- -title: "{path.stem.replace("-", " ").title()}" -id: {path.stem.lower()} +layout: {json.dumps(layout_val)} +title: "{title_guess}" +permalink: {json.dumps(permalink_val)} +{optional_lines}id: {canonical_id} doc_owner: specfact-cli tracks: - AGENTS.md @@ -394,13 +467,6 @@ def suggest_frontmatter(path: Path) -> str: """ -def _rel_posix(path: Path) -> str: - try: - return path.resolve().relative_to(_root().resolve()).as_posix() - except ValueError: - return str(path).replace("\\", "/") - - def _load_enforced_patterns() -> list[str] | None: """Return path patterns from docs/.doc-frontmatter-enforced, or None if file missing.""" path = _enforced_path() diff --git a/tests/helpers/doc_frontmatter_types.py b/tests/helpers/doc_frontmatter_types.py index c189a0c0..2efa9a91 100644 --- a/tests/helpers/doc_frontmatter_types.py +++ b/tests/helpers/doc_frontmatter_types.py @@ -39,12 +39,14 @@ class CheckDocFrontmatterModule(Protocol): @runtime_checkable class DocFrontmatterRecord(Protocol): - """Minimal validated model instance shape used by tests.""" + """Validated doc-sync record shape (``DocFrontmatter`` / ``AgentRuleFrontmatter`` base fields).""" title: str doc_owner: str tracks: list[str] last_reviewed: date + exempt: bool + exempt_reason: str @runtime_checkable @@ -58,12 +60,16 @@ def model_validate(cls, data: dict[str, object]) -> DocFrontmatterRecord: @runtime_checkable class AgentRuleFrontmatterRecord(DocFrontmatterRecord, Protocol): - """Validated agent-rule record shape used by tests.""" + """Validated agent-rule record shape (mirrors ``AgentRuleFrontmatter`` public fields).""" id: str always_load: bool applies_when: list[str] priority: int + blocking: bool + user_interaction_required: bool + stop_conditions: list[str] + depends_on: list[str] @runtime_checkable diff --git a/tests/unit/docs/test_agent_rules_governance.py b/tests/unit/docs/test_agent_rules_governance.py index c7a22c0f..02b763fc 100644 --- a/tests/unit/docs/test_agent_rules_governance.py +++ b/tests/unit/docs/test_agent_rules_governance.py @@ -2,22 +2,12 @@ from pathlib import Path -import yaml +from tests.helpers.doc_frontmatter_types import CheckDocFrontmatterModule REPO_ROOT = Path(__file__).resolve().parents[3] -def _read_frontmatter(path: Path) -> dict[str, object]: - text = path.read_text(encoding="utf-8") - assert text.startswith("---\n") - _, body = text.split("---\n", 1) - frontmatter, _ = body.split("\n---\n", 1) - loaded = yaml.safe_load(frontmatter) - assert isinstance(loaded, dict) - return loaded - - def test_agent_rules_index_and_checklist_exist() -> None: index_path = REPO_ROOT / "docs" / "agent-rules" / "INDEX.md" checklist_path = REPO_ROOT / "docs" / "agent-rules" / "05-non-negotiable-checklist.md" @@ -26,8 +16,13 @@ def test_agent_rules_index_and_checklist_exist() -> None: assert checklist_path.exists() -def test_agent_rules_index_has_deterministic_bootstrap_metadata() -> None: - frontmatter = _read_frontmatter(REPO_ROOT / "docs" / "agent-rules" / "INDEX.md") +def test_agent_rules_index_has_deterministic_bootstrap_metadata( + check_doc_frontmatter_module: CheckDocFrontmatterModule, +) -> None: + parse_frontmatter = check_doc_frontmatter_module.parse_frontmatter + frontmatter = parse_frontmatter(REPO_ROOT / "docs" / "agent-rules" / "INDEX.md") + assert isinstance(frontmatter, dict) + applies_when = frontmatter["applies_when"] assert isinstance(applies_when, list) @@ -37,8 +32,13 @@ def test_agent_rules_index_has_deterministic_bootstrap_metadata() -> None: assert frontmatter["priority"] == 0 -def test_non_negotiable_checklist_is_always_loaded() -> None: - frontmatter = _read_frontmatter(REPO_ROOT / "docs" / "agent-rules" / "05-non-negotiable-checklist.md") +def test_non_negotiable_checklist_is_always_loaded( + check_doc_frontmatter_module: CheckDocFrontmatterModule, +) -> None: + parse_frontmatter = check_doc_frontmatter_module.parse_frontmatter + frontmatter = parse_frontmatter(REPO_ROOT / "docs" / "agent-rules" / "05-non-negotiable-checklist.md") + assert isinstance(frontmatter, dict) + depends_on = frontmatter["depends_on"] assert isinstance(depends_on, list) diff --git a/tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py b/tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py index 70679fdc..1b521447 100644 --- a/tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py +++ b/tests/unit/scripts/test_doc_frontmatter/test_agent_rule_frontmatter.py @@ -124,7 +124,7 @@ def test_validation_rejects_missing_agent_rule_fields( write_enforced(root, "docs/agent-rules/INDEX.md") result = validation_main([]) - assert result == 1 + assert result != 0 err = capsys.readouterr().err assert "docs/agent-rules/INDEX.md" in err assert "applies_when" in err From 9b3faea54abed0871a08522478b8e3297fb2327e Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Fri, 10 Apr 2026 23:31:33 +0200 Subject: [PATCH 6/6] docs: add sibling internal wiki context for OpenSpec design Point AGENTS.md, Claude/Copilot/Cursor surfaces, and the OpenSpec rule at docs/agent-rules/40-openspec-and-tdd.md to read-only wiki paths (hot.md, graph.md, concepts) via absolute paths when specfact-cli-internal is present. Update INDEX applicability notes and extend governance tests. Made-with: Cursor --- .cursor/rules/session_startup_instructions.mdc | 1 + .github/copilot-instructions.md | 1 + AGENTS.md | 4 ++++ CLAUDE.md | 2 ++ docs/agent-rules/40-openspec-and-tdd.md | 12 ++++++++++++ docs/agent-rules/INDEX.md | 4 ++-- tests/unit/docs/test_agent_rules_governance.py | 2 ++ 7 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.cursor/rules/session_startup_instructions.mdc b/.cursor/rules/session_startup_instructions.mdc index 620609c6..5b90ece0 100644 --- a/.cursor/rules/session_startup_instructions.mdc +++ b/.cursor/rules/session_startup_instructions.mdc @@ -11,5 +11,6 @@ alwaysApply: true 3. Read `docs/agent-rules/05-non-negotiable-checklist.md`. 4. Detect repository root, branch, and worktree state before implementation. 5. Load any additional rule files selected by the applicability matrix in `docs/agent-rules/INDEX.md`. +6. If a sibling internal checkout (for example `../specfact-cli-internal/`) exists and you are designing or scoping an OpenSpec change, follow the internal wiki guidance in `docs/agent-rules/40-openspec-and-tdd.md` (section **Internal wiki and strategic context**): read `wiki/hot.md`, `wiki/graph.md`, and relevant `wiki/concepts/*.md` via absolute paths; do not import wiki text into this repo. Do not treat this file as a complete workflow handbook. The canonical repository governance now lives in `docs/agent-rules/`. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 48d63eaf..094242a1 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,6 +4,7 @@ Use [AGENTS.md](../AGENTS.md) as the mandatory bootstrap surface and [docs/agent ## Minimal reminders +- When a sibling internal repository (for example `../specfact-cli-internal/`) exists, read its `wiki/` files by absolute path before designing an OpenSpec change; see **Strategic context** in `AGENTS.md` and `docs/agent-rules/40-openspec-and-tdd.md` (section **Internal wiki and strategic context**). Do not copy wiki content into this repository. - This repository enforces the clean-code review gate through `hatch run specfact code review run --json --out .specfact/code-review.json`. - Public APIs require `@icontract` and `@beartype`. - Work belongs on `feature/*`, `bugfix/*`, `hotfix/*`, or `chore/*` branches, normally in a worktree. diff --git a/AGENTS.md b/AGENTS.md index cc048988..1b5ae117 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,6 +36,10 @@ This file is the mandatory bootstrap governance surface for coding agents workin - Treat the clean-code compliance gate as mandatory: the review surface enforces `naming`, `kiss`, `yagni`, `dry`, and `solid` categories and blocks regressions. - Enforce module signatures and version bumps when signed module assets or manifests are affected. +## Strategic context + +Design and dependency context may live in a **sibling internal repository** (for example a checkout of `specfact-cli-internal` beside this repo, with wiki pages under `../specfact-cli-internal/wiki/`). Before designing or scoping a new OpenSpec change, read the wiki paths listed in [docs/agent-rules/40-openspec-and-tdd.md](docs/agent-rules/40-openspec-and-tdd.md#internal-wiki-and-strategic-context) using **absolute paths** to those files. Treat the wiki as read-only context; do not paste or commit wiki bodies into this public repository. + ## Canonical rule docs - [docs/agent-rules/INDEX.md](docs/agent-rules/INDEX.md) diff --git a/CLAUDE.md b/CLAUDE.md index afa4a6b1..311cd5f8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,6 +6,8 @@ This file is an alias surface for Claude Code. Follow [AGENTS.md](AGENTS.md) as Claude must treat the canonical rule docs as the source of truth for worktree policy, OpenSpec gating, GitHub completeness checks, TDD order, quality gates, versioning, and documentation rules. Do not rely on this file as a standalone governance handbook. +When a sibling internal repository with a `wiki/` tree is present (see **Strategic context** in `AGENTS.md` and [Internal wiki and strategic context](docs/agent-rules/40-openspec-and-tdd.md#internal-wiki-and-strategic-context) in the OpenSpec rule), read those wiki files by absolute path before designing a new OpenSpec change. Keep wiki content out of the public repository. + ## Clean-code alias Claude must preserve the clean-code compliance gate and its category references. The canonical review surface enforces `naming`, `kiss`, `yagni`, `dry`, and `solid` and treats clean-code regressions as blocking until they are fixed or explicitly justified. diff --git a/docs/agent-rules/40-openspec-and-tdd.md b/docs/agent-rules/40-openspec-and-tdd.md index 47c124e6..ae8de93c 100644 --- a/docs/agent-rules/40-openspec-and-tdd.md +++ b/docs/agent-rules/40-openspec-and-tdd.md @@ -41,6 +41,18 @@ depends_on: - The existence of any open change is not sufficient; the change must cover the requested scope. - If no change exists, clarify whether the work needs a new change, a modified existing change, or a delta. +## Internal wiki and strategic context + +When a **sibling internal repository** is available on disk (typical layout: this repository’s parent directory also contains `specfact-cli-internal`, so the internal wiki resolves under `../specfact-cli-internal/wiki/` relative to this repo root), use that wiki as **read-only** input for design decisions. Do not copy wiki content into this public tree. + +Before **designing or materially scoping** a new OpenSpec change, read these wiki files when they exist: resolve each wiki-relative path against the sibling checkout so you open an **absolute path** on the host (for example join this repository root with `../specfact-cli-internal/wiki/hot.md` and canonicalize) and read the file directly: + +- `wiki/hot.md` for current blocker state +- `wiki/graph.md` to see what the change unblocks or depends on +- The relevant concept page under `wiki/concepts/` (for example `wiki/concepts/clean-code-principles.md`) + +If the sibling checkout or a given wiki file is missing, continue without it; absence of the internal repo is not a blocking error for public-repo work. + ## Change validity - Never implement from a change id alone. diff --git a/docs/agent-rules/INDEX.md b/docs/agent-rules/INDEX.md index 455d5c7b..aee2c89c 100644 --- a/docs/agent-rules/INDEX.md +++ b/docs/agent-rules/INDEX.md @@ -65,7 +65,7 @@ This page is the canonical loader for repository governance instructions. `AGENT | Task signal | Required rule files | Optional rule files | | --- | --- | --- | -| Any implementation request | `10-session-bootstrap.md`, `40-openspec-and-tdd.md`, `50-quality-gates-and-review.md` | `20-repository-context.md` | +| Any implementation request | `10-session-bootstrap.md`, `40-openspec-and-tdd.md`, `50-quality-gates-and-review.md` | `20-repository-context.md`; sibling internal `wiki/` (see **Internal wiki and strategic context** in `40-openspec-and-tdd.md`) when present | | Code or docs changes on a branch | `30-worktrees-and-branching.md` | `80-current-guidance-catalog.md` | | Public GitHub issue work | `60-github-change-governance.md` | `30-worktrees-and-branching.md` | | Release or finalization work | `70-release-commit-and-docs.md`, `50-quality-gates-and-review.md` | `80-current-guidance-catalog.md` | @@ -77,7 +77,7 @@ This page is the canonical loader for repository governance instructions. `AGENT - [`10-session-bootstrap.md`](./10-session-bootstrap.md): startup checks, compact context loading, and stop/continue behavior - [`20-repository-context.md`](./20-repository-context.md): project overview, commands, architecture, and logging - [`30-worktrees-and-branching.md`](./30-worktrees-and-branching.md): branch protection, worktree policy, and conflict avoidance -- [`40-openspec-and-tdd.md`](./40-openspec-and-tdd.md): OpenSpec selection, change validity, and strict TDD order +- [`40-openspec-and-tdd.md`](./40-openspec-and-tdd.md): OpenSpec selection, change validity, strict TDD order, and optional sibling internal wiki context for change design - [`50-quality-gates-and-review.md`](./50-quality-gates-and-review.md): required gates, code review JSON, clean-code enforcement, module signatures - [`60-github-change-governance.md`](./60-github-change-governance.md): cache-first GitHub metadata, dependency completeness, and `in progress` ambiguity handling - [`70-release-commit-and-docs.md`](./70-release-commit-and-docs.md): versioning, changelog, docs, README, and commit signing diff --git a/tests/unit/docs/test_agent_rules_governance.py b/tests/unit/docs/test_agent_rules_governance.py index 02b763fc..ac0895c0 100644 --- a/tests/unit/docs/test_agent_rules_governance.py +++ b/tests/unit/docs/test_agent_rules_governance.py @@ -52,3 +52,5 @@ def test_agents_references_canonical_rule_docs() -> None: assert "docs/agent-rules/INDEX.md" in agents_text assert "docs/agent-rules/05-non-negotiable-checklist.md" in agents_text + assert "## Strategic context" in agents_text + assert "internal-wiki-and-strategic-context" in agents_text