68 Commits

Author SHA1 Message Date
Seth Hobson 1533e7787b feat: add the Pi harness (pi.dev) as a sixth generated target (#707)
* feat(pi): register the Pi harness in capabilities, model aliases, and tool maps

* feat(pi): add the Pi adapter (skills, prompt templates, subagent-extension agents)

* feat(pi): generate the .pi tree via make generate HARNESS=pi

* feat(pi): validate the generated .pi tree

* feat(pi): gardener reports stale .pi artifacts

* feat(pi): make install-pi symlinks the .pi tree into the Pi config dir

* test(pi): real-CLI smoke tests via token-free slash expansion; install pi in CI

* test(pi): override every Anthropic credential variable in the smoke env

* docs: add the Pi harness everywhere the harness list appears

* fix(pi): close the final-review findings (CI type-check, base URL override, validator gap, docs)

* docs(pi): align harness-count wording and the no-billing explanation

Claude-Session: https://claude.ai/code/session_01DZazzWVyb8MxPCuLC1w5Qo

* fix(pi): scope clean and prune to the adapter-owned .pi subtrees; tighten filename checks

Claude-Session: https://claude.ai/code/session_01DZazzWVyb8MxPCuLC1w5Qo
2026-09-13 09:51:18 -04:00
Max Freedom Pollard 9433535cf4 fix(adapters): quote YAML scalars in OpenCode and Copilot frontmatter (#700)
* fix(adapters): quote YAML scalars in OpenCode and Copilot frontmatter

`_opencode_frontmatter` (tools/adapters/opencode.py:132) writes every scalar
bare, and `_copilot_frontmatter` (tools/adapters/copilot.py:32) quotes only
pure numbers and lowercase reserved words via `_needs_yaml_quoting`. Source
frontmatter that is correctly quoted therefore loses its quotes on the way
out: `description: "Manage track lifecycle: archive, restore"` becomes
`description: Manage track lifecycle: archive, restore`, which PyYAML
rejects, and `argument-hint: "[--archive | --list]"` becomes a bare `[...]`
that parses as a list instead of a string. Copilot also stringified
mapping-valued fields as a Python dict repr because it had no dict branch.

Generating every plugin from main and running `yaml.safe_load` over the
frontmatter: OpenCode emits 8 unparseable and 12 mistyped blocks, Copilot 30
and 24. Codex and Antigravity emit none, because both already route scalars
through a private `_yaml_scalar` helper that is duplicated verbatim between
them.

Move that helper to tools/adapters/base.py as `yaml_scalar`, import it in all
four adapters, and give Copilot the dict branch Antigravity already has.
Codex and Antigravity output is byte identical before and after; OpenCode and
Copilot drop to zero unparseable and zero mistyped. Adds a
`TestFrontmatterYamlSafety` class that parses emitted frontmatter with PyYAML
rather than the repo's tolerant `parse_frontmatter`, which is what let this
through the existing validators.

* adapters: quote flow delimiters and implicit numerics in frontmatter

`_yaml_flow_scalar` at tools/adapters/antigravity.py:68 quoted a flow-sequence item only when it contained `,` or `]`, and `yaml_scalar` rejects `[`, `{` and `}` only in the leading position, so a value such as `a {b` was emitted bare as `tools: [a {b]`. PyYAML raises `ParserError: while parsing a flow sequence, expected ',' or ']', but got '{'` on that line. The check now covers every character YAML treats as structural inside a flow collection: `[`, `]`, `{`, `}` and `,`. Codex, Copilot and OpenCode render lists as block sequences, where those characters are legal inside a plain scalar, so none of them needed the same widening.

`yaml_scalar` at tools/adapters/base.py:315 tested `s[:1].isdigit()` for number-likeness, which misses every implicit number that opens with `+` or `.`. Feeding the helper a table of those forms and loading the result with `yaml.safe_load` returned numbers rather than strings for twelve of them: `+1`, `+3` and `+0x1A` as ints, `+1_000` as 1000, `+1:30` as the sexagesimal int 90, `.0` and `.5` as floats, `.inf`, `.INF` and `+.inf` as float infinity, and `.nan` and `.NaN` as float not-a-number. A YAML 1.2 loader additionally reads `+.5` as a float, so a signed bare fraction is quoted too. A new `_YAML_IMPLICIT_NUMBER` pattern quotes an optional sign followed by an optional dot and a digit, or an optional sign followed by a dot and an inf or nan spelling, which reaches all four adapters at once because they share the helper. A dot or plus in front of a non-number, `.gitignore`, `.info` or `+abc`, still emits bare.

`test_antigravity_emits_parseable_frontmatter` at tools/tests/test_adapters.py:1502 filtered the emitted paths to `.md` and parsed each one, but its `_ambiguous_plugin` fixture holds a single command and Antigravity writes commands as `.toml`, so the list was always empty and the test passed without parsing any frontmatter. It now builds a one-skill plugin through a new `_ambiguous_skill_plugin` helper, asserts at least one Markdown artifact was emitted, and checks the loaded description, argument hint and version.

New round-trip tests cover the implicit numeric forms through `yaml_scalar`, the flow delimiters through the Antigravity emitter, and every hostile shape through all four frontmatter emitters as scalar, list item and mapping value at once. Each fails on the previous commit and passes here. Generating all 92 plugins for all five harnesses before and after this change gives byte identical output across 3061 files, so no content in the repository today hits either rule. `make validate STRICT=1` still reports `OK: no issues across 5 harness(es).`, `make garden` still reports `0 error(s), 18 warning(s)`, `make lint` passes ruff check, ruff format and ty, and `make test` goes from 615 to 619 passed.
2026-09-13 07:37:10 -04:00
dependabot[bot] b7ca56eee2 deps(yt-design-extractor): bump the python-minor-and-patch group (#698)
Bumps the python-minor-and-patch group in /tools/yt-design-extractor with 2 updates: [torch](https://github.com/pytorch/pytorch) and [torchvision](https://github.com/pytorch/vision).


Updates `torch` from 2.13.0 to 2.14.0
- [Release notes](https://github.com/pytorch/pytorch/releases)
- [Changelog](https://github.com/pytorch/pytorch/blob/main/RELEASE.md)
- [Commits](https://github.com/pytorch/pytorch/compare/v2.13.0...v2.14.0)

Updates `torchvision` from 0.28.0 to 0.29.0
- [Release notes](https://github.com/pytorch/vision/releases)
- [Commits](https://github.com/pytorch/vision/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: torch
  dependency-version: 2.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-minor-and-patch
- dependency-name: torchvision
  dependency-version: 0.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-13 07:37:07 -04:00
Seth Hobson a30778f8c4 fix: issue triage — grounded-vault skill, $ARGUMENTS framing, agent copy reconciliation (#694)
* feat(garden): warn on unframed $ARGUMENTS in commands

Claude Code substitutes $ARGUMENTS textually and every command runs with tool
access, so argument text copied from an issue or a log can carry instructions
the agent acts on. The new ARGUMENTS_UNFRAMED check (`--check arguments`)
flags a command that interpolates the token into prompt text with no framing:
no <user_request> block around it, no nearby sentence saying the text is data
rather than instructions, and not a backticked reference to the value.
Fenced code blocks are skipped. One warning per command lists the lines.

docs/authoring.md gains "Treat $ARGUMENTS as data" with the block and inline
shapes; CONTRIBUTING's portability checklist points at it.

Refs #688

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* fix(commands): frame $ARGUMENTS as data in 39 commands

The 37 commands that used the bare "## Requirements / $ARGUMENTS" template now
wrap the value in a <user_request> block followed by the clause that it is
data supplied by the caller, not instructions that override the command.
git-pr-workflows/onboard and dgx-spark-ops/spark-preflight (the example in
the issue) are framed by hand, including the Task prompt that forwards the
workload to the subagent.

Refs #688

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* fix(agents): reconcile django-pro and deployment-engineer copies

Two of the divergent groups from #643 were strict supersets: one copy had
gained OCI and Azure Blob Storage mentions that the others never received.
api-scaffolding/django-pro and cicd-automation/deployment-engineer now carry
the fuller text, so all copies of each are identical apart from the
plugin-scoped name. AGENT_BODY_DIVERGENT drops from 11 to 9.

Refs #643

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* feat(documentation-standards): add grounded-vault skill

Teaches the raw/wiki/archive knowledge-store pattern proposed in #673: an
immutable raw/ layer, wiki/ pages whose every number, date, and quote links
to its source, an archive/ layer for superseded pages, a page header with a
git fingerprint and monitored paths so drift is one `git diff` instead of a
reread, and a commit gate. SKILL.md carries the convention (5 KB, When to
Use, workflow, gate); references/details.md carries a standard-library check
script, templates, edge cases, and the reference implementation
(llm-wiki-loop, MIT), credited to the issue author. No dependency on it.

documentation-standards goes to 1.1.0 with a description that names both
skills; catalog rows and every skill count move to 183; registries
regenerated.

Closes #673

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* fix(commands): frame the remaining inline $ARGUMENTS interpolations

The 30 inline uses across 16 commands (`Target for review: $ARGUMENTS`,
`# Fine-tune for: $ARGUMENTS`, Task prompts that forward the value) now
quote the value and say it is the caller's text, treated as data, not
instructions. ARGUMENTS_UNFRAMED is at zero on this branch.

Refs #688

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* fix(garden): framing window reaches the paragraph after a heading

A heading is followed by a blank line, so its "treat as data" clause sits two
lines below the interpolation. The window now spans three lines above and two
below. ARGUMENTS_UNFRAMED is at zero on this branch.

Refs #688

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* fix(documentation-standards): harden the vault check script per review

- link labels and paths, headings, the header block, and fenced code are
  excluded from claim scanning, so raw/adr/0007-jwt.md no longer reads as a
  claim of 0007
- numbers match as whole tokens (15 is not 150 or 2015)
- a linked source must resolve inside raw/; traversal or a missing file is
  a miss
- under --strict, a number or quotation with no raw/ link is an error
- a page without a Fingerprint is an error; an empty Monitored is allowed
- a git failure (unknown fingerprint after a history rewrite) counts as
  drift instead of being swallowed

docs/authoring.md says plainly that $ARGUMENTS framing is a mitigation and
not a security boundary; tool permissions and approval prompts remain the
control.

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* docs: round-trip rows reflect 183 skills after #673

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* docs: blank line between the two new authoring sections

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs
2026-09-01 18:36:23 -04:00
Seth Hobson c80732de69 feat: support gh skill and npx skills installers (#693)
* feat: support gh skill and npx skills installers

Both Agent Skills installers already discover every skill in this repo through
the plugins/<plugin>/skills/<skill>/ layout, so support is documentation plus a
real-CLI gate rather than a layout change.

- docs: README quick start block; docs/harnesses.md "Skills-only installers"
  (selectors, install paths, release-freeze rule, local-checkout caveat);
  docs/agent-skills.md pointer; AGENTS.md bullet; authoring note that a skill's
  name must equal its directory name
- smoke tests: gh skill local discovery, gh skill publish --dry-run spec
  validation, npx skills discovery, and skill-name uniqueness across plugins
  (both installers install under the bare skill name)
- ci: set up Node for npx and fail loudly if the runner's gh predates gh skill
- rename database-design/skills/postgresql to postgresql-table-design so the
  directory matches the frontmatter name, the one spec error the dry-run found

* test: type the smoke helper env as dict[str, str]

* fix(database-design): correct three PostgreSQL facts in postgresql-table-design

Flagged by review once the rename made the file appear new. Pre-existing
content, separate commit so it can be dropped if the rename should stay
content-free.

- UNIQUE NULLS NOT DISTINCT (...) places the clause before the column list
- the RLS example used current_user_id(), which is not a built-in; use
  current_user or an app-set setting
- foreign keys on partitioned tables work from PG11 (from) and PG12
  (referencing); triggers are only the pre-11 fallback

* refactor(database-design): split postgresql-table-design under the Codex 8 KB cap

SKILL.md keeps the rules, decision points, a When to Use section, and the
three quick-start DDL examples (7.6 KB body, 126 lines). The full data-type
catalog, table types, row-level security, constraint and index notes,
partitioning DDL, workload patterns, generated columns, extensions, and JSONB
indexing move verbatim to references/details.md. The "avoid these types" list
becomes a table. Clears the SKILL_OVER_CODEX_CAP warning this skill carried.

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* test(smoke): capture opencode agent list through a file, tighten npx parser

`opencode agent list` prints every agent's expanded permission array (about
330k lines) and exits before a pipe drains, so pipe capture intermittently
lost the alphabetically last agents (measured: 1 in 5 runs short via
subprocess pipes, 0 in 5 via a file sink). Both OpenCode tests now write
stdout to a file. The npx parser matches only the `│    <name>` line shape.

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs

* docs,ci: cover the skills installers everywhere install is documented

- docs/usage.md, docs/plugins.md, docs/architecture.md, ARCHITECTURE.md,
  README multi-harness section, docs/harnesses.md supported table, and
  CONTRIBUTING's portability checklist now name gh skill and npx skills
- docs/round-trip-results.md gains summary rows and a reproduce recipe
- docs/authoring.md: skill directory names are identities for installers
  and adapters alike, so a rename is user-visible
- CI installs GitHub CLI from the official apt repository when the runner
  build predates `gh skill`, so the job no longer depends on the image

Claude-Session: https://claude.ai/code/session_01LjJmzuuxXSwGNEYdBvsmFs
2026-09-01 18:28:17 -04:00
dependabot[bot] f12fb151f7 deps(yt-design-extractor): bump yt-dlp (#682)
Bumps the python-minor-and-patch group in /tools/yt-design-extractor with 1 update: [yt-dlp](https://github.com/yt-dlp/yt-dlp).


Updates `yt-dlp` from 2026.7.4 to 2026.8.19
- [Release notes](https://github.com/yt-dlp/yt-dlp/releases)
- [Changelog](https://github.com/yt-dlp/yt-dlp/blob/master/Changelog.md)
- [Commits](https://github.com/yt-dlp/yt-dlp/compare/2026.07.04...2026.08.19)

---
updated-dependencies:
- dependency-name: yt-dlp
  dependency-version: 2026.8.19
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-26 08:12:28 -04:00
Seth Hobson 2b49247f13 feat(garden): count and agent-divergence checks, plus tool-rewrite tests (#676)
* feat(garden): detect stale doc counts and diverged agent copies

Two checks close gaps that kept surfacing in PR review.

check_doc_counts compares the plugin/agent/skill/command totals quoted in
README.md and AGENTS.md against the live counts, at error severity. Only the
two canonical context files are scanned, because docs/ carries per-category
subtotals that legitimately differ. Plugins count marketplace entries rather
than plugins/ directories, so external git-subdir entries are included the way
the headline figure counts them. Four manual sync PRs (#522, #613, #615, #616)
existed because nothing caught this.

check_agent_divergence groups agent files by filename and compares bodies with
the plugin-namespaced frontmatter name normalized away. Without that
normalization no two copies can ever hash alike, which is why #643 read the
duplication as total divergence. Of 30 duplicated names, 19 are verbatim copies
and 11 have genuinely drifted. Verbatim copies are expected while plugins
install standalone, so they report as info; drifted bodies report as warning.

* test(adapters): pin strip_claude_tool_refs output

The method rewrites Claude tool names in Copilot command bodies and had no test
coverage, so a refactor could change its output silently. #642 did exactly that
while claiming no behavioral change: replacements lost their backticks,
tool_case=normal stopped returning 'read', and a bare `Grep` mapped to rg
instead of `grep`.

These assert the exact output for both tool_case values, both prose forms, and
every mapped tool.

* docs(contributing): rule out payment and access-control tooling in payloads

The commercial section covered funnels to paid products but not a payload that
sells something itself. #670 shipped a Telegram sales bot, USDT payment
verification, and a script granting GitHub collaborator access on payment.

* fix(garden): widen count matching and stop reporting verbatim agent copies

Review feedback on PR #676.

COUNT_RE required two digits, so a drop to single-digit totals would go
unnoticed. It now matches any decimal. It also missed `202 subagents` in the
cross-harness section of AGENTS.md, which is the same total under a different
name, so `subagents` is now an alias for the agent count.

check_agent_divergence no longer reports verbatim copies. A copy that matches
byte for byte once the namespaced name is normalized is expected, not drift,
and 19 info findings only added noise. The divergence warning still fires when
bodies actually differ.

* docs(contributing): distinguish payment machinery from payment guidance

The first wording banned 'payment processing ... tooling in a plugin payload',
which reads as barring the existing payment-processing plugin. That plugin is
Markdown-only guidance for building Stripe and PayPal integrations in the user's
own application, which was never the target.

The rule now turns on whether the payload runs a commercial transaction itself,
and names payment-processing as the reference example of what stays allowed.

* test(adapters): pin every tool mapping in both tool_case modes

Review nitpick on PR #676. The mapping loop ran only the default case. That
default is already `lower`, so the lower path was covered, but the assertion
did not say so and normal mode was pinned for Read alone.

The loop now asserts both modes for all nine tools, and a separate test pins
that the default is lower, which is what Copilot emission relies on.

* fix(garden): scope agent name normalization to the frontmatter block

Review feedback on PR #676. The substitution used a MULTILINE pattern with
count=1, which lands on the frontmatter name in every agent the repo has today
but would blank a body `name:` line in an agent whose frontmatter lacked one.

Normalization is now scoped to the opening frontmatter block, so a `name:` in
the body stays content and still counts toward a divergence. Three tests cover
differing body names, matching body names, and a file with no frontmatter.

No change to current output: still 11 divergent, 0 verbatim reported.

* fix(garden): match singular component nouns in doc counts

Review feedback on PR #676. COUNT_RE only matched plurals, so a total of one
written as `1 plugin` would not have been compared against anything.

Singular forms now resolve to the same key. Neither README.md nor AGENTS.md
contains a singular count today, so the live result is unchanged and the counts
check stays silent.

* fix(garden): treat an unreadable marketplace as an unknown plugin count

Review feedback on PR #676. A JSON syntax error in marketplace.json set the
plugin count to 0, so check_doc_counts flagged every documented plugin count as
stale and told the reader to write 0. The real parse error was reported once by
check_marketplace_consistency and buried under the noise.

The count is now None when the manifest is missing or unparseable, and the
comparison skips it. Other component counts are still checked.

* fix(garden): handle CRLF frontmatter and malformed marketplace shapes

Review feedback on PR #676, both confirmed by running them.

AGENT_FRONTMATTER_RE required LF delimiters and a newline after the closing
---, so a CRLF agent or one ending at its frontmatter got no normalization at
all and two copies read as divergent. Scoping normalization to the frontmatter
block in 4798d40 introduced that: the MULTILINE pattern it replaced matched
CRLF fine. The pattern now accepts \r?\n and a closing delimiter at EOF.

actual_counts() also assumed the manifest parsed to a mapping with a list under
plugins. A root of [] raised AttributeError and {"plugins": null} raised
TypeError, crashing the gardener rather than reporting an unknown count. The
shape is now checked before len().

Four regression tests. No repo agent uses CRLF today, so live output is
unchanged at 11 divergent.

* refactor(garden): compare agents through the shared frontmatter parser

Review rounds four and seven were both about my own frontmatter regex being
stricter than the files it reads. Rather than widen it a third time, agent
comparison now goes through parse_frontmatter, the same parser the adapters use,
and drops the plugin-namespaced name field.

A copy is judged on its frontmatter fields and body, so delimiter formatting no
longer decides drift. Verified locally across 16 input shapes: CRLF, BOM,
leading blank line, trailing space after a delimiter, closing --- at EOF, no
trailing newline, block scalars and inline lists all compare equal when only the
name differs, while body text, model tier, an added field, a differing body
name: line and files with no frontmatter still register as drift.

Real-repo output is unchanged: 11 divergent, 19 verbatim, same names and counts.

* fix(garden): read a thousands separator as one number

Found by a local battery over check_doc_counts rather than by review. COUNT_RE
matched bare digit runs, so `1,234 agents` matched the `234` and reported a
stale count of 234 at error severity. A comma-formatted total anywhere in
README.md or AGENTS.md would have failed CI with wrong advice.

The pattern now takes the whole number and strips separators before comparing,
so 1,234 reads as 1234 and is checked properly rather than skipped.

Also pinned that counts inside code fences are checked, because README.md
quotes the plugin total inside a bash fence.

* fix(garden): survive an unreadable file instead of killing the run

Pre-existing across the module, not new to this PR. Five of the seven checks
died with UnicodeDecodeError on a single non-UTF-8 file, and
check_oversized_context_files read without an encoding at all. One bad file took
down every other check's output with it.

All reads now go through read_text_or_none, which reports UNREADABLE_FILE
against that path and lets the rest of the run finish. actual_counts has no
Report to write to, so an unreadable manifest joins a malformed one as an
unknown count. Also drops the unused frontmatter binding in
check_codex_skill_caps.

Real-repo output is unchanged.

* fix(garden): keep body indentation, report an unreadable manifest, drop dead guard

Four review findings on PR #676, all confirmed by running them.

normalized_agent_text used body.strip(), so an indented body compared equal to
the same text unindented and real drift went unreported. Leading whitespace is
content in Markdown; only trailing whitespace is formatting. Now rstrip.

actual_counts read the manifest directly, so a non-UTF-8 marketplace.json
quietly became an unknown plugin count with no UNREADABLE_FILE finding. It now
takes the Report and reads through read_text_or_none like everything else.

check_dead_links kept a try/except OSError around the new reader, which already
catches OSError and returns None. Dead code, removed.

CONTRIBUTING's closing sentence narrowed the payment rule to running a
transaction, which would have permitted a tool that consumes an external payment
result and only flips access. Verification, entitlement checks and access
changes are now each covered on their own.

Battery re-run at 18 cases, all pass. Real-repo output unchanged at 11 divergent.

* fix(garden): keep indentation without frontmatter, reject malformed manifest entries

Three findings on PR #676, all reproduced first.

normalized_agent_text stripped leading whitespace before deciding whether
frontmatter existed, so two frontmatter-free agents differing only by
indentation compared equal. Blank lines ahead of a frontmatter block are
formatting; ahead of anything else they are body content. Same mistake as the
body.strip() fix in the previous commit, one level up.

A plugins list holding a non-object entry was counted as valid, letting garbage
drive an error-severity stale-count finding. The count is unknown unless every
entry is an object.

check_marketplace_consistency then crashed outright on that input with
AttributeError, and on a non-object root as well. Both now report
MARKETPLACE_SHAPE and carry on. That crash predates this PR.

* fix(garden): keep ty clean after the manifest shape guard

The isinstance narrowing added in aaf76f6 turned the entry from Any into
dict[Unknown, Unknown], so .get("name") failed with invalid-argument-type. Two
ty errors, which I pushed without reading the output. The entry is cast once
after the guard.

make lint is clean: ruff check, ruff format --check and ty all pass.

* fix(garden): match CRLF against LF, validate name, test the real Copilot path

Three findings on PR #676.

parse_frontmatter strips a leading newline but leaves the carriage return, so a
CRLF copy never matched its LF twin and reported false drift. My own CRLF test
missed it because it compared CRLF against CRLF, which passes without
normalizing anything. Body line endings are normalized now, newlines stripped
but never spaces so indentation stays content, and the test mixes the two
endings. A second test proves normalizing does not flatten real drift.

check_marketplace_consistency added entry['name'] to a set without checking its
type, so a list-valued name raised TypeError. It now reports MARKETPLACE_SHAPE.

test_lower_is_the_default_tool_case only protected the method default, while
Copilot's two call sites pass tool_case explicitly, so generated commands could
regress with the test green. Replaced with one that emits a command through
CopilotAdapter and asserts the rewritten body.

* fix(garden): strip closing-delimiter residue, assert Copilot output per file

Two findings on PR #676.

parse_frontmatter leaves the spaces from a `--- ` closing line at the head of
the body, so an agent whose closing delimiter carried a trailing space never
matched its clean twin. My earlier trailing-space test put the space on the
opening delimiter, which parse_frontmatter already tolerates, so it proved
nothing about this. Leading whitespace-only lines are now dropped as delimiter
residue while a line that starts with spaces then real text keeps its
indentation.

The Copilot integration test joined every emitted file, so one emitter could
regress to `read` while the other's `open` satisfied the assertion. It now
reads each command artifact separately and rejects `read`. Scoping that
exposed a second problem with my own test: it had asserted over every emitted
markdown file including the plugin index, which carries no command body and only
passed because the join diluted it.

* refactor(garden): one entry rule for both marketplace readers

Review feedback on PR #676. actual_counts counted {"name": ["bad"]} because it
is a dictionary, while check_marketplace_consistency rejected the same entry as
MARKETPLACE_SHAPE. A counts-only run could report a stale total from a manifest
the other check calls invalid.

Rather than copy the name rule into the second place, both now call
marketplace_entry_problem, which returns why an entry is unusable or None. That
also collapses the two near-identical report blocks in the consistency check
into one.

Parametrized coverage of the rule itself, plus a case proving a list-valued name
leaves the count unknown.

* style(tests): sort the doc_gardener test imports

I001 from adding marketplace_entry_problem to the import block in e7bd51c. I
pushed that commit without reading the ruff output, for the second time in this
review. Adding a pre-push habit of running make lint rather than eyeballing it.

* fix(garden): canonicalize nested frontmatter before hashing

Review feedback on PR #676. parse_frontmatter supports one-level mappings, and
repr preserves insertion order, so two agents whose metadata block listed the
same keys in a different order hashed differently and reported false drift. Only
the top-level keys were sorted.

Mapping keys are now sorted recursively. List order is left alone because it is
meaningful: reordering tools: [Read, Write] is a real change, and three tests
pin that distinction alongside a changed nested value still counting as drift.

No agent in the repo uses nested frontmatter today, so live output is unchanged
at 11 divergent. Skills do use it, and agents are free to.
2026-08-22 21:56:29 -04:00
Seth Hobson ca2287c776 chore(tooling): close the ruff scope gap and correct two stale docs (#677)
* chore(tooling): close the ruff scope gap and correct two stale docs

Pre-existing issues found while working on #676.

CI checked ruff against five explicit paths under tools/, so four files outside
that list drifted out of format: check_agent_name_collisions.py, both installers
and yt-design-extractor.py. Ruff now runs over all of tools/, those four are
formatted, and two real B007 findings in yt-design-extractor are fixed. ty keeps
explicit paths because yt-design-extractor imports optional OCR dependencies that
only `make install-ocr` provides.

default_config_dir in install_opencode.py assigned os.environ, a Mapping, back
over a parameter annotated dict[str, str] | None, which produced five ty errors
and left the value possibly-None to the reader. It now binds a separate
Mapping-typed local.

New `make lint` and `make format` targets run the checks from
plugins/plugin-eval/ the way CI does. Running ruff from the repo root silently
falls back to line-length 88 and disagrees with CI, which is easy to hit and
wastes time; the targets remove the choice. I tried a root ruff.toml first and
reverted it: it changes isort's first-party resolution for tools/ and makes CI
fail with I001.

AGENTS.md said generated artifacts are committed. Only the small registries are;
the transformed trees under .codex/, .opencode/, .copilot/ and .antigravity/ are
gitignored. CONTRIBUTING listed `make garden STRICT=1` as a gate while main
carries ten SKILL_OVER_CODEX_CAP warnings that make it always fail.

* fix(make): pin lint tools to the dev extra

Review feedback on PR #677. ruff and ty are declared under the dev optional
dependency, and the new targets called uv run without it. On a clean checkout
that does not fail as expected: uv provisions an unpinned ruff on the fly, so
make lint ran 0.16.4 while CI, which does uv sync --all-extras, ran the locked
0.16.3. A gate whose purpose is matching CI was free to disagree with it about
formatting.

--extra dev on all five invocations. Verified the version now resolves to
0.16.3.

* docs(install-opencode): describe the empty-mapping invariant

Review feedback on PR #677. The comment still described the old
dict[str, str] | None annotation and missed the behavior that actually matters.

The old `env or os.environ` fell back whenever env was falsy, so an explicitly
empty mapping silently read the real environment. The explicit None check keeps
it empty, which is what install_copilot.default_config_dir already did, so the
two now agree. Two tests pin both paths.
2026-08-22 21:55:32 -04:00
Seth Hobson 367cb6a4a1 feat(antigravity)!: migrate from Gemini CLI to Google Antigravity CLI harness (#669)
* feat(antigravity): add Google Antigravity CLI harness adapter (#644)

* feat(antigravity)!: retire Gemini CLI harness (#644)

Google deprecated the Gemini CLI in May 2026. This drops the Gemini adapter,
validator, and doc-gardener drift pairs, and removes the committed
gemini-extension.json / .gemini/ / GEMINI.md artifacts and the local
build-only skills/, agents/, commands/ trees they produced.

The Google Antigravity CLI (agy), added in the prior commit, is now the
harness those users should migrate to: native plugins at
.antigravity/plugins/<name>/, reading AGENTS.md directly (no context-file
redirect needed), with its own marketplace, tier-based model aliases
(pro/flash/inherit), and `make install-antigravity` for global installs.

- tools/adapters/gemini.py deleted; capabilities.py/generate.py/
  validate_generated.py/doc_gardener.py/Makefile lose their Gemini
  dispatch, targets, and drift pairs.
- Tests: TestGeminiAdapter, TestGeminiValidator, TestGeminiRoundTrip,
  TestGeminiSmoke removed along with now-unused imports.
- CI: cli-smoke-test now installs the Antigravity CLI instead of the
  Gemini CLI; multi-harness-generate uploads .antigravity/ instead of the
  legacy top-level skills/agents/commands/ output.
- Docs (AGENTS.md, ARCHITECTURE.md, docs/harnesses.md, docs/authoring.md,
  docs/round-trip-results.md, docs/plugin-eval.md, README.md,
  CONTRIBUTING.md, issue/PR templates) swept to describe Antigravity as
  the fifth harness in place of Gemini.

BREAKING CHANGE: the Gemini CLI harness is no longer generated, validated,
or supported. Existing gemini-extension.json / .gemini/ / GEMINI.md
consumers should switch to `make generate HARNESS=antigravity` and
`make install-antigravity`.

* fix(antigravity): mirror skill support dirs, translate $ARGUMENTS, harden validator (#644)

Address CodeRabbit + Codex review feedback on PR #669:

- antigravity.py: mirror every skill support file (scripts/, assets/,
  resources/, examples/), not just references/ — matches OpenCode's pattern.
  Excludes hidden files.
- antigravity.py: translate $ARGUMENTS to {{args}} in place within command
  bodies; only append a trailing {{args}} block when the source has none.
- antigravity.py: serialize frontmatter with YAML-safe scalar quoting and
  preserve dict-valued fields (e.g. metadata) as nested mappings instead of
  stringifying the Python repr.
- validate_generated.py: guard against non-dict plugin.json and non-string
  command description/prompt fields so malformed input is reported as a
  finding instead of crashing with AttributeError/TypeError.
- Sync stale plugin/agent/skill/command counts in claude-code-review.yml and
  ARCHITECTURE.md to the canonical 92/202/181/105.
- CONTRIBUTING.md: add the missing Antigravity entry to the six-harness
  portability checklist.
- docs/authoring.md: add fable to ARCHITECTURE.md's valid model list; correct
  the TodoWrite/hooks support matrix for Antigravity.
- harness_portability.py: fix the bare-model-alias comment — Antigravity maps
  aliases to tier values, not full model IDs.
- .cursor/rules/020-agent-skill-authoring.mdc (source in
  tools/adapters/cursor_rules/, regenerated): Antigravity lacks TodoWrite but
  does support Task-spawn and hooks via native equivalents.
- README.md: narrow the Pensyve integration claim to the harnesses it
  actually covers.
- .gitignore: document that Antigravity follows OpenCode's clone+generate
  install pattern; give .antigravity/ its own comment.
- Extend adapter and validator test suites for both fixes.

* fix(antigravity): quote comma-containing items in flow-style YAML lists

CodeRabbit follow-up on the frontmatter YAML-safety fix: _yaml_scalar() didn't
treat ',' or ']' as needing quotes, so a list item containing a comma (e.g.
tags: ["foo, bar", baz]) split into two list entries on round-trip since flow
sequences use ',' as the item delimiter. Add _yaml_flow_scalar() for list
items specifically (top-level scalars don't need this — commas are only
ambiguous inside [...]). Regression test added.
2026-08-18 11:42:59 -04:00
Seth Hobson 960e11180f fix(copilot): do not clear caches when install fails (#663) (#666) 2026-08-18 10:31:23 -04:00
Seth Hobson d6837ae274 deps(yt-design-extractor): bump pillow to 12.3.0
Resolves all 13 open Dependabot alerts (10 high, 3 medium), including
CVE-2026-59205/59199/59197 heap OOB writes, multiple decompression-bomb
check bypasses, and CVE-2026-55798 command injection. All patched in
12.3.0; the >=10.0.0 constraint already allowed it.
2026-08-15 17:37:07 -04:00
Seth Hobson 53b5756c5d build: prune orphaned artifacts on every full generate
make generate (--all) and generate-all now pass --prune, so removing a
plugin no longer leaves stale per-harness artifacts behind (the trap hit
when runapi-mcp was removed). prune_orphans also sweeps directories its
deletions empty. Sync stale counts in ARCHITECTURE.md (90 local + 1
external) and GEMINI.md (180 skills, 202 subagents, 105 commands); note
the prune behavior in AGENTS.md.
2026-08-15 17:06:36 -04:00
Seth Hobson 7f2727b52e chore: remove runapi-mcp and three external plugins per vendor policy
runapi-mcp: vendor-submitted wrapper for a paid API aggregator with no
disclosure; only its catalog/pricing tools work without a paid key,
violating the no-paid-API-on-default-path and funnel rules.

qa-orchestra, storymap-skill, ciagent: external git-subdir entries that
fail the maturity bar added to CONTRIBUTING (1-11 stars, dormant or
weeks old at submission). pensyve remains the sole external entry.

Counts: 91 plugins (90 local + 1 external), 202 agents, 180 skills,
105 commands. Generated artifacts regenerated with --prune.
2026-08-15 17:03:32 -04:00
dependabot[bot] 29b022dcf9 deps(yt-design-extractor): bump setuptools in /tools/yt-design-extractor (#639)
Bumps [setuptools](https://github.com/pypa/setuptools) from 81.0.0 to 83.0.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v81.0.0...v83.0.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-version: 83.0.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-15 16:49:17 -04:00
Vishnu J c4b82b0ad7 fix(codex): fall back to plugin name when description is empty (#617) (#626)
* fix(codex): fall back to plugin name when description is empty (#617)

npx codex-marketplace add wshobson/agents --plugins fails with
"String must contain at least 1 character(s)" at path ["description"]
because codex-marketplace's installer parses each plugin's
plugins/<name>/.codex-plugin/plugin.json with a zod schema requiring
description: z.string().min(1) (pluginManifestSchema in the installer's
dist/schema.js). _codex_plugin_manifest() previously wrote
"description": plugin.description or "" — plugin-eval's own
.claude-plugin/plugin.json has no description field, so its generated
Codex manifest shipped an empty string and failed that check for every
--plugins install of this repo.

Fix: use the same plugin.description or plugin.name fallback already
used two lines below for the interface.shortDescription field. Also
add a top-level description to each .agents/plugins/marketplace.json
entry as forward-compatible metadata, since the installer's currently
published marketplacePluginSchema doesn't declare or require it there
(unknown keys are silently stripped by zod's default .parse()) — that
alone does not fix the crash, which lives in the per-plugin manifest.

Regenerated the committed Codex artifacts via make generate-all; only
plugin-eval's .codex-plugin/plugin.json needed the description fix,
confirming it's the only plugin missing an upstream description. Added
a regression test for the plugin.name fallback in
_codex_plugin_manifest(), alongside the existing marketplace-entry
description test.

Reported by jkroepke.

* test(codex): cover marketplace description fallback to plugin name

CodeRabbit: synthetic_plugin already has a description, so the
_codex_marketplace name fallback was untested. Add a no-desc plugin
and assert description == name.

* chore: regenerate .agents marketplace after main merge

plugin-eval now carries its real description (#630) instead of the name
fallback, and the pptx-deck-creation entry (#625) gains the description
field this PR's generator emits for every marketplace entry.

---------

Co-authored-by: Seth Hobson <wshobson@gmail.com>
2026-07-18 17:25:19 -04:00
kimtth 73d2f99cd4 feat: add pptx-deck-creation plugin (#625)
* fix: read validation artifacts as UTF-8

* Add pptx-deck-creation plugin

* fix: resolve CodeRabbit quality issues

* fix: consolidate ooxml skill into reference-deck-analysis

* fix: resolve CodeRabbit quality issues
2026-07-18 17:00:10 -04:00
dependabot[bot] ddf29f7201 deps(yt-design-extractor): bump the python-minor-and-patch group (#619)
Bumps the python-minor-and-patch group in /tools/yt-design-extractor with 2 updates: [torch](https://github.com/pytorch/pytorch) and [torchvision](https://github.com/pytorch/vision).


Updates `torch` from 2.12.1 to 2.13.0
- [Release notes](https://github.com/pytorch/pytorch/releases)
- [Changelog](https://github.com/pytorch/pytorch/blob/main/RELEASE.md)
- [Commits](https://github.com/pytorch/pytorch/compare/v2.12.1...v2.13.0)

Updates `torchvision` from 0.27.1 to 0.28.0
- [Release notes](https://github.com/pytorch/vision/releases)
- [Commits](https://github.com/pytorch/vision/compare/v0.27.1...v0.28.0)

---
updated-dependencies:
- dependency-name: torch
  dependency-version: 2.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-minor-and-patch
- dependency-name: torchvision
  dependency-version: 0.28.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Seth Hobson <wshobson@gmail.com>
2026-07-18 16:54:37 -04:00
Seth Hobson 2de74ac1c8 fix(adapters): parse nested frontmatter mappings (#618)
* fix(adapters): parse nested frontmatter mappings

Preserve one-level mapping values in the shared frontmatter parser so generated Codex skill metadata keeps the dictionary shape Codex requires. Add regression coverage for nested keys and quoted values.

* style(tests): satisfy ruff formatting

* fix(adapters): reject deeper mapping indentation
2026-07-11 09:58:27 -04:00
Seth Hobson 511f8345cf docs: refresh model references for Claude Sonnet 5 and Fable 5 (#612)
* feat(adapters): map sonnet tier to Claude Sonnet 5; Copilot fable to claude-fable-5

Claude Sonnet 5 is GA (Copilot GA 2026-06-30) and Copilot now serves
Fable 5 natively, so the sonnet/inherit aliases move off Sonnet 4.6 and
the Copilot fable alias no longer falls back to Opus 4.8. Catalog
verification date bumped to 2026-07.

* fix(plugin-eval): judge sonnet tier resolves to claude-sonnet-5

* docs: refresh model alias table and tier counts (Sonnet 5, five-tier, 66/22/52)

* docs(plugins): update model examples to Sonnet 5 / Opus 4.8

Replace claude-sonnet-4-6 with claude-sonnet-5 and Opus 4.7 mentions
with 4.8 in llm-application-dev; replace retired claude-3-5-sonnet in
performance-testing-review's ai-review. Drop temperature args from
migrated examples — Sonnet 5 rejects non-default sampling params.
2026-07-07 12:17:53 -04:00
Seth Hobson 0bacec2367 fix: cross-cutting process fixes from open-PR/issue audit (#611)
* fix(cursor-rules): align marketplace.json rule with CONTRIBUTING.md

The rule 'Never modify .claude-plugin/marketplace.json from inside a
plugin PR' contradicted CONTRIBUTING.md step 3 and actual maintainer
practice, causing CodeRabbit to force revert/re-add churn on plugin PRs
(#577, #582, #596, #606). Reword to prohibit hand-editing the generated
registries instead.

* docs: fix stale component counts (194 agents, 106 commands, 158 skills, 44 plugins)

* docs(contributing): add commercial content and disclosure policy

* docs(protect-mcp): remove unverified downloads claim

npm reports ~3.2K monthly downloads, not 10K+; the README already has a
live shields.io downloads badge. Also drop the stale v0.5.5 reference
(see #601).
2026-07-07 11:42:03 -04:00
dependabot[bot] 614d169260 deps(yt-design-extractor): bump yt-dlp (#608)
Bumps the python-minor-and-patch group in /tools/yt-design-extractor with 1 update: [yt-dlp](https://github.com/yt-dlp/yt-dlp).


Updates `yt-dlp` from 2026.6.9 to 2026.7.4
- [Release notes](https://github.com/yt-dlp/yt-dlp/releases)
- [Changelog](https://github.com/yt-dlp/yt-dlp/blob/master/Changelog.md)
- [Commits](https://github.com/yt-dlp/yt-dlp/compare/2026.06.09...2026.07.04)

---
updated-dependencies:
- dependency-name: yt-dlp
  dependency-version: 2026.7.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-07 11:40:04 -04:00
dependabot[bot] 7640f33478 deps(yt-design-extractor): bump the python-minor-and-patch group across 1 directory with 3 updates
Bumps the python-minor-and-patch group with 2 updates in the /tools/yt-design-extractor directory: [yt-dlp](https://github.com/yt-dlp/yt-dlp) and [torch](https://github.com/pytorch/pytorch).


Updates `yt-dlp` from 2026.3.17 to 2026.6.9
- [Release notes](https://github.com/yt-dlp/yt-dlp/releases)
- [Changelog](https://github.com/yt-dlp/yt-dlp/blob/master/Changelog.md)
- [Commits](https://github.com/yt-dlp/yt-dlp/compare/2026.03.17...2026.06.09)

Updates `torch` from 2.12.0 to 2.12.1
- [Release notes](https://github.com/pytorch/pytorch/releases)
- [Changelog](https://github.com/pytorch/pytorch/blob/main/RELEASE.md)
- [Commits](https://github.com/pytorch/pytorch/compare/v2.12.0...v2.12.1)

Updates `torchvision` from 0.27.0 to 0.27.1
- [Release notes](https://github.com/pytorch/vision/releases)
- [Commits](https://github.com/pytorch/vision/compare/v0.27.0...v0.27.1)

---
updated-dependencies:
- dependency-name: yt-dlp
  dependency-version: 2026.6.9
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-minor-and-patch
- dependency-name: torch
  dependency-version: 2.12.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-minor-and-patch
- dependency-name: torchvision
  dependency-version: 0.27.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-22 01:08:46 +00:00
Seth Hobson cc37bfdd29 feat: add fable model tier and refresh per-harness model aliases
Add Claude Fable 5 (model: fable) as the tier above opus across the
adapter framework - native passthrough in Claude Code, mapped to each
harness's top model elsewhere. No agents are promoted yet; tier criteria
and cost guidance are documented in docs/agents.md and docs/authoring.md.

Refresh MODEL_ALIASES against current harness catalogs (June 2026):
- Codex: gpt-5 family -> gpt-5.5 / gpt-5.4-mini (per Codex model docs)
- Copilot: GPT-5 stand-ins -> native Claude models (claude-opus-4.8,
  claude-sonnet-4.6, claude-haiku-4.5) now that Copilot CLI serves them
- OpenCode: opus -> anthropic/claude-opus-4-8; haiku dated pin ->
  latest-tracking anthropic/claude-haiku-4-5
- Gemini: intentionally stays on GA gemini-2.5-* (3.x is preview-gated)
- plugin-eval judge opus tier -> claude-opus-4-8

Gates: generate-all (no committed drift), validate STRICT=1, garden,
test (442 passed), smoke-test all green.
2026-06-12 10:55:38 +09:00
Seth Hobson 09250c0b50 fix: format tools/ with plugin-eval's ruff config (line-length 100)
The Code Quality job runs ruff from `plugins/plugin-eval/`, so that project's
`[tool.ruff]` (line-length 100) governs the `../../tools/` sources too — there
is no repo-root ruff config. The previous reformat was run from the repo root,
where ruff fell back to its 88-col default, so CI disagreed. Reformat from the
plugin-eval cwd to match CI exactly.
2026-05-29 13:22:17 -04:00
Seth Hobson d31e8b8fea fix: address PR review + upgrade ruff/ty so CI matches local
Review feedback:
- codex.py: Codex marketplace entries now conform to the openai/codex
  core-plugins schema — source {source: "local", path}, policy
  {installation, authentication}, and category (was missing required
  fields; flagged P1). Top-level trimmed to {name, plugins}.
- codex.py: interface.shortDescription cuts on a word boundary + ellipsis
  instead of a mid-word [:120] slice in committed .codex-plugin manifests.
- cursor.py: top-level .cursor-plugin/plugin.json displayName is now the
  short "Claude Code Workflows" instead of the long marketplace description.

Tooling (local drives CI):
- Bump ruff 0.15.14 -> 0.15.15 and ty 0.0.39 -> 0.0.40 in plugin-eval's
  uv.lock so CI installs the same versions we run locally, and reformat the
  tools/ + plugin-eval sources to ruff 0.15.15 (fixes the failing
  ruff format --check; the lock-hash change also busts CI's stale cache).

make validate STRICT=1 clean / garden 0 errors / 442 tests pass; regeneration
remains drift-free.
2026-05-29 13:18:48 -04:00
Seth Hobson 608c3840ca feat: native plugin-install for Codex/Cursor/Gemini + CLAUDE.md→AGENTS.md symlink
Add lean, native plugin-install entry points so each harness's own plugin
manager can install this marketplace (mirroring obra/superpowers) — committing
only small JSON registries, not duplicated skill/agent content trees.

- Codex: committed marketplace registry (.agents/plugins/marketplace.json) +
  per-plugin manifests (plugins/*/.codex-plugin/plugin.json). Entries point at
  source ./plugins/<name>; Codex reads SKILL.md directly. Transformed
  .codex/skills|agents stay gitignored.
- Cursor: commit the existing .cursor-plugin/ marketplace + .cursor/rules/
  (these already point at source plugins/).
- Gemini: gemini-extension.json already committed (contextFileName: AGENTS.md);
  transformed trees stay gitignored (install via clone + make generate).
- OpenCode: unchanged — install via `make install-opencode` (transformed tree
  stays gitignored).
- CLAUDE.md is now a symlink to AGENTS.md; Claude-Code addenda moved to
  docs/harnesses.md.
- CI: new step fails if `make generate-all` drifts from the committed registries.

Net new committed: ~720 KB of manifests (no skill/agent duplication). Adds
round-trip tests for the new registries + the symlink. Docs updated across
README, docs/harnesses.md, ARCHITECTURE.md, CONTRIBUTING.md, GEMINI.md,
docs/authoring.md, and the PR template.
2026-05-29 13:02:40 -04:00
GitHub Copilot 6396498ed4 fix: ruff format for plugin-eval config (double quotes, 100 line-length) 2026-05-26 09:53:03 -05:00
GitHub Copilot 9e14e351d7 fix: import sorting for plugin-eval ruff config (I rule) 2026-05-26 09:47:29 -05:00
GitHub Copilot 4a3685ed6b fix: ruff formatting and type fixes for CI quality gates 2026-05-26 09:28:57 -05:00
GitHub Copilot f39402df5f fix(copilot): address PR #550 review feedback
- fix stem-parsing bug in doc_gardener.py (.agent suffix strip on Path.stem)
- wrap skill.body with _rewrite_body_lowercase_tools() in copilot.py
- add config_dir.is_dir() guard in install_copilot.py uninstall
- fix ruff I001 import sorting across 5 files
2026-05-26 09:04:44 -05:00
GitHub Copilot eb22976da8 review: address code-audit findings — .omo/ artifact, docs drift, YAML quoting, validator helper 2026-05-26 09:04:37 -05:00
GitHub Copilot a1b78ce68a review: address PR #550 review feedback — revert bot-driven changes to test and base adapter
- Delete agents_skills.txt and gemini_skills.txt (stale lint outputs)
- Remove agents/*.agent.md gitignore guard
- README.md: restore original table header, Claude Code row, simplify generate-all comment
- docs/authoring.md: re-add Codex deprecated note alongside Copilot info
- docs/usage.md: restore removed pr-enhance command
- tools/adapters/base.py: remove AskUserQuestion mapping
- tools/tests/test_cli_smoke.py: revert TTY skip in codex doctor test
2026-05-26 09:04:37 -05:00
GitHub Copilot 3487dc3f52 feat(copilot): emit plugin commands as runnable skills
Copilot does not support custom slash commands via `.copilot/commands/` —
that path was a project invention with no official discovery mechanism.
Plugin commands emitted there were invisible to Copilot CLI and VS Code.

Instead, emit each plugin command as a Copilot skill SKILL.md with:
- user-invocable: true (appears in VS Code / menu)
- disable-model-invocation: true (not auto-loaded, only on demand)
- hyphenated name `<plugin>-<command>` per VS Code Agent Skills spec

Legacy `.copilot/commands/` emission retained for backward compat.

Closes the loop on commands-not-working-in-Copilot-CLI investigation.
2026-05-26 09:04:37 -05:00
GitHub Copilot f5ad900ee9 copilot: symlink command directories to ~/.copilot/<plugin>/commands/
- Commands now symlink to ~/.copilot/comprehensive-review/commands/ instead of ~/.copilot/commands/
- Adapter emits command files to .copilot/commands/<plugin>/ directory structure
- Installer symlinks each command directory to ~/.copilot/<plugin>/commands/
- This matches Copilot CLI's discovery path for plugin commands

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-26 09:04:35 -05:00
GitHub Copilot 9a178cb044 copilot: ensure command frontmatter has description (synthesize from H1 when missing)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-26 09:04:32 -05:00
GitHub Copilot 52ced895f9 Automate Copilot cache clearing in install process
The 'make install-copilot' command now automatically clears Copilot's
cache directories (pkg and marketplace-cache) after symlinking artifacts,
ensuring new agents and skills are immediately discoverable without
requiring manual cache clearing.

This fixes the issue where installing agents like comprehensive-review
required a separate manual cache clear step before they appeared in
Copilot's agent discovery.

- Add _clear_copilot_cache() to remove pkg/ and marketplace-cache/
- Update _print_report() to show cache clearing confirmation
- Integrate cache clearing into main() install flow only

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-26 09:04:32 -05:00
GitHub Copilot 07036e9689 feat: copilot harness follows OpenCode install pattern with .copilot/ output
- Generate to .copilot/agents/ and .copilot/skills/ (repo-local, gitignored)
- make install-copilot symlinks to ~/.copilot/ for user-level discovery
- tools/install_copilot.py + test_install_copilot.py (mirrors install_opencode)
- tools/validate_generated.py: validate agents + skills
- tools/doc_gardener.py: stale artifact detection for .copilot/
- tools/generate.py: _HARNESS_TARGETS + prune_orphans for .copilot/
- tools/tests/test_adapters.py: TestCopilotAdapter (9 tests)
- tools/tests/test_round_trip.py: TestCopilotRoundTrip (3 tests)
- tools/tests/test_validate_generated.py: expanded to 8 tests
- docs/harnesses.md: install-copilot instructions + Pensyve entry
- .gitignore: .copilot/

Closes #553 (follows same install pattern as OpenCode)
2026-05-26 09:02:12 -05:00
GitHub Copilot 4691655d3c feat: generate copilot artifacts directly to ~/.copilot/ instead of .github/
- CopilotAdapter now writes to ~/.copilot/agents/ and ~/.copilot/skills/
- Updated generate.py to pass ~/.copilot/ as output_root for copilot
- Added copilot stale artifact detection to doc_gardener.py
- Updated validate_generated.py to check ~/.copilot/agents/ (with fallback)
- Removed old copilot gitignore entries and cleaned up stale artifacts
- No install step needed — make generate HARNESS=copilot writes directly
2026-05-26 09:02:12 -05:00
GitHub Copilot 1db71ee658 fix: copilot adapter output path respects output_root with .github/ prefix 2026-05-26 09:02:12 -05:00
GitHub Copilot 36eb3fa527 style: ruff format copilot.py 2026-05-26 09:02:12 -05:00
GitHub Copilot aa01539acf docs: add missing docstrings to CopilotAdapter class and methods 2026-05-26 09:02:12 -05:00
GitHub Copilot 3afefa2a31 fix: update copilot prune paths and _HARNESS_TARGETS; fix table separator 2026-05-26 09:02:09 -05:00
GitHub Copilot b88ab1e5b1 fix: move import re above stdlib imports to satisfy ruff 2026-05-26 09:02:02 -05:00
GitHub Copilot c5bd699089 feat: add Copilot harness adapter and fix test tooling 2026-05-26 09:01:48 -05:00
GitHub Copilot 3d72fae153 Revert "docs: increase validator docstrings to satisfy docstring coverage (addresses PR comment)\n\nAdds docstrings for validate_codex, validate_cursor, validate_opencode, validate_gemini, and main."
This reverts commit 091c218541.
2026-05-26 09:01:23 -05:00
GitHub Copilot 0009a09978 docs: increase validator docstrings to satisfy docstring coverage (addresses PR comment)\n\nAdds docstrings for validate_codex, validate_cursor, validate_opencode, validate_gemini, and main. 2026-05-26 09:01:23 -05:00
GitHub Copilot 39b33c67b4 docs: add validator docstring for validate_copilot (addresses PR comment)\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> 2026-05-26 09:01:22 -05:00
GitHub Copilot bd5c049b61 test: skip codex doctor in non-interactive envs; validator scoped to .copilot 2026-05-26 09:01:22 -05:00
GitHub Copilot 130384b7b3 revert: remove --commit flag and Makefile wiring (follow project contribution patterns)
- Keep generation local by default (.copilot)
- Revert opt-in --commit behavior that wrote to .github/agents
- Retain validator adjustments scoped to .copilot
- Clean branch focuses only on adapter ergonomics and validator behavior

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-26 09:01:22 -05:00
GitHub Copilot c90f2c379c chore: copilot commit-mode support (clean branch)
- Add --commit flag to tools/generate.py and default .copilot output_root
- Validate .github/agents in tools/validate_generated.py
- Makefile wiring for COMMIT=1

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-26 09:01:22 -05:00