refactor(skills): retrofit the corpus to the ADR-0020 context contract #129
@@ -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` |
|
| `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
|
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 `<category>/<name>/tests`
|
not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips
|
||||||
when it generates the flat mirror, because these are dev-time fixtures no plugin host needs to
|
`<category>/<name>/tests` when it generates the flat mirror, because these are dev-time fixtures no
|
||||||
discover (ADR-0017). Run them from a repo checkout, not from an install.
|
plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
name: agentsmd-audit
|
name: agentsmd-audit
|
||||||
description: >
|
description: >
|
||||||
Use when the user wants a repo's AGENTS.md audited — "audit this AGENTS.md",
|
Use when the user wants a repo's AGENTS.md audited for secrets, structure
|
||||||
"is this AGENTS.md safe to commit" — or after a hand-edit outside
|
and drift — "is this AGENTS.md safe to commit" — or after a hand-edit
|
||||||
`agentsmd-author`. Reports secrets, structure and drift; never edits.
|
outside `agentsmd-author`.
|
||||||
Not for CLAUDE.md or provider files -> `provider-adapter-author`.
|
Not converting a provider file -> `provider-adapter-author`.
|
||||||
Not writing AGENTS.md -> `agentsmd-author`.
|
Not writing AGENTS.md -> `agentsmd-author`.
|
||||||
allowed-tools: Bash Read
|
allowed-tools: Bash Read
|
||||||
metadata:
|
metadata:
|
||||||
@@ -31,7 +31,7 @@ bash scripts/validate-structure.sh <repo-root>
|
|||||||
bash scripts/validate-drift.sh <repo-root>
|
bash scripts/validate-drift.sh <repo-root>
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
## 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).
|
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:
|
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.
|
||||||
|
|
||||||
```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.
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: agentsmd-author
|
|||||||
description: >
|
description: >
|
||||||
Use when the user wants a repo's AGENTS.md written or updated, root or
|
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
|
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`.
|
`provider-adapter-author`.
|
||||||
allowed-tools: Bash Read Write Edit
|
allowed-tools: Bash Read Write Edit
|
||||||
metadata:
|
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
|
## 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
|
## 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 `<repo-root>` 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.
|
||||||
|
|||||||
@@ -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` |
|
| `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/`)
|
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
|
||||||
`<category>/<name>/tests` when it generates the flat mirror, because these are dev-time fixtures no
|
`<category>/<name>/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.
|
plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
name: provider-adapter-author
|
name: provider-adapter-author
|
||||||
description: >
|
description: >
|
||||||
Use when a provider file (CLAUDE.md, .cursor rules, copilot-instructions)
|
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 writing the AGENTS file -> `agentsmd-author`.
|
||||||
Not auditing the AGENTS file -> `agentsmd-audit`.
|
Not auditing the AGENTS file -> `agentsmd-audit`.
|
||||||
allowed-tools: Bash Read Edit Write
|
allowed-tools: Bash Read Edit Write
|
||||||
@@ -16,7 +17,6 @@ metadata:
|
|||||||
## Gotchas
|
## 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.
|
- 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
|
## 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] <adapter-file> <agents-md-file>
|
bash scripts/validate-adapter.sh [--no-import-syntax] [--max-lines N] <adapter-file> <agents-md-file>
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
## Step 4 — Report
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,15 @@ Arguments:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
--no-import-syntax The target provider has no native cross-file import
|
--no-import-syntax The target provider has no native cross-file import
|
||||||
mechanism. Accept a plain-text pointer mention of
|
mechanism. Require a plain-text pointer line naming
|
||||||
"AGENTS.md" instead of requiring an @import-style line.
|
"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
|
--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.
|
--help, -h Show this help and exit 0.
|
||||||
|
|
||||||
Exit codes:
|
Exit codes:
|
||||||
@@ -44,7 +49,15 @@ while [[ $# -gt 0 ]]; do
|
|||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--max-lines)
|
--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
|
shift 2
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -94,21 +107,25 @@ if not adapter_content.strip():
|
|||||||
IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$')
|
IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$')
|
||||||
lines = adapter_content.splitlines()
|
lines = adapter_content.splitlines()
|
||||||
import_lines = [ln for ln in lines if IMPORT_RE.match(ln)]
|
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:
|
if no_import_syntax:
|
||||||
has_reference = "AGENTS.md" in adapter_content
|
has_reference = bool(pointer_lines)
|
||||||
else:
|
else:
|
||||||
has_reference = bool(import_lines) or "AGENTS.md" in adapter_content
|
has_reference = bool(import_lines)
|
||||||
|
|
||||||
if not has_reference:
|
if not has_reference:
|
||||||
has_fail = True
|
has_fail = True
|
||||||
print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}")
|
print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}")
|
||||||
if no_import_syntax:
|
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.\"")
|
print(" Fix: Add a sentence like \"See AGENTS.md at the repo root for shared conventions.\"")
|
||||||
else:
|
else:
|
||||||
print(" Why: A thin adapter must import AGENTS.md (e.g. `@AGENTS.md`) rather than silently omitting it.")
|
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.")
|
print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line, or pass --no-import-syntax if this provider resolves no imports.")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
# --- Duplication check ---
|
# --- Duplication check ---
|
||||||
@@ -132,7 +149,7 @@ if non_blank_count > max_lines:
|
|||||||
has_fail = True
|
has_fail = True
|
||||||
print(f"FAIL Adapter is not thin — {adapter_path}")
|
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(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()
|
print()
|
||||||
|
|
||||||
if has_fail:
|
if has_fail:
|
||||||
|
|||||||
@@ -115,6 +115,51 @@ EOF
|
|||||||
assert_output --partial "no reference"
|
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" {
|
@test "--help exits 0 and documents usage" {
|
||||||
run bash "$SCRIPT" --help
|
run bash "$SCRIPT" --help
|
||||||
assert_success
|
assert_success
|
||||||
|
|||||||
@@ -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` |
|
| `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
|
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 `<category>/<name>/tests`
|
not present in an installed plugin: the repo's `scripts/sync-plugin-content.sh` strips
|
||||||
when it generates the flat mirror, because these are dev-time fixtures no plugin host needs to
|
`<category>/<name>/tests` when it generates the flat mirror, because these are dev-time fixtures no
|
||||||
discover (ADR-0017). Run them from a repo checkout, not from an install.
|
plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
name: agentsmd-audit
|
name: agentsmd-audit
|
||||||
description: >
|
description: >
|
||||||
Use when the user wants a repo's AGENTS.md audited — "audit this AGENTS.md",
|
Use when the user wants a repo's AGENTS.md audited for secrets, structure
|
||||||
"is this AGENTS.md safe to commit" — or after a hand-edit outside
|
and drift — "is this AGENTS.md safe to commit" — or after a hand-edit
|
||||||
`agentsmd-author`. Reports secrets, structure and drift; never edits.
|
outside `agentsmd-author`.
|
||||||
Not for CLAUDE.md or provider files -> `provider-adapter-author`.
|
Not converting a provider file -> `provider-adapter-author`.
|
||||||
Not writing AGENTS.md -> `agentsmd-author`.
|
Not writing AGENTS.md -> `agentsmd-author`.
|
||||||
allowed-tools: Bash Read
|
allowed-tools: Bash Read
|
||||||
metadata:
|
metadata:
|
||||||
@@ -31,7 +31,7 @@ bash scripts/validate-structure.sh <repo-root>
|
|||||||
bash scripts/validate-drift.sh <repo-root>
|
bash scripts/validate-drift.sh <repo-root>
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
## 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).
|
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:
|
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.
|
||||||
|
|
||||||
```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.
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ name: agentsmd-author
|
|||||||
description: >
|
description: >
|
||||||
Use when the user wants a repo's AGENTS.md written or updated, root or
|
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
|
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`.
|
`provider-adapter-author`.
|
||||||
allowed-tools: Bash Read Write Edit
|
allowed-tools: Bash Read Write Edit
|
||||||
metadata:
|
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
|
## 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
|
## 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 `<repo-root>` 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.
|
||||||
|
|||||||
@@ -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` |
|
| `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/`)
|
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
|
||||||
`<category>/<name>/tests` when it generates the flat mirror, because these are dev-time fixtures no
|
`<category>/<name>/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.
|
plugin host needs to discover (ADR-0017). Run them from a repo checkout, not from an install.
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
name: provider-adapter-author
|
name: provider-adapter-author
|
||||||
description: >
|
description: >
|
||||||
Use when a provider file (CLAUDE.md, .cursor rules, copilot-instructions)
|
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 writing the AGENTS file -> `agentsmd-author`.
|
||||||
Not auditing the AGENTS file -> `agentsmd-audit`.
|
Not auditing the AGENTS file -> `agentsmd-audit`.
|
||||||
allowed-tools: Bash Read Edit Write
|
allowed-tools: Bash Read Edit Write
|
||||||
@@ -16,7 +17,6 @@ metadata:
|
|||||||
## Gotchas
|
## 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.
|
- 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
|
## 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] <adapter-file> <agents-md-file>
|
bash scripts/validate-adapter.sh [--no-import-syntax] [--max-lines N] <adapter-file> <agents-md-file>
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
## Step 4 — Report
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,15 @@ Arguments:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
--no-import-syntax The target provider has no native cross-file import
|
--no-import-syntax The target provider has no native cross-file import
|
||||||
mechanism. Accept a plain-text pointer mention of
|
mechanism. Require a plain-text pointer line naming
|
||||||
"AGENTS.md" instead of requiring an @import-style line.
|
"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
|
--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.
|
--help, -h Show this help and exit 0.
|
||||||
|
|
||||||
Exit codes:
|
Exit codes:
|
||||||
@@ -44,7 +49,15 @@ while [[ $# -gt 0 ]]; do
|
|||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--max-lines)
|
--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
|
shift 2
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -94,21 +107,25 @@ if not adapter_content.strip():
|
|||||||
IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$')
|
IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$')
|
||||||
lines = adapter_content.splitlines()
|
lines = adapter_content.splitlines()
|
||||||
import_lines = [ln for ln in lines if IMPORT_RE.match(ln)]
|
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:
|
if no_import_syntax:
|
||||||
has_reference = "AGENTS.md" in adapter_content
|
has_reference = bool(pointer_lines)
|
||||||
else:
|
else:
|
||||||
has_reference = bool(import_lines) or "AGENTS.md" in adapter_content
|
has_reference = bool(import_lines)
|
||||||
|
|
||||||
if not has_reference:
|
if not has_reference:
|
||||||
has_fail = True
|
has_fail = True
|
||||||
print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}")
|
print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}")
|
||||||
if no_import_syntax:
|
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.\"")
|
print(" Fix: Add a sentence like \"See AGENTS.md at the repo root for shared conventions.\"")
|
||||||
else:
|
else:
|
||||||
print(" Why: A thin adapter must import AGENTS.md (e.g. `@AGENTS.md`) rather than silently omitting it.")
|
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.")
|
print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line, or pass --no-import-syntax if this provider resolves no imports.")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
# --- Duplication check ---
|
# --- Duplication check ---
|
||||||
@@ -132,7 +149,7 @@ if non_blank_count > max_lines:
|
|||||||
has_fail = True
|
has_fail = True
|
||||||
print(f"FAIL Adapter is not thin — {adapter_path}")
|
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(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()
|
print()
|
||||||
|
|
||||||
if has_fail:
|
if has_fail:
|
||||||
|
|||||||
Reference in New Issue
Block a user