diff --git a/.github/INVENTORY.md b/.github/INVENTORY.md index 972884a..b3c42e5 100644 --- a/.github/INVENTORY.md +++ b/.github/INVENTORY.md @@ -9,6 +9,8 @@ This file is the exact path inventory for the live GitHub Copilot catalog in thi - `.github/instructions/awesome-copilot-kubernetes-manifests.instructions.md` - `.github/instructions/awesome-copilot-shell.instructions.md` - `.github/instructions/internal-bash.instructions.md` +- `.github/instructions/internal-copilot-agent-authoring.instructions.md` +- `.github/instructions/internal-copilot-skill-reference-authoring.instructions.md` - `.github/instructions/internal-docker.instructions.md` - `.github/instructions/internal-github-action-composite.instructions.md` - `.github/instructions/internal-github-actions.instructions.md` diff --git a/.github/agents/internal-sync-global-copilot-configs-into-repo.agent.md b/.github/agents/internal-sync-global-copilot-configs-into-repo.agent.md index dffc0e3..68986bf 100644 --- a/.github/agents/internal-sync-global-copilot-configs-into-repo.agent.md +++ b/.github/agents/internal-sync-global-copilot-configs-into-repo.agent.md @@ -43,7 +43,7 @@ Treat this agent plus `.github/skills/internal-agent-sync-global-copilot-configs - Treat this repository as the source of truth for the managed sync baseline. - Start in `plan` by default. Move to `apply` only on explicit request and only when the plan is conflict-safe. - Keep target assumptions narrow and let the paired skill own the mirrored-scope and plan-file details. -- Preserve target `local-*` assets plus any consumer-owned `.github/local-github-instructions-overrides.md` file, exclude repository-owned `internal-sync-*` resources from mirroring, and keep root-guidance files layered according to the paired skill contract. +- Preserve target `local-*` assets plus any consumer-owned `.github/copilot-instructions.override.md` file, exclude repository-owned `internal-sync-*` resources from mirroring, and keep root-guidance files layered according to the paired skill contract. - When the source baseline contains approved imported-asset override registries or replay patches, mirror them as source-managed governance assets; do not recreate target-only hidden forks or ad hoc local edits to imported upstream resources. - When repository-root `LESSONS_LEARNED.md` is in scope, ensure the target has it and keep it structurally aligned with the source contract while preserving or migrating target-authored lesson rows through the paired skill workflow. - Sync only the managed cross-repository baseline declared by the paired skill contract; do not expand beyond that scope unless the user explicitly asks for more. @@ -52,7 +52,7 @@ Treat this agent plus `.github/skills/internal-agent-sync-global-copilot-configs ## Routing - Use this agent for consumer-repository baseline propagation, drift assessment, `plan`, and `apply` runs. -- Use this agent when the target must inherit the current bridge model around `AGENTS.md`, `.github/copilot-instructions.md`, `.github/local-github-instructions-overrides.md`, `.github/INVENTORY.md`, and repository-root `LESSONS_LEARNED.md`. +- Use this agent when the target must inherit the current bridge model around `AGENTS.md`, `.github/copilot-instructions.md`, `.github/copilot-instructions.override.md`, `.github/INVENTORY.md`, and repository-root `LESSONS_LEARNED.md`. - Do not use this agent for source-side catalog redesign, agent or skill authoring, or governance restructuring in this repository; recommend `internal-planning-leader` instead. - Do not use this agent for routine local execution once the sync contract is already settled and only a small target-local edit remains; recommend the appropriate executor for that repository instead. - When current platform behavior is the deciding factor, validate it through `internal-copilot-docs-research` before changing the sync policy. @@ -73,7 +73,7 @@ Treat this agent plus `.github/skills/internal-agent-sync-global-copilot-configs - Target analysis and selected mode - Root-guidance alignment strategy and `LESSONS_LEARNED.md` sync status -- Preserved `local-*` assets, `.github/local-github-instructions-overrides.md` status, and target-only cleanup decisions +- Preserved `local-*` assets, `.github/copilot-instructions.override.md` status, and target-only cleanup decisions - Boundary or approval decisions that affected the selected mode - Validation results, remaining blockers, and the completion-report sections - When present, the completion report should name the used agents, instructions, skills, and other resources and explain why they were relevant diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 91c4f2d..7168b99 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -18,14 +18,14 @@ You are an expert software and platform engineer. Protect correctness, security, 4. Matching `.github/instructions/*.instructions.md` files provide scoped or domain-specific guidance and may override defaults inside their declared scope. 5. Skills and agents are on-demand operational assets; use them only when relevant. 6. `.github/INVENTORY.md` is the live catalog of managed assets and is never replaced by `AGENTS.md`. -7. If `.github/local-github-instructions-overrides.md` exists, read it before relying on synced repo-wide defaults; it is the consumer-local exception layer authorized by `AGENTS.md`. +7. If `.github/copilot-instructions.override.md` exists, read it before relying on synced repo-wide defaults; it is the consumer-local exception layer authorized by `AGENTS.md`. - `internal-sync-*` assets stay sync-specific and must not become second canonical homes for repository-wide policy. - When repository-wide defaults change, update `AGENTS.md` first, then refresh this file, then realign narrower governance assets that reference the change. - When source-managed guidance from this repository is mirrored into consumer repositories, phrase source-side rules conditionally so they remain true in targets and do not imply that the target repository is the source of truth. -- `.github/local-github-instructions-overrides.md` may override synced defaults from `AGENTS.md` or this file only when the exception makes the conflict, scope, reason, and required disclosure explicit. -- If `.github/local-github-instructions-overrides.md` exists but declares no active overrides, keep following the synced baseline. -- When following a local override instead of the synced baseline, say that a consumer-local exception is in effect and cite `.github/local-github-instructions-overrides.md`. +- `.github/copilot-instructions.override.md` may override synced defaults from `AGENTS.md` or this file only when the exception makes the conflict, scope, reason, and required disclosure explicit. +- If `.github/copilot-instructions.override.md` exists but declares no active overrides, keep following the synced baseline. +- When following a local override instead of the synced baseline, say that a consumer-local exception is in effect and cite `.github/copilot-instructions.override.md`. - Do not treat the local override file as inventory or as a replacement for the bridge, projection, and catalog split. ## Language Projection diff --git a/.github/local-github-instructions-overrides.md.template b/.github/copilot-instructions.override.md.template similarity index 85% rename from .github/local-github-instructions-overrides.md.template rename to .github/copilot-instructions.override.md.template index 2f9eae0..d67410d 100644 --- a/.github/local-github-instructions-overrides.md.template +++ b/.github/copilot-instructions.override.md.template @@ -1,9 +1,9 @@ -# Local GitHub Instructions Overrides +# Copilot Instructions Override This file is the consumer-local exception layer authorized by `AGENTS.md` and referenced by `.github/copilot-instructions.md`. -In the standards repository it lives as `.github/local-github-instructions-overrides.md.template`. -Sync materializes that template into consumer repositories as `.github/local-github-instructions-overrides.md`. +In the standards repository it lives as `.github/copilot-instructions.override.md.template`. +Sync materializes that template into consumer repositories as `.github/copilot-instructions.override.md`. After materialization, the target repository owns the local exceptions declared there. ## Status @@ -32,5 +32,5 @@ Copy this block for each active exception and replace the placeholders. - `Baseline rule`: `` - `Local scope`: `` - `Reason`: `` -- `Required disclosure`: `Consumer-local exception in effect from .github/local-github-instructions-overrides.md: ` +- `Required disclosure`: `Consumer-local exception in effect from .github/copilot-instructions.override.md: ` - `Local instruction`: `` diff --git a/.github/instructions/internal-copilot-agent-authoring.instructions.md b/.github/instructions/internal-copilot-agent-authoring.instructions.md new file mode 100644 index 0000000..ed9b9f8 --- /dev/null +++ b/.github/instructions/internal-copilot-agent-authoring.instructions.md @@ -0,0 +1,25 @@ +--- +description: Repository-owned Copilot agent authoring guardrails for boundary clarity, paired-asset coherence, and minimal duplication. +applyTo: ".github/agents/internal-*.agent.md,.github/agents/local-*.agent.md" +--- + +# Copilot Agent Authoring Instructions + +## Workflow + +- Load `internal-agent-development` before planning or editing a repository-owned agent, or before redefining the boundary between an agent, skill, prompt, and instruction. +- When the agent depends on a paired skill or local references, inspect those assets before finalizing and fix only the necessary drift in the same change. + +## Cohesion + +- Keep route, boundary, tool contract, and output expectations in the agent. +- Keep reusable procedure in paired skills and deep reusable detail in references. +- If a paired skill or reference owns the detailed contract, keep the agent summary-level and remove re-listed subtopics. +- Use `## Mandatory Engine Skills` only for required engines and `## Optional Support Skills` only for conditional helpers. +- Use `## Skill Usage Contract` only when declared support skills are genuinely conditional. +- Treat `## Preferred/Optional Skills` as legacy and do not introduce it in repository-owned agents. + +## Validation + +- Re-check frontmatter alignment, declared skills, and paired-bundle drift before finishing. +- Run the closest existing catalog validation that covers the touched agent. diff --git a/.github/instructions/internal-copilot-skill-reference-authoring.instructions.md b/.github/instructions/internal-copilot-skill-reference-authoring.instructions.md new file mode 100644 index 0000000..90db96d --- /dev/null +++ b/.github/instructions/internal-copilot-skill-reference-authoring.instructions.md @@ -0,0 +1,25 @@ +--- +description: Repository-owned skill reference guardrails for deep reusable detail without duplicating paired agent or SKILL.md contracts. +applyTo: ".github/skills/internal-*/references/**/*.md,.github/skills/local-*/references/**/*.md" +--- + +# Copilot Skill Reference Authoring Instructions + +## Workflow + +- Use references as the deep owner for reusable tables, templates, and detailed checklists. +- When a reference change rewrites the paired bundle boundary, load `internal-skill-creator` and `internal-agent-development` as needed instead of inventing a parallel split. +- When editing a deep reference, inspect the paired `SKILL.md` and any paired agent before finalizing and fix only the necessary drift in the same change. + +## Cohesion + +- Keep route and boundary language in the paired agent. +- Keep reusable workflow, anti-scope, and validation posture in `SKILL.md`. +- Use references as the deep owner for reusable tables, templates, and detailed checklists. +- Do not copy the same deep material back into `SKILL.md` or the paired agent. +- If a reference becomes the canonical detail owner, trim matching duplication from the paired bundle in the same change. + +## Validation + +- Re-check local links and paired-bundle drift before finishing. +- Run the closest existing skill or catalog validation that covers the touched bundle. diff --git a/.github/scripts/lib/catalog_checks.py b/.github/scripts/lib/catalog_checks.py index 6f57e16..1fad4b5 100644 --- a/.github/scripts/lib/catalog_checks.py +++ b/.github/scripts/lib/catalog_checks.py @@ -28,6 +28,7 @@ def run_consistency_checks(root: Path, include_token_risks: bool = False) -> lis findings.extend(check_inventory_matches_filesystem(root)) findings.extend(check_bridge_references(root)) findings.extend(check_internal_agent_contracts(root)) + findings.extend(check_repo_owned_agent_sections(root)) findings.extend(check_duplicate_frontmatter_names(root)) findings.extend(check_source_local_assets(root)) findings.extend(check_imported_asset_overrides(root)) @@ -191,6 +192,56 @@ def check_internal_agent_contracts(root: Path) -> list[Finding]: return findings +def check_repo_owned_agent_sections(root: Path) -> list[Finding]: + findings: list[Finding] = [] + agents_root = root / ".github/agents" + if not agents_root.exists(): + return findings + + for path in sorted(agents_root.glob("*.agent.md")): + if not path.is_file() or not path.name.startswith(("internal-", "local-")): + continue + + relative_path = path.relative_to(root).as_posix() + text = read_text(path) + + if "## Preferred/Optional Skills" in text: + findings.append( + Finding( + severity="blocking", + code="repo-owned-agent-legacy-skill-heading", + path=relative_path, + message=( + "Repository-owned agents must use `## Optional Support Skills` instead of the legacy " + "`## Preferred/Optional Skills` heading." + ), + suggestion=( + "Replace the legacy heading and keep `## Skill Usage Contract` only when support " + "skills are genuinely conditional." + ), + ) + ) + + if "## Skill Usage Contract" in text and "## Optional Support Skills" not in text: + findings.append( + Finding( + severity="blocking", + code="repo-owned-agent-skill-usage-without-optional-support", + path=relative_path, + message=( + "Repository-owned agents should not keep `## Skill Usage Contract` without an " + "`## Optional Support Skills` section." + ), + suggestion=( + "Remove `## Skill Usage Contract` or add `## Optional Support Skills` only when the " + "declared skills are genuinely conditional." + ), + ) + ) + + return findings + + def check_duplicate_frontmatter_names(root: Path) -> list[Finding]: findings: list[Finding] = [] groups = { diff --git a/.github/scripts/lib/shared.py b/.github/scripts/lib/shared.py index 8f55111..756e878 100644 --- a/.github/scripts/lib/shared.py +++ b/.github/scripts/lib/shared.py @@ -38,8 +38,8 @@ ".github/repo-profiles.yml", ) MANAGED_WORKFLOW_FILES = (".github/workflows/_pre-commit.yml",) -LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_TEMPLATE_PATH = ".github/local-github-instructions-overrides.md.template" -LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_PATH = ".github/local-github-instructions-overrides.md" +COPILOT_INSTRUCTIONS_OVERRIDE_TEMPLATE_PATH = ".github/copilot-instructions.override.md.template" +COPILOT_INSTRUCTIONS_OVERRIDE_PATH = ".github/copilot-instructions.override.md" INVENTORY_PATH = ".github/INVENTORY.md" IMPORTED_ASSET_OVERRIDES_PATH = ".github/skills/internal-agent-sync-external-resources/references/imported-asset-overrides.yaml" diff --git a/.github/scripts/lib/syncing.py b/.github/scripts/lib/syncing.py index ba3581e..5d852af 100644 --- a/.github/scripts/lib/syncing.py +++ b/.github/scripts/lib/syncing.py @@ -11,10 +11,10 @@ from .inventory import render_inventory_markdown, sections_from_catalog_paths from .fingerprinting import HASH_ALGO, NORMALIZATION_VERSION, build_fingerprint from .shared import ( + COPILOT_INSTRUCTIONS_OVERRIDE_PATH, + COPILOT_INSTRUCTIONS_OVERRIDE_TEMPLATE_PATH, INVENTORY_PATH, LESSONS_PATH, - LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_PATH, - LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_TEMPLATE_PATH, MANAGED_ROOT_FILES, MANAGED_WORKFLOW_FILES, SyncOperation, @@ -65,25 +65,25 @@ def build_sync_plan(source_root: Path, target_root: Path) -> SyncPlan: local_assets: list[str] = [] generated_lessons: str | None = None - local_override_template_path = source_root / LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_TEMPLATE_PATH - local_override_target_path = target_root / LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_PATH + local_override_template_path = source_root / COPILOT_INSTRUCTIONS_OVERRIDE_TEMPLATE_PATH + local_override_target_path = target_root / COPILOT_INSTRUCTIONS_OVERRIDE_PATH if local_override_template_path.exists(): if not local_override_target_path.exists(): operations.append( SyncOperation( action="create", - path=LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_PATH, + path=COPILOT_INSTRUCTIONS_OVERRIDE_PATH, reason="Source-managed local override template missing from target; create the consumer-local override scaffold.", source_hash=sha256_file(local_override_template_path), target_hash=None, ) ) else: - local_assets.append(LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_PATH) + local_assets.append(COPILOT_INSTRUCTIONS_OVERRIDE_PATH) operations.append( SyncOperation( action="preserve", - path=LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_PATH, + path=COPILOT_INSTRUCTIONS_OVERRIDE_PATH, reason="Preserved consumer-owned local override layer after template materialization.", source_hash=sha256_file(local_override_template_path), target_hash=sha256_file(local_override_target_path), @@ -384,7 +384,7 @@ def discover_source_sync_files(root: Path) -> set[str]: files.update(all_files_under(root, ".github/agents")) files.update(all_files_under(root, ".github/instructions")) files.update(all_files_under(root, MANAGED_SKILL_DIR)) - files.discard(LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_TEMPLATE_PATH) + files.discard(COPILOT_INSTRUCTIONS_OVERRIDE_TEMPLATE_PATH) return { relative_path for relative_path in files @@ -574,8 +574,8 @@ def apply_sync_plan(plan: SyncPlan, allow_dirty_target: bool = False) -> Path: if plan.generated_lessons is None: raise RuntimeError("Generated LESSONS_LEARNED.md content missing from sync plan.") write_text(target_path, plan.generated_lessons) - elif operation.path == LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_PATH: - source_path = plan.source_root / LOCAL_GITHUB_INSTRUCTIONS_OVERRIDES_TEMPLATE_PATH + elif operation.path == COPILOT_INSTRUCTIONS_OVERRIDE_PATH: + source_path = plan.source_root / COPILOT_INSTRUCTIONS_OVERRIDE_TEMPLATE_PATH copy2(source_path, target_path) else: source_path = plan.source_root / operation.path diff --git a/.github/scripts/lib/token_risks.py b/.github/scripts/lib/token_risks.py index c551580..d51693b 100644 --- a/.github/scripts/lib/token_risks.py +++ b/.github/scripts/lib/token_risks.py @@ -30,6 +30,18 @@ def detect_token_risks(root: Path) -> list[Finding]: return sorted(findings, key=finding_sort_key) +def iter_repo_owned_agent_paths(root: Path) -> list[Path]: + agents_root = root / ".github/agents" + if not agents_root.exists(): + return [] + + return [ + path + for path in sorted(agents_root.glob("*.agent.md")) + if path.is_file() and path.name.startswith(("internal-", "local-")) + ] + + def check_bridge_overlap(root: Path) -> list[Finding]: agents_path = root / "AGENTS.md" copilot_path = root / ".github/copilot-instructions.md" @@ -106,9 +118,7 @@ def check_duplicate_markdown_bodies(root: Path) -> list[Finding]: def check_internal_agent_skill_list_size(root: Path) -> list[Finding]: findings: list[Finding] = [] - for path in sorted((root / ".github/agents").glob("internal-*.agent.md")): - if not path.is_file(): - continue + for path in iter_repo_owned_agent_paths(root): bullets = extract_section_bullets(read_text(path), "## Optional Support Skills") if len(bullets) > 8: findings.append( @@ -116,7 +126,7 @@ def check_internal_agent_skill_list_size(root: Path) -> list[Finding]: severity="non-blocking", code="large-skill-list", path=path.relative_to(root).as_posix(), - message=f"The internal agent declares {len(bullets)} optional support skills, which broadens live context.", + message=f"The repo-owned agent declares {len(bullets)} optional support skills, which broadens live context.", suggestion="Keep optional skill lists tight and move generic guidance into shared skills when possible.", ) ) @@ -227,9 +237,7 @@ def check_paired_agent_skill_overlap(root: Path) -> list[Finding]: return [] findings: list[Finding] = [] - for agent_path in sorted(agents_root.glob("internal-*.agent.md")): - if not agent_path.is_file(): - continue + for agent_path in iter_repo_owned_agent_paths(root): agent_text = read_text(agent_path) mandatory_skills = [bullet.strip("`") for bullet in extract_section_bullets(agent_text, "## Mandatory Engine Skills")] diff --git a/.github/skills/internal-agent-development/SKILL.md b/.github/skills/internal-agent-development/SKILL.md index 137e749..3cbebfd 100644 --- a/.github/skills/internal-agent-development/SKILL.md +++ b/.github/skills/internal-agent-development/SKILL.md @@ -29,6 +29,7 @@ Prefer explicit engine-skill architecture for routers and broader command center - Keep one cohesive operating role per agent. - Translate imported agent value into repo-local GitHub Copilot form. - Move reusable procedures into skills instead of bloating agent bodies. +- Keep paired agent, skill, and reference bundles coherent by assigning one owner per detail layer instead of letting the same subtopic drift across files. - Prefer explicit mandatory engine skills when an agent depends on reusable routing or decision logic, and make delegation-completion, degraded-mode, and anti-stall behavior explicit for routers and coordinator-style agents. - Keep any skill guidance explicit and reviewable when it adds value, without implying platform-enforced execution order. - Preserve evidence-first guidance patterns for fast-moving vendor or platform domains without cargo-culting obsolete tool wiring. @@ -53,6 +54,8 @@ Load these inputs before finalizing an internal agent: When the source agent already has a skill-guidance section such as `## Optional Support Skills` or `## Preferred/Optional Skills`, load only the directly relevant skill files before editing the target agent. Treat those lists as curated routing hints shaped by the repository resource model, not as a platform-enforced requirement to use every listed skill. +When the target agent depends on a paired skill or local references for detailed workflow, load those assets before editing so route, reusable procedure, and deep reference detail stay aligned instead of drifting in parallel. + ## Decision Gate Pick the right artifact before drafting: @@ -77,6 +80,7 @@ Keep these rules visible while drafting: - `description:` is the route and should start with `Use this agent when ...`. - Internal agents declare `tools:` explicitly with a short, role-shaped contract. - Use `## Mandatory Engine Skills` only for truly required reusable logic and `## Optional Support Skills` only for conditional support. +- When a paired skill or reference is the detailed contract owner, keep the agent boundary-focused and do not re-list the same operational subtopics. - Keep delegation controls explicit with `agents:`, `user-invocable`, and `disable-model-invocation` only when they materially enforce the boundary. - Keep long procedures in skills, not in the agent body. @@ -137,7 +141,7 @@ That asymmetry is a feature, not a defect, when it reduces drift. 3. Decide whether the behavior belongs in an agent, a skill, or both. Extract reusable procedure into a skill if the draft starts becoming a playbook. 4. If the behavior belongs in both, define the split explicitly. - Keep route, stance, tool contract, and output shape in the agent; keep reusable procedure in the skill. + Keep route, stance, tool contract, and output shape in the agent; keep reusable procedure in the skill; keep deep tables, templates, and long checklists in references. 5. Draft the `description:` before the body. If the routing sentence is vague, the rest of the agent will stay vague. 6. Choose the frontmatter and engine-skill strategy intentionally. @@ -146,8 +150,8 @@ That asymmetry is a feature, not a defect, when it reduces drift. Preserve the decision model while deleting obsolete runtime-specific scaffolding. 8. Add real boundaries and measurable output expectations. Non-router agents recommend the better owner when the boundary breaks instead of routing automatically. -9. Validate and de-duplicate. - Run repository validation and re-check whether the new agent makes another one redundant. +9. Validate, de-duplicate, and re-check paired assets. + Run repository validation and re-check whether the new agent makes another one redundant or leaves the paired bundle out of sync. ## Capability Translation Rules @@ -207,6 +211,7 @@ Load `references/design-patterns.md` for command-center structure questions and - Routers or coordinators that stop after naming the selected owner or saying a handoff will happen, without the delegated result or an explicit blocking explanation. - A skill-list section as a dumping ground for unrelated capabilities. - A `## Mandatory Engine Skills` section that merely mirrors the agent body without owning real reusable logic. +- An agent that points to a paired skill or reference as the detailed contract owner and then repeats the same subtopic inventory in the body. - Creating one dedicated skill per agent for visual symmetry even when shared or existing engines already solve the problem. - Repeating the same lane-mismatch recommendation matrix across multiple neighboring agents when one shared boundary engine would be clearer. - Starting from the selected agent file alone and skipping the directly relevant optional support or preferred skills that define how that agent should be applied. @@ -236,7 +241,9 @@ Load `references/design-patterns.md` for command-center structure questions and - If the agent includes `## Mandatory Engine Skills`, confirm every listed skill exists on disk and is truly required for the agent's core behavior. - If the agent includes `## Mandatory Engine Skills`, confirm the engine owns reusable logic that would otherwise bloat the agent or drift across multiple agents. - Confirm `## Optional Support Skills` does not duplicate `## Mandatory Engine Skills`. +- If a paired skill or reference is cited as the detailed contract owner, confirm the agent does not restate the same operational subtopics. - For canonical operational agents, confirm `## Optional Support Skills` is used instead of `## Preferred/Optional Skills`. +- If the agent includes `## Skill Usage Contract`, confirm `## Optional Support Skills` is present and the contract is actually conditional. - If the agent includes a skill-list section, confirm the list matches the intended reusable procedures. - If the agent includes a skill-list section, confirm the wording does not imply that `internal-*` skills automatically outrank imported skills. - Confirm any existing command-center agent used as a source or workflow anchor had its directly relevant declared skills loaded before final decisions were made. @@ -247,6 +254,7 @@ Load `references/design-patterns.md` for command-center structure questions and - Confirm routers are treated as the strongest case for a dedicated engine and that shared operational logic for the four canonical owners stays in a shared engine instead of branching into decorative mirrors. - Confirm the final internal agent preserved the strongest usable structure from the source pattern when that structure improved requirement discovery, tradeoff analysis, or response quality. - Confirm reusable procedures live in skills, not in the agent body. +- When changing a paired agent, confirm the adjacent skill and directly referenced local docs still match the route and boundaries. - Confirm the new or changed agent does not make an existing agent redundant. - Use `references/review-checklist.md` for a final pass when the change broadens scope or imports external patterns. - Run the repository validation entrypoints that currently exist after changes that affect agent naming or inventory, and report the gap explicitly when no dedicated validator is present. diff --git a/.github/skills/internal-agent-development/references/agent-contract.md b/.github/skills/internal-agent-development/references/agent-contract.md index 0726eed..a41c7d4 100644 --- a/.github/skills/internal-agent-development/references/agent-contract.md +++ b/.github/skills/internal-agent-development/references/agent-contract.md @@ -30,6 +30,7 @@ Use this reference when editing frontmatter, tool scope, engine-skill sections, - `## Optional Support Skills` is optional. Use it only when it materially improves routing clarity, discovery, or command-center usability. - Prefer `## Optional Support Skills` over `## Preferred/Optional Skills` for current internal contracts. - Use `## Optional Support Skills` only for conditional support skills, not for the required engine. +- When an agent depends on a paired skill or reference for detailed workflow, keep the agent summary-level and avoid re-listing the same operational subtopics. - When present, a skill-list section is a curated routing and discovery list. List exact canonical skill identifiers, one per bullet, in backticks. - Do not present a skill-list section as a native GitHub Copilot property or as a guarantee that every listed skill will be invoked automatically. - When expressing the resource model, treat `obra-*` as the cross-cutting workflow lane, `internal-*` as the canonical repository-owned layer, imported skills as support depth by default, and `local-*` as consumer-local extensions. Do not infer strategic, tactical, or operational role from prefix alone. @@ -53,8 +54,10 @@ Use this reference when editing frontmatter, tool scope, engine-skill sections, - Every agent must explain both positive routing and at least one meaningful boundary. - Every agent must define `## Output Expectations`. -- Add `## Skill Usage Contract` only when the agent is a broader command center whose listed skills are used conditionally. +- Add `## Skill Usage Contract` only when the agent is a broader command center whose listed support skills are used conditionally. +- Do not keep `## Skill Usage Contract` on a single-paired-skill agent with no conditional support list. - When `## Skill Usage Contract` is present, explain selection criteria and boundaries, not a blanket execution order. +- If an agent points to a paired skill or reference as the detailed contract owner, keep deep procedure, matrices, and templates out of the agent body. - When an agent can influence external actions, call out where human approval or review gates apply. - Keep long reusable workflows in skills, not in the agent body. diff --git a/.github/skills/internal-agent-development/references/review-checklist.md b/.github/skills/internal-agent-development/references/review-checklist.md index 508e82e..463fad0 100644 --- a/.github/skills/internal-agent-development/references/review-checklist.md +++ b/.github/skills/internal-agent-development/references/review-checklist.md @@ -23,6 +23,7 @@ Use this checklist before finalizing a new or revised internal agent. - Are the skill identifiers exact and canonical? - Do all declared skills reinforce the same operating role? - Does the agent need `## Skill Usage Contract`, or would that add noise? +- If the agent cites a paired skill or reference, does the agent stay summary-level instead of repeating the same subtopic inventory? ## Output Contract @@ -61,6 +62,7 @@ Use this checklist before finalizing a new or revised internal agent. - Does the filename stem match frontmatter `name:`? - Do all referenced local files exist? +- Were adjacent paired skills and directly referenced local docs checked for drift? - Does the agent avoid making a neighboring agent redundant? - Have the repository validation entrypoints that currently exist been run, or has the validation gap been called out explicitly? diff --git a/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/SKILL.md b/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/SKILL.md index 69b7ead..a822816 100644 --- a/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/SKILL.md +++ b/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/SKILL.md @@ -28,7 +28,7 @@ The paired agent should not restate default mode handling, preserved `local-*` b - Preserve target `local-*` assets under mirrored categories, preserve the target consumer-local GitHub instructions overrides file after materialization, and delete target-only non-local assets there during `apply`. - When the source baseline includes an approved imported-asset override registry plus replay patches, mirror that governance bundle as source-managed state instead of recreating target-local hidden forks on imported assets. - Exclude source resources named `internal-sync-*` from consumer mirroring and remove any target copies of those resources during `apply`. -- Materialize the source template `.github/local-github-instructions-overrides.md.template` into the consumer target as the consumer-local GitHub instructions overrides file when that target file is missing, then preserve target-authored changes there on later sync runs. +- Materialize the source template `.github/copilot-instructions.override.md.template` into the consumer target as the consumer-local copilot instructions override file when that target file is missing, then preserve target-authored changes there on later sync runs. - Keep root guidance layered: `AGENTS.md` is the bridge, `.github/copilot-instructions.md` is the repo-wide projection, the consumer-local GitHub instructions overrides file is the consumer-local exception layer, and `.github/INVENTORY.md` is the live catalog. - Treat `LESSONS_LEARNED.md` as a source-managed retained-learning template: create it when missing, keep its structure aligned with the source contract, and preserve target-authored pending lessons instead of overwriting them with source rows. - Mirror only the explicitly shared repository-hygiene files declared in `references/sync-contract.md`; do not widen workflow or root-file mirroring implicitly. diff --git a/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md b/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md index b35296a..b01c0d2 100644 --- a/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md +++ b/.github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md @@ -28,7 +28,7 @@ Treat `LESSONS_LEARNED.md` as a structure-managed exception: sync the source tem ## Target Rules - Preserve target `local-*` assets under mirrored categories and surface them in the plan or final report. -- Materialize `.github/local-github-instructions-overrides.md.template` from the standards repository into the consumer-local GitHub instructions overrides file when that target file is missing, then preserve the target file as a consumer-owned local exception layer and surface it in the plan or final report when present. +- Materialize `.github/copilot-instructions.override.md.template` from the standards repository into the consumer-local copilot instructions override file when that target file is missing, then preserve the target file as a consumer-owned local exception layer and surface it in the plan or final report when present. - Delete target-owned non-`local-*` assets inside mirrored categories during `apply`. - Keep the target target-agnostic. The default assumptions are only `.github/` and root `AGENTS.md`. - Ensure target root `LESSONS_LEARNED.md` exists. If it already exists, align it to the current source structure and migrate preserved pending lesson rows when the source table shape changes. diff --git a/.github/skills/internal-skill-creator/SKILL.md b/.github/skills/internal-skill-creator/SKILL.md index 0c4806d..1572bd0 100644 --- a/.github/skills/internal-skill-creator/SKILL.md +++ b/.github/skills/internal-skill-creator/SKILL.md @@ -93,6 +93,7 @@ Do not restate the full OpenAI creation workflow here. Use this skill to decide - Make descriptions searchable with concrete terms people would actually type: skill, trigger, `.github/skills/`, `SKILL.md`, create, replace, revise, update, reuse, validation. - Preserve a working `description:` during token optimization unless the baseline shows the route itself is the problem. - Keep the body lean. Put only the local contract in `SKILL.md` and move optional depth into references or reusable tools when repeated need justifies it. +- When a skill sits behind a paired agent or local references, keep one owner per detail layer: route and boundary in the agent, reusable workflow in `SKILL.md`, and deep detail in `references/`. - Prefer `references/` over new `scripts/` for static tables, starter templates, and audit taxonomies. Add scripts only when the workflow is deterministic, repeated, and execution-heavy. - Keep cross-references explicit instead of duplicating large chunks of generic bundle guidance. - Do not mirror the full OpenAI bundle workflow in this skill. Point to it when the remaining task is already covered there. @@ -132,7 +133,7 @@ After the local decision gate is complete, hand off to `openai-skill-creator` on 7. Validate the right thing. Ensure OpenAI-side structural checks ran if bundle mechanics changed, then check retrieval quality plus skill-type behavior before treating the skill as done. 8. Re-check routing fallout. - Update nearby references only when the visible local entrypoint or ownership meaning actually changed. + Update nearby references or paired agent text only when the visible local entrypoint or ownership meaning actually changed. Use `references/writing-skills-checklist.md` for the anti-rationalization rules, token-discipline reminders, and skill-type testing expectations that this wrapper should enforce. @@ -148,6 +149,9 @@ Then confirm: - the result makes rejection, reuse, and in-place tightening as natural as creation or replacement. - the skill still points to the right adjacent owner when the work is actually catalog governance or agent authoring. - the skill reads like a reusable guide instead of a one-off narrative. +- the edited skill does not repeat agent-owned routing or boundary language. +- the edited skill points to reference-owned deep material instead of copying it back into `SKILL.md`. +- any paired agent or local references still agree with the skill boundary when they exist. - OpenAI-side scaffolding or validation was invoked only when the remaining work actually required it. - the retrieval and pressure tests appropriate to the skill type have actually been run. - the body did not become a maintenance fork of generic OpenAI bundle documentation. diff --git a/.github/skills/internal-skill-creator/references/writing-skills-checklist.md b/.github/skills/internal-skill-creator/references/writing-skills-checklist.md index ae37391..9911667 100644 --- a/.github/skills/internal-skill-creator/references/writing-skills-checklist.md +++ b/.github/skills/internal-skill-creator/references/writing-skills-checklist.md @@ -31,8 +31,10 @@ This is a local distilled checklist informed by `writing-skills`. It exists to k ## Token discipline - Keep `SKILL.md` lean and move deeper material into `references/` or reusable tools only when justified. +- If the skill sits behind a paired agent, keep route and boundary language out of `SKILL.md`. - Preserve a working `description:` during token cuts unless the baseline shows routing is wrong. - Cross-reference reusable material instead of restating it. +- If local references own the deep tables, templates, or examples, point to them instead of copying them back into `SKILL.md`. - Prefer moving static lookup tables, starter templates, and detailed taxonomies into `references/`. - Prefer new `references/` over new `scripts/` unless the workflow is deterministic, repeated, and execution-heavy. - Prefer one strong example over several repetitive ones. diff --git a/AGENTS.md b/AGENTS.md index 0ccc836..44e036b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -67,11 +67,11 @@ This file is the stable entrypoint for the repository instruction architecture. ## Consumer Override Layer -- This standards repository owns the sync seed template at `.github/local-github-instructions-overrides.md.template`. -- Consumer repositories may keep `.github/local-github-instructions-overrides.md` as the consumer-local exception layer materialized from that template by sync. +- This standards repository owns the sync seed template at `.github/copilot-instructions.override.md.template`. +- Consumer repositories may keep `.github/copilot-instructions.override.md` as the consumer-local exception layer materialized from that template by sync. - That file may override synced defaults from `AGENTS.md` or `.github/copilot-instructions.md` only inside the consumer repository and only when each exception states the overridden baseline rule, local scope, reason, and required disclosure. - If the target file exists but declares no active overrides, keep the synced baseline authoritative. -- When a response follows a local override, it must say that a consumer-local exception is in effect and cite `.github/local-github-instructions-overrides.md`. +- When a response follows a local override, it must say that a consumer-local exception is in effect and cite `.github/copilot-instructions.override.md`. - Keep the target override file local in effect even when seeded by sync. Do not treat it as inventory, and do not use it to collapse the separate roles of `AGENTS.md`, `.github/copilot-instructions.md`, and `.github/INVENTORY.md`. - The local override layer must not redefine the ownership meaning of `internal-*`, `local-*`, or `internal-sync-*`; use it for repo-local exceptions, not for replacing the bridge model. diff --git a/tests/test_inventory_and_consistency.py b/tests/test_inventory_and_consistency.py index 98be974..d06e6ba 100644 --- a/tests/test_inventory_and_consistency.py +++ b/tests/test_inventory_and_consistency.py @@ -132,3 +132,63 @@ def test_run_consistency_checks_flags_invalid_imported_asset_override_registry( assert "imported-asset-override-invalid-apply-strategy" in finding_codes assert "imported-asset-override-patch-missing" in finding_codes assert "imported-asset-override-invalid-hash" in finding_codes + + +def test_run_consistency_checks_flags_legacy_repo_owned_agent_skill_headings( + tmp_path: Path, +) -> None: + write_file( + tmp_path / "AGENTS.md", + "# AGENTS\n\n- Use `.github/copilot-instructions.md`.\n- Use `.github/INVENTORY.md`.\n", + ) + write_file( + tmp_path / ".github/copilot-instructions.md", + "# Copilot Instructions\n\nSee `AGENTS.md`.\n", + ) + write_file( + tmp_path / ".github/agents/local-demo.agent.md", + "---\nname: local-demo\ntools: [read]\n---\n\n" + "# Local Demo\n\n" + "## Preferred/Optional Skills\n\n" + "- `local-demo`\n", + ) + write_file(tmp_path / ".github/INVENTORY.md", build_inventory_markdown(tmp_path)) + + findings = run_consistency_checks(tmp_path) + findings_by_path = {(finding.path, finding.code) for finding in findings} + + assert ( + ".github/agents/local-demo.agent.md", + "repo-owned-agent-legacy-skill-heading", + ) in findings_by_path + + +def test_run_consistency_checks_flags_skill_usage_contract_without_optional_support( + tmp_path: Path, +) -> None: + write_file( + tmp_path / "AGENTS.md", + "# AGENTS\n\n- Use `.github/copilot-instructions.md`.\n- Use `.github/INVENTORY.md`.\n", + ) + write_file( + tmp_path / ".github/copilot-instructions.md", + "# Copilot Instructions\n\nSee `AGENTS.md`.\n", + ) + write_file( + tmp_path / ".github/agents/internal-demo.agent.md", + "---\nname: internal-demo\ntools: [read]\n---\n\n" + "# Internal Demo\n\n" + "## Mandatory Engine Skills\n\n" + "- `internal-demo`\n\n" + "## Skill Usage Contract\n\n" + "- `internal-demo`: Use when the skill is mandatory.\n", + ) + write_file(tmp_path / ".github/INVENTORY.md", build_inventory_markdown(tmp_path)) + + findings = run_consistency_checks(tmp_path) + findings_by_path = {(finding.path, finding.code) for finding in findings} + + assert ( + ".github/agents/internal-demo.agent.md", + "repo-owned-agent-skill-usage-without-optional-support", + ) in findings_by_path diff --git a/tests/test_sync_and_token_risks.py b/tests/test_sync_and_token_risks.py index 735af9b..8012dfd 100644 --- a/tests/test_sync_and_token_risks.py +++ b/tests/test_sync_and_token_risks.py @@ -21,8 +21,8 @@ def test_build_sync_plan_preserves_local_assets_and_deletes_non_local_assets( write_file(source_root / "AGENTS.md", "# AGENTS\n") write_file(source_root / ".github/copilot-instructions.md", "# Copilot\n") write_file( - source_root / ".github/local-github-instructions-overrides.md.template", - "# Local GitHub Instructions Overrides\n\n- No active overrides in this repository.\n", + source_root / ".github/copilot-instructions.override.md.template", + "# Copilot Instructions Override\n\n- No active overrides in this repository.\n", ) write_file( source_root / ".github/agents/internal-fast.agent.md", @@ -48,8 +48,8 @@ def test_build_sync_plan_preserves_local_assets_and_deletes_non_local_assets( "---\nname: local-special\ntools: [read]\n---\n", ) write_file( - target_root / ".github/local-github-instructions-overrides.md", - "# Local GitHub Instructions Overrides\n\n- Override: Keep repo-local behavior explicit.\n", + target_root / ".github/copilot-instructions.override.md", + "# Copilot Instructions Override\n\n- Override: Keep repo-local behavior explicit.\n", ) write_file( target_root / ".github/agents/custom.agent.md", @@ -60,7 +60,7 @@ def test_build_sync_plan_preserves_local_assets_and_deletes_non_local_assets( actions = {(operation.action, operation.path) for operation in plan.operations} assert ("preserve", ".github/agents/local-special.agent.md") in actions - assert ("preserve", ".github/local-github-instructions-overrides.md") in actions + assert ("preserve", ".github/copilot-instructions.override.md") in actions assert ("delete", ".github/agents/custom.agent.md") in actions assert ("update", ".github/agents/internal-fast.agent.md") in actions assert ("delete", ".github/agents/internal-sync-legacy.agent.md") in actions @@ -75,19 +75,19 @@ def test_build_sync_plan_creates_target_local_override_from_template_when_missin write_file(source_root / "AGENTS.md", "# AGENTS\nsource\n") write_file(source_root / ".github/copilot-instructions.md", "# Copilot\nsource\n") write_file( - source_root / ".github/local-github-instructions-overrides.md.template", - "# Local GitHub Instructions Overrides\n\n- No active overrides in this repository.\n", + source_root / ".github/copilot-instructions.override.md.template", + "# Copilot Instructions Override\n\n- No active overrides in this repository.\n", ) write_file(target_root / "AGENTS.md", "# AGENTS\ntarget\n") write_file(target_root / ".github/copilot-instructions.md", "# Copilot\ntarget\n") plan = build_sync_plan(source_root, target_root) - assert ("create", ".github/local-github-instructions-overrides.md") in { + assert ("create", ".github/copilot-instructions.override.md") in { (operation.action, operation.path) for operation in plan.operations } assert all( - operation.path != ".github/local-github-instructions-overrides.md.template" + operation.path != ".github/copilot-instructions.override.md.template" for operation in plan.operations ) @@ -100,8 +100,8 @@ def test_apply_sync_plan_clears_plan_file_and_writes_manifest(tmp_path: Path) -> write_file(source_root / "VERSION", "1.2.3\n") write_file(source_root / ".github/copilot-instructions.md", "# Copilot\nsource\n") write_file( - source_root / ".github/local-github-instructions-overrides.md.template", - "# Local GitHub Instructions Overrides\n\n- No active overrides in this repository.\n", + source_root / ".github/copilot-instructions.override.md.template", + "# Copilot Instructions Override\n\n- No active overrides in this repository.\n", ) write_file( source_root / ".github/agents/internal-fast.agent.md", @@ -132,11 +132,11 @@ def test_apply_sync_plan_clears_plan_file_and_writes_manifest(tmp_path: Path) -> assert not ( target_root / ".github/internal-sync-copilot-configs.manifest.json" ).exists() - assert (target_root / ".github/local-github-instructions-overrides.md").exists() - assert (target_root / ".github/local-github-instructions-overrides.md").read_text( + assert (target_root / ".github/copilot-instructions.override.md").exists() + assert (target_root / ".github/copilot-instructions.override.md").read_text( encoding="utf-8" ) == ( - "# Local GitHub Instructions Overrides\n\n" + "# Copilot Instructions Override\n\n" "- No active overrides in this repository.\n" ) assert "AGENTS.md" in manifest["managed_hashes"] @@ -400,7 +400,7 @@ def test_detect_token_risks_ignores_structural_bridge_references( "- Use `.github/instructions/` for scoped guidance.\n" "- Use `.github/skills/` when a reusable workflow is relevant.\n" "- Use `.github/agents/` when a stable owner is relevant.\n" - "- Keep `.github/local-github-instructions-overrides.md` local to consumer repositories.\n", + "- Keep `.github/copilot-instructions.override.md` local to consumer repositories.\n", ) write_file(tmp_path / ".github/copilot-instructions.md", "# Copilot\n") write_file(tmp_path / ".github/INVENTORY.md", "# Inventory\n") @@ -524,6 +524,50 @@ def test_detect_token_risks_reports_paired_agent_skill_overlap(tmp_path: Path) - assert "paired-agent-skill-overlap" in finding_codes +def test_detect_token_risks_reports_paired_local_agent_skill_overlap( + tmp_path: Path, +) -> None: + shared_lines = "\n".join( + [ + "- Keep the paired agent short.", + "- The skill owns the reusable support workflow.", + "- Keep references as the home for starter templates.", + "- Re-check the paired bundle before finalizing.", + "- Avoid cloning the same subtopic inventory in three places.", + "- Leave routing and boundary language in the agent only.", + ] + ) + + write_file(tmp_path / "AGENTS.md", "# AGENTS\n") + write_file(tmp_path / ".github/copilot-instructions.md", "# Copilot\n") + write_file(tmp_path / ".github/INVENTORY.md", "# Inventory\n") + write_file( + tmp_path / ".github/agents/local-sync-example.agent.md", + "---\n" + "name: local-sync-example\n" + "tools: [read]\n" + "---\n\n" + "# Local Sync Example\n\n" + "## Mandatory Engine Skills\n\n" + "- `local-sync-example`\n\n" + f"{shared_lines}\n", + ) + write_file( + tmp_path / ".github/skills/local-sync-example/SKILL.md", + "---\n" + "name: local-sync-example\n" + "description: Local sync example\n" + "---\n\n" + "# Local Sync Example\n\n" + f"{shared_lines}\n", + ) + + findings = detect_token_risks(tmp_path) + finding_codes = {finding.code for finding in findings} + + assert "paired-agent-skill-overlap" in finding_codes + + def test_sync_contract_requires_target_local_validation_after_apply() -> None: sync_contract_text = Path( ".github/skills/internal-agent-sync-global-copilot-configs-into-repo/references/sync-contract.md" diff --git a/tests/test_workflow_review_contract.py b/tests/test_workflow_review_contract.py index 7b9e80d..84f6eb0 100644 --- a/tests/test_workflow_review_contract.py +++ b/tests/test_workflow_review_contract.py @@ -91,3 +91,54 @@ def test_agent_authoring_docs_preserve_subagent_inherited_defaults_note() -> Non "a subagent inherits the main session agent, model, and tools" in subagent_patterns_text ) + + +def test_repo_owned_agent_and_reference_authoring_guardrails_stay_scoped() -> None: + agent_instruction_text = read_text( + ".github/instructions/internal-copilot-agent-authoring.instructions.md" + ) + reference_instruction_text = read_text( + ".github/instructions/internal-copilot-skill-reference-authoring.instructions.md" + ) + agent_development_text = read_text( + ".github/skills/internal-agent-development/SKILL.md" + ) + agent_contract_text = read_text( + ".github/skills/internal-agent-development/references/agent-contract.md" + ) + skill_creator_text = read_text(".github/skills/internal-skill-creator/SKILL.md") + writing_skills_text = read_text( + ".github/skills/internal-skill-creator/references/writing-skills-checklist.md" + ) + + assert not Path( + ".github/instructions/internal-copilot-agent-skill-authoring.instructions.md" + ).exists() + assert ( + 'applyTo: ".github/agents/internal-*.agent.md,.github/agents/local-*.agent.md"' + in agent_instruction_text + ) + assert ( + 'applyTo: ".github/skills/internal-*/references/**/*.md,.github/skills/local-*/references/**/*.md"' + in reference_instruction_text + ) + assert ".github/skills/**/SKILL.md" not in agent_instruction_text + assert ".github/skills/**/SKILL.md" not in reference_instruction_text + assert "Treat `## Preferred/Optional Skills` as legacy" in agent_instruction_text + assert ( + "Use references as the deep owner for reusable tables, templates, and detailed checklists." + in reference_instruction_text + ) + assert ( + "When a paired skill or reference is the detailed contract owner" + in agent_development_text + ) + assert ( + "If an agent points to a paired skill or reference as the detailed contract owner" + in agent_contract_text + ) + assert ( + "When a skill sits behind a paired agent or local references" + in skill_creator_text + ) + assert "If the skill sits behind a paired agent" in writing_skills_text