diff --git a/plugins/core/.apm/skills/agentsmd-audit/README.md b/plugins/core/.apm/skills/agentsmd-audit/README.md index 658df6f..dec17e6 100644 --- a/plugins/core/.apm/skills/agentsmd-audit/README.md +++ b/plugins/core/.apm/skills/agentsmd-audit/README.md @@ -33,6 +33,6 @@ hand-edit made outside `agentsmd-author` — the audit is what confirms the resu | `tests/validate-drift.bats` | (source-only) Bats test suite for `scripts/validate-drift.sh` | Rows marked **(source-only)** exist in the authoring source (`.apm/skills/agentsmd-audit/`) but are -not present in an installed plugin: `scripts/sync-plugin-content.sh` strips `//tests` -when it generates the flat mirror, because these are dev-time fixtures no plugin host needs to -discover (ADR-0017). Run them from a repo checkout, not from an install. +not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips +`//tests` when it generates the flat mirror, because these are dev-time fixtures no +plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install. diff --git a/plugins/core/.apm/skills/agentsmd-audit/SKILL.md b/plugins/core/.apm/skills/agentsmd-audit/SKILL.md index 8d578d4..e852ebd 100644 --- a/plugins/core/.apm/skills/agentsmd-audit/SKILL.md +++ b/plugins/core/.apm/skills/agentsmd-audit/SKILL.md @@ -1,10 +1,10 @@ --- name: agentsmd-audit description: > - Use when the user wants a repo's AGENTS.md audited — "audit this AGENTS.md", - "is this AGENTS.md safe to commit" — or after a hand-edit outside - `agentsmd-author`. Reports secrets, structure and drift; never edits. - Not for CLAUDE.md or provider files -> `provider-adapter-author`. + Use when the user wants a repo's AGENTS.md audited for secrets, structure + and drift — "is this AGENTS.md safe to commit" — or after a hand-edit + outside `agentsmd-author`. + Not converting a provider file -> `provider-adapter-author`. Not writing AGENTS.md -> `agentsmd-author`. allowed-tools: Bash Read metadata: @@ -31,7 +31,7 @@ bash scripts/validate-structure.sh bash scripts/validate-drift.sh ``` -Each script walks the repo for every `AGENTS.md` file (root and nested, excluding `.git`, `node_modules`, `vendor`, and similar) and prints `FAIL`/`INFO`/`SUGGESTION` lines with `Why`/`Fix` (or `Note`) per finding. A nonzero exit means at least one FAIL was found in that dimension. If a script cannot execute (`python3` unavailable, Bash denied), fall back to manual review: scan for real-looking credentials, check common sections are present, and spot-check a few referenced commands/paths by hand. Grade a manual finding the way the scripts grade theirs: a missing common section (e.g. no "Security" heading) is informational, not a failure — not every repo needs every section from the checklist. Only flag a FAIL when the file is empty, entirely unfilled placeholder text, or contains a real embedded secret/stale reference. +Each script walks the repo for every `AGENTS.md` file (root and nested, excluding `.git`, `node_modules`, `vendor`, and similar) and prints `FAIL` lines, plus `INFO`/`SUGGESTION` where applicable, with `Why`/`Fix` (or `Note`) per finding. A nonzero exit means at least one FAIL was found in that dimension. If a script cannot execute (`python3` unavailable, Bash denied), fall back to manual review: scan for real-looking credentials, check common sections are present, and spot-check a few referenced commands/paths by hand. Grade a manual finding the way the scripts grade theirs: a missing common section (e.g. no "Security" heading) is informational, not a failure — not every repo needs every section from the checklist. Only flag a FAIL when the file is empty, entirely unfilled placeholder text, or contains a real embedded secret/stale reference. ## Step 2 — Report @@ -43,16 +43,4 @@ Checked: secrets · structure · drift Then output only findings that were found, in this order within a repo: `### Secrets`, `### Structure`, `### Drift`. Omit a dimension heading entirely if it produced nothing — its absence confirms it passed. Report each finding verbatim as emitted by the scripts (they already carry file:line, Why/Fix or Note). -Close with a result block: - -```text -## Result - -PASS -PASS · P info -PASS (N suggestions) · P info -FAIL (N fails) -FAIL (N fails) · P info -``` - -INFO and SUGGESTION findings are observational — they never flip PASS to FAIL. Do not fix anything — this skill reports and proposes only. Point the user to `agentsmd-author` to apply fixes. +Close with a `## Result` block holding one line: `PASS`, `PASS (N suggestions)`, or `FAIL (N fails · M suggestions)`, each optionally followed by ` · P info`. Omit the suggestion count when there are none, and omit `· P info` when there are none. INFO and SUGGESTION findings are observational — they never flip PASS to FAIL. Do not fix anything — this skill reports and proposes only. Point the user to `agentsmd-author` to apply fixes. diff --git a/plugins/core/.apm/skills/agentsmd-author/SKILL.md b/plugins/core/.apm/skills/agentsmd-author/SKILL.md index 6dc9d1f..a9b35f3 100644 --- a/plugins/core/.apm/skills/agentsmd-author/SKILL.md +++ b/plugins/core/.apm/skills/agentsmd-author/SKILL.md @@ -3,7 +3,7 @@ name: agentsmd-author description: > Use when the user wants a repo's AGENTS.md written or updated, root or nested, including "document this for AI coding tools". Writes only verified - conventions. Not review-only -> `agentsmd-audit`. Not for CLAUDE.md -> + conventions. Not review-only -> `agentsmd-audit`. Not converting CLAUDE.md -> `provider-adapter-author`. allowed-tools: Bash Read Write Edit metadata: @@ -36,8 +36,8 @@ AGENTS.md has no required schema. Use only sections that reflect something real ## Step 4 — Check for an existing provider file -Look for `CLAUDE.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, or similar in the target repo. If one exists and now duplicates content the AGENTS.md you just wrote/updated already owns, invoke the `provider-adapter-author` skill on it to reconcile. +Look for `CLAUDE.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, or similar in the target repo. If one exists, invoke the `provider-adapter-author` skill on it to reconcile — whether it duplicates content the AGENTS.md you just wrote/updated now owns, or is merely stale or missing a pointer to it. Never edit it yourself in either case. ## Step 5 — Audit and report -Invoke the `agentsmd-audit` skill directly on the AGENTS.md file(s) you just wrote or updated. This closeout is mandatory, not optional, even when the change looks trivial — never sign the work off on your own judgment. Resolve any FAIL findings before considering the work done — re-invoke this skill's own writing steps to fix them, then re-run the audit, same as any other close-the-loop check. Report what was created/changed, whether a provider file was reconciled, and the audit's final result. +Invoke the `agentsmd-audit` skill on the target repo root — its validators take a `` and walk the tree for every AGENTS.md themselves; there is no per-file entry point. This closeout is mandatory, not optional, even when the change looks trivial — never sign the work off on your own judgment. Resolve any FAIL findings before considering the work done — re-invoke this skill's own writing steps to fix them, then re-run the audit, same as any other close-the-loop check. Report what was created/changed, whether a provider file was reconciled, and the audit's final result. diff --git a/plugins/core/.apm/skills/provider-adapter-author/README.md b/plugins/core/.apm/skills/provider-adapter-author/README.md index 1f665e0..9401197 100644 --- a/plugins/core/.apm/skills/provider-adapter-author/README.md +++ b/plugins/core/.apm/skills/provider-adapter-author/README.md @@ -31,6 +31,6 @@ Provide the path to the provider-specific file to convert (and the target repo r | `tests/validate-adapter.bats` | (source-only) Bats test suite for `scripts/validate-adapter.sh` | Rows marked **(source-only)** exist in the authoring source (`.apm/skills/provider-adapter-author/`) -but are not present in an installed plugin: `scripts/sync-plugin-content.sh` strips +but are not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips `//tests` when it generates the flat mirror, because these are dev-time fixtures no plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install. diff --git a/plugins/core/.apm/skills/provider-adapter-author/SKILL.md b/plugins/core/.apm/skills/provider-adapter-author/SKILL.md index 2de7fe5..76111c7 100644 --- a/plugins/core/.apm/skills/provider-adapter-author/SKILL.md +++ b/plugins/core/.apm/skills/provider-adapter-author/SKILL.md @@ -2,7 +2,8 @@ name: provider-adapter-author description: > Use when a provider file (CLAUDE.md, .cursor rules, copilot-instructions) - duplicating the repo's AGENTS.md should be cut to a thin adapter. + duplicating the repo's AGENTS.md should be cut to a thin adapter — "make + CLAUDE.md just import AGENTS.md". Not writing the AGENTS file -> `agentsmd-author`. Not auditing the AGENTS file -> `agentsmd-audit`. allowed-tools: Bash Read Edit Write @@ -16,7 +17,6 @@ metadata: ## Gotchas - Assume a provider has no cross-file import mechanism until you have confirmed it has one. Claude Code is the exception, not the rule: a `CLAUDE.md` may consist of nothing but `@path` lines, while the same `@AGENTS.md` line in a Cursor rule or a Copilot instructions file is inert text no tool resolves. Pass `--no-import-syntax` to `scripts/validate-adapter.sh` for those providers. -- Works standalone or composed-into by `agentsmd-author` — behave identically either way; don't assume a caller skill exists. ## Step 1 — Detect @@ -43,7 +43,7 @@ Run the bundled check before finishing — this is the skill's own closeout gate bash scripts/validate-adapter.sh [--no-import-syntax] [--max-lines N] ``` -Fix any `FAIL` by editing the provider file, and re-run until it exits `0`. The size `FAIL` advises moving provider-agnostic content into `AGENTS.md`; disregard that half of its wording and delete the redundant lines instead. +Fix any `FAIL` by editing the provider file, and re-run until it exits `0`. ## Step 4 — Report diff --git a/plugins/core/.apm/skills/provider-adapter-author/scripts/validate-adapter.sh b/plugins/core/.apm/skills/provider-adapter-author/scripts/validate-adapter.sh index a94d112..513ef1f 100755 --- a/plugins/core/.apm/skills/provider-adapter-author/scripts/validate-adapter.sh +++ b/plugins/core/.apm/skills/provider-adapter-author/scripts/validate-adapter.sh @@ -16,10 +16,15 @@ Arguments: Options: --no-import-syntax The target provider has no native cross-file import - mechanism. Accept a plain-text pointer mention of - "AGENTS.md" instead of requiring an @import-style line. + mechanism. Require a plain-text pointer line naming + "AGENTS.md" instead of an @import-style line; an + @AGENTS.md line alone does not satisfy it, because + such a provider never resolves it. Without this flag + an actual @import line is required, and naming + AGENTS.md in prose alone does not satisfy it. --max-lines N Max non-blank lines allowed in the adapter file before - it's considered no longer "thin". Default: 60. + it's considered no longer "thin". Must be a + non-negative integer. Default: 60. --help, -h Show this help and exit 0. Exit codes: @@ -44,7 +49,15 @@ while [[ $# -gt 0 ]]; do shift ;; --max-lines) - MAX_LINES="${2:-}" + if [[ $# -lt 2 ]]; then + echo "Error: --max-lines requires a value (a non-negative integer)." >&2 + exit 1 + fi + MAX_LINES="$2" + if [[ ! "$MAX_LINES" =~ ^[0-9]+$ ]]; then + echo "Error: --max-lines expects a non-negative integer, got '$MAX_LINES'." >&2 + exit 1 + fi shift 2 ;; *) @@ -94,21 +107,25 @@ if not adapter_content.strip(): IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$') lines = adapter_content.splitlines() import_lines = [ln for ln in lines if IMPORT_RE.match(ln)] +# A prose pointer is any line naming AGENTS.md that is not itself an import +# line — an inert `@AGENTS.md` in a provider that resolves no imports points +# a reader at nothing. +pointer_lines = [ln for ln in lines if not IMPORT_RE.match(ln) and "AGENTS.md" in ln] if no_import_syntax: - has_reference = "AGENTS.md" in adapter_content + has_reference = bool(pointer_lines) else: - has_reference = bool(import_lines) or "AGENTS.md" in adapter_content + has_reference = bool(import_lines) if not has_reference: has_fail = True print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}") if no_import_syntax: - print(" Why: This provider has no import syntax, so the adapter must at least mention AGENTS.md as a text pointer.") + print(" Why: This provider resolves no cross-file import, so the adapter must point at AGENTS.md in prose; an `@AGENTS.md` line here is inert text.") print(" Fix: Add a sentence like \"See AGENTS.md at the repo root for shared conventions.\"") else: - print(" Why: A thin adapter must import AGENTS.md (e.g. `@AGENTS.md`) rather than silently omitting it.") - print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line.") + print(" Why: A thin adapter must import AGENTS.md with an `@AGENTS.md` line; merely naming the file in prose defers nothing.") + print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line, or pass --no-import-syntax if this provider resolves no imports.") print() # --- Duplication check --- @@ -132,7 +149,7 @@ if non_blank_count > max_lines: has_fail = True print(f"FAIL Adapter is not thin — {adapter_path}") print(f" Why: {non_blank_count} non-blank lines exceeds the {max_lines}-line threshold for a thin adapter.") - print(" Fix: Move provider-agnostic content into AGENTS.md; keep only genuinely provider-specific additions here.") + print(" Fix: Delete the lines already covered by AGENTS.md; keep only genuinely provider-specific additions here.") print() if has_fail: diff --git a/plugins/core/.apm/skills/provider-adapter-author/tests/validate-adapter.bats b/plugins/core/.apm/skills/provider-adapter-author/tests/validate-adapter.bats index 3b5252c..e1277aa 100644 --- a/plugins/core/.apm/skills/provider-adapter-author/tests/validate-adapter.bats +++ b/plugins/core/.apm/skills/provider-adapter-author/tests/validate-adapter.bats @@ -115,6 +115,51 @@ EOF assert_output --partial "no reference" } +@test "the two --no-import-syntax branches disagree: a text-pointer-only adapter fails in default mode" { + ADAPTER="$TMPDIR/copilot-instructions.md" + cat > "$ADAPTER" <<'EOF' +See AGENTS.md at the repo root for setup, style, and testing conventions. + +## Copilot-specific +Prefer inline suggestions over chat for one-line edits. +EOF + run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD" + assert_failure + assert_output --partial "no reference" + + run bash "$SCRIPT" --no-import-syntax "$ADAPTER" "$AGENTS_MD" + assert_success +} + +@test "with --no-import-syntax, an inert @AGENTS.md line alone is not a prose pointer" { + ADAPTER="$TMPDIR/copilot-instructions.md" + cat > "$ADAPTER" <<'EOF' +@AGENTS.md + +## Copilot-specific +Prefer inline suggestions over chat for one-line edits. +EOF + run bash "$SCRIPT" --no-import-syntax "$ADAPTER" "$AGENTS_MD" + assert_failure + assert_output --partial "no reference" +} + +@test "--max-lines as the final argument reports a real error instead of failing silently" { + ADAPTER="$TMPDIR/CLAUDE.md" + echo "@AGENTS.md" > "$ADAPTER" + run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD" --max-lines + assert_failure + assert_output --partial "--max-lines requires a value" +} + +@test "--max-lines rejects a non-numeric value with a real error" { + ADAPTER="$TMPDIR/CLAUDE.md" + echo "@AGENTS.md" > "$ADAPTER" + run bash "$SCRIPT" --max-lines abc "$ADAPTER" "$AGENTS_MD" + assert_failure + assert_output --partial "non-negative integer" +} + @test "--help exits 0 and documents usage" { run bash "$SCRIPT" --help assert_success diff --git a/plugins/core/skills/agentsmd-audit/README.md b/plugins/core/skills/agentsmd-audit/README.md index 658df6f..dec17e6 100644 --- a/plugins/core/skills/agentsmd-audit/README.md +++ b/plugins/core/skills/agentsmd-audit/README.md @@ -33,6 +33,6 @@ hand-edit made outside `agentsmd-author` — the audit is what confirms the resu | `tests/validate-drift.bats` | (source-only) Bats test suite for `scripts/validate-drift.sh` | Rows marked **(source-only)** exist in the authoring source (`.apm/skills/agentsmd-audit/`) but are -not present in an installed plugin: `scripts/sync-plugin-content.sh` strips `//tests` -when it generates the flat mirror, because these are dev-time fixtures no plugin host needs to -discover (ADR-0017). Run them from a repo checkout, not from an install. +not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips +`//tests` when it generates the flat mirror, because these are dev-time fixtures no +plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install. diff --git a/plugins/core/skills/agentsmd-audit/SKILL.md b/plugins/core/skills/agentsmd-audit/SKILL.md index 8d578d4..e852ebd 100644 --- a/plugins/core/skills/agentsmd-audit/SKILL.md +++ b/plugins/core/skills/agentsmd-audit/SKILL.md @@ -1,10 +1,10 @@ --- name: agentsmd-audit description: > - Use when the user wants a repo's AGENTS.md audited — "audit this AGENTS.md", - "is this AGENTS.md safe to commit" — or after a hand-edit outside - `agentsmd-author`. Reports secrets, structure and drift; never edits. - Not for CLAUDE.md or provider files -> `provider-adapter-author`. + Use when the user wants a repo's AGENTS.md audited for secrets, structure + and drift — "is this AGENTS.md safe to commit" — or after a hand-edit + outside `agentsmd-author`. + Not converting a provider file -> `provider-adapter-author`. Not writing AGENTS.md -> `agentsmd-author`. allowed-tools: Bash Read metadata: @@ -31,7 +31,7 @@ bash scripts/validate-structure.sh bash scripts/validate-drift.sh ``` -Each script walks the repo for every `AGENTS.md` file (root and nested, excluding `.git`, `node_modules`, `vendor`, and similar) and prints `FAIL`/`INFO`/`SUGGESTION` lines with `Why`/`Fix` (or `Note`) per finding. A nonzero exit means at least one FAIL was found in that dimension. If a script cannot execute (`python3` unavailable, Bash denied), fall back to manual review: scan for real-looking credentials, check common sections are present, and spot-check a few referenced commands/paths by hand. Grade a manual finding the way the scripts grade theirs: a missing common section (e.g. no "Security" heading) is informational, not a failure — not every repo needs every section from the checklist. Only flag a FAIL when the file is empty, entirely unfilled placeholder text, or contains a real embedded secret/stale reference. +Each script walks the repo for every `AGENTS.md` file (root and nested, excluding `.git`, `node_modules`, `vendor`, and similar) and prints `FAIL` lines, plus `INFO`/`SUGGESTION` where applicable, with `Why`/`Fix` (or `Note`) per finding. A nonzero exit means at least one FAIL was found in that dimension. If a script cannot execute (`python3` unavailable, Bash denied), fall back to manual review: scan for real-looking credentials, check common sections are present, and spot-check a few referenced commands/paths by hand. Grade a manual finding the way the scripts grade theirs: a missing common section (e.g. no "Security" heading) is informational, not a failure — not every repo needs every section from the checklist. Only flag a FAIL when the file is empty, entirely unfilled placeholder text, or contains a real embedded secret/stale reference. ## Step 2 — Report @@ -43,16 +43,4 @@ Checked: secrets · structure · drift Then output only findings that were found, in this order within a repo: `### Secrets`, `### Structure`, `### Drift`. Omit a dimension heading entirely if it produced nothing — its absence confirms it passed. Report each finding verbatim as emitted by the scripts (they already carry file:line, Why/Fix or Note). -Close with a result block: - -```text -## Result - -PASS -PASS · P info -PASS (N suggestions) · P info -FAIL (N fails) -FAIL (N fails) · P info -``` - -INFO and SUGGESTION findings are observational — they never flip PASS to FAIL. Do not fix anything — this skill reports and proposes only. Point the user to `agentsmd-author` to apply fixes. +Close with a `## Result` block holding one line: `PASS`, `PASS (N suggestions)`, or `FAIL (N fails · M suggestions)`, each optionally followed by ` · P info`. Omit the suggestion count when there are none, and omit `· P info` when there are none. INFO and SUGGESTION findings are observational — they never flip PASS to FAIL. Do not fix anything — this skill reports and proposes only. Point the user to `agentsmd-author` to apply fixes. diff --git a/plugins/core/skills/agentsmd-author/SKILL.md b/plugins/core/skills/agentsmd-author/SKILL.md index 6dc9d1f..a9b35f3 100644 --- a/plugins/core/skills/agentsmd-author/SKILL.md +++ b/plugins/core/skills/agentsmd-author/SKILL.md @@ -3,7 +3,7 @@ name: agentsmd-author description: > Use when the user wants a repo's AGENTS.md written or updated, root or nested, including "document this for AI coding tools". Writes only verified - conventions. Not review-only -> `agentsmd-audit`. Not for CLAUDE.md -> + conventions. Not review-only -> `agentsmd-audit`. Not converting CLAUDE.md -> `provider-adapter-author`. allowed-tools: Bash Read Write Edit metadata: @@ -36,8 +36,8 @@ AGENTS.md has no required schema. Use only sections that reflect something real ## Step 4 — Check for an existing provider file -Look for `CLAUDE.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, or similar in the target repo. If one exists and now duplicates content the AGENTS.md you just wrote/updated already owns, invoke the `provider-adapter-author` skill on it to reconcile. +Look for `CLAUDE.md`, `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, or similar in the target repo. If one exists, invoke the `provider-adapter-author` skill on it to reconcile — whether it duplicates content the AGENTS.md you just wrote/updated now owns, or is merely stale or missing a pointer to it. Never edit it yourself in either case. ## Step 5 — Audit and report -Invoke the `agentsmd-audit` skill directly on the AGENTS.md file(s) you just wrote or updated. This closeout is mandatory, not optional, even when the change looks trivial — never sign the work off on your own judgment. Resolve any FAIL findings before considering the work done — re-invoke this skill's own writing steps to fix them, then re-run the audit, same as any other close-the-loop check. Report what was created/changed, whether a provider file was reconciled, and the audit's final result. +Invoke the `agentsmd-audit` skill on the target repo root — its validators take a `` and walk the tree for every AGENTS.md themselves; there is no per-file entry point. This closeout is mandatory, not optional, even when the change looks trivial — never sign the work off on your own judgment. Resolve any FAIL findings before considering the work done — re-invoke this skill's own writing steps to fix them, then re-run the audit, same as any other close-the-loop check. Report what was created/changed, whether a provider file was reconciled, and the audit's final result. diff --git a/plugins/core/skills/provider-adapter-author/README.md b/plugins/core/skills/provider-adapter-author/README.md index 1f665e0..9401197 100644 --- a/plugins/core/skills/provider-adapter-author/README.md +++ b/plugins/core/skills/provider-adapter-author/README.md @@ -31,6 +31,6 @@ Provide the path to the provider-specific file to convert (and the target repo r | `tests/validate-adapter.bats` | (source-only) Bats test suite for `scripts/validate-adapter.sh` | Rows marked **(source-only)** exist in the authoring source (`.apm/skills/provider-adapter-author/`) -but are not present in an installed plugin: `scripts/sync-plugin-content.sh` strips +but are not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips `//tests` when it generates the flat mirror, because these are dev-time fixtures no plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install. diff --git a/plugins/core/skills/provider-adapter-author/SKILL.md b/plugins/core/skills/provider-adapter-author/SKILL.md index 2de7fe5..76111c7 100644 --- a/plugins/core/skills/provider-adapter-author/SKILL.md +++ b/plugins/core/skills/provider-adapter-author/SKILL.md @@ -2,7 +2,8 @@ name: provider-adapter-author description: > Use when a provider file (CLAUDE.md, .cursor rules, copilot-instructions) - duplicating the repo's AGENTS.md should be cut to a thin adapter. + duplicating the repo's AGENTS.md should be cut to a thin adapter — "make + CLAUDE.md just import AGENTS.md". Not writing the AGENTS file -> `agentsmd-author`. Not auditing the AGENTS file -> `agentsmd-audit`. allowed-tools: Bash Read Edit Write @@ -16,7 +17,6 @@ metadata: ## Gotchas - Assume a provider has no cross-file import mechanism until you have confirmed it has one. Claude Code is the exception, not the rule: a `CLAUDE.md` may consist of nothing but `@path` lines, while the same `@AGENTS.md` line in a Cursor rule or a Copilot instructions file is inert text no tool resolves. Pass `--no-import-syntax` to `scripts/validate-adapter.sh` for those providers. -- Works standalone or composed-into by `agentsmd-author` — behave identically either way; don't assume a caller skill exists. ## Step 1 — Detect @@ -43,7 +43,7 @@ Run the bundled check before finishing — this is the skill's own closeout gate bash scripts/validate-adapter.sh [--no-import-syntax] [--max-lines N] ``` -Fix any `FAIL` by editing the provider file, and re-run until it exits `0`. The size `FAIL` advises moving provider-agnostic content into `AGENTS.md`; disregard that half of its wording and delete the redundant lines instead. +Fix any `FAIL` by editing the provider file, and re-run until it exits `0`. ## Step 4 — Report diff --git a/plugins/core/skills/provider-adapter-author/scripts/validate-adapter.sh b/plugins/core/skills/provider-adapter-author/scripts/validate-adapter.sh index a94d112..513ef1f 100755 --- a/plugins/core/skills/provider-adapter-author/scripts/validate-adapter.sh +++ b/plugins/core/skills/provider-adapter-author/scripts/validate-adapter.sh @@ -16,10 +16,15 @@ Arguments: Options: --no-import-syntax The target provider has no native cross-file import - mechanism. Accept a plain-text pointer mention of - "AGENTS.md" instead of requiring an @import-style line. + mechanism. Require a plain-text pointer line naming + "AGENTS.md" instead of an @import-style line; an + @AGENTS.md line alone does not satisfy it, because + such a provider never resolves it. Without this flag + an actual @import line is required, and naming + AGENTS.md in prose alone does not satisfy it. --max-lines N Max non-blank lines allowed in the adapter file before - it's considered no longer "thin". Default: 60. + it's considered no longer "thin". Must be a + non-negative integer. Default: 60. --help, -h Show this help and exit 0. Exit codes: @@ -44,7 +49,15 @@ while [[ $# -gt 0 ]]; do shift ;; --max-lines) - MAX_LINES="${2:-}" + if [[ $# -lt 2 ]]; then + echo "Error: --max-lines requires a value (a non-negative integer)." >&2 + exit 1 + fi + MAX_LINES="$2" + if [[ ! "$MAX_LINES" =~ ^[0-9]+$ ]]; then + echo "Error: --max-lines expects a non-negative integer, got '$MAX_LINES'." >&2 + exit 1 + fi shift 2 ;; *) @@ -94,21 +107,25 @@ if not adapter_content.strip(): IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$') lines = adapter_content.splitlines() import_lines = [ln for ln in lines if IMPORT_RE.match(ln)] +# A prose pointer is any line naming AGENTS.md that is not itself an import +# line — an inert `@AGENTS.md` in a provider that resolves no imports points +# a reader at nothing. +pointer_lines = [ln for ln in lines if not IMPORT_RE.match(ln) and "AGENTS.md" in ln] if no_import_syntax: - has_reference = "AGENTS.md" in adapter_content + has_reference = bool(pointer_lines) else: - has_reference = bool(import_lines) or "AGENTS.md" in adapter_content + has_reference = bool(import_lines) if not has_reference: has_fail = True print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}") if no_import_syntax: - print(" Why: This provider has no import syntax, so the adapter must at least mention AGENTS.md as a text pointer.") + print(" Why: This provider resolves no cross-file import, so the adapter must point at AGENTS.md in prose; an `@AGENTS.md` line here is inert text.") print(" Fix: Add a sentence like \"See AGENTS.md at the repo root for shared conventions.\"") else: - print(" Why: A thin adapter must import AGENTS.md (e.g. `@AGENTS.md`) rather than silently omitting it.") - print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line.") + print(" Why: A thin adapter must import AGENTS.md with an `@AGENTS.md` line; merely naming the file in prose defers nothing.") + print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line, or pass --no-import-syntax if this provider resolves no imports.") print() # --- Duplication check --- @@ -132,7 +149,7 @@ if non_blank_count > max_lines: has_fail = True print(f"FAIL Adapter is not thin — {adapter_path}") print(f" Why: {non_blank_count} non-blank lines exceeds the {max_lines}-line threshold for a thin adapter.") - print(" Fix: Move provider-agnostic content into AGENTS.md; keep only genuinely provider-specific additions here.") + print(" Fix: Delete the lines already covered by AGENTS.md; keep only genuinely provider-specific additions here.") print() if has_fail: