gitea-releases was the weakest skill in the plugin: no allowed-tools, no
owner/repo resolution, and a checkbox list where a dispatch table belongs, so
an agent reaching it had to guess both its permissions and its inputs. The
id-vs-tag_name trap — deleting by tag name where the API wants the numeric id —
is restored as an explicit Gotcha because it destroys the wrong release
silently.
Elsewhere the `exclusive` flag was documented on the wrong side of the
read/write split, and label data from one instance was presented as though it
were universal, which invites an agent to assume a taxonomy that does not
exist on the target repo. rename_branch was missing from the branch surface.
Reference prose and fences are cleaned up in passing.
The retrofit left only a descriptive sentence on the loaded path — "Gitea
never infers a prerelease from a -beta/-rc tag name" — and moved the
imperative into references/conventions.md behind a trigger listing semver
naming, release-notes sourcing and release-to-tag relationships. Draft and
prerelease are not in that list, and "cut a v2.0.0-beta.1" is exactly the
request where the caller does not raise the topic, so the rule was
unreachable from the flow that needs it.
Severity comes from the repair path: the MCP surface has create, get,
get_latest, list and delete only — there is no update or edit tool. A
release published without is_pre_release can only be corrected by
delete_release plus a fresh create, and get_latest_release points
consumers at the beta meanwhile. Neither SKILL.md nor call-signatures.md
said so anywhere.
The flags are now set explicitly on every create, the missing update tool
and its delete-and-recreate consequence are stated in the body, and the
semver pass-through rule stranded behind the same trigger is promoted
alongside it. call-signatures.md now cites the deployed tool description
as direct evidence that get_latest_release excludes drafts, while keeping
the prerelease half hedged — that remains unconfirmed.
Verified live against gitea-mcp v1.7.0, read-only calls.
Refs #99
SKILL.md called `exclusive` "an org-labels-only flag" and concluded that
applying a Kind/*, Priority/* or Status/* label "must replace the one
already there, not stack on it". Live `list_repo_labels` on this repo
returns `exclusive` on every REPO label: all seven Kind/* plus
Compat/Breaking are false, while Priority/*, Reviewed/* and Status/* are
true. So the field is not org-only, and the replace rule would strip a
valid Kind/* label — a destructive write from a false premise.
The nuance kept: label_write's `exclusive` parameter genuinely is
annotated org-only, so that row was schema-accurate. The error was
generalising a write-parameter restriction into a claim about where the
field exists. The row is qualified rather than deleted.
The rule is now per-label: where exclusive is true the server drops the
sibling itself, so do not pre-remove; where it is false the label is
legitimately stackable.
Also fixes the org-label fallback, which treated any list_org_labels
failure as proof the owner is a user account with no org pool and said so
was "an answer, not an error to report". Under the token scopes this skill
declares the call fails with required=[read:organization] before any
org-vs-user determination is made, so a capability gap was being reported
as an absent label. Scope errors are now distinguished and reported.
Verified live against gitea-mcp v1.7.0, read-only calls.
Refs #99
SKILL.md's headline Gotcha said `list_issues` "has no `type` filter", and
references/issues.md stated in bold that neither `type` nor `milestones`
exists, "despite both appearing in api-reference.md". Both parameters are
present on the deployed gitea-mcp v1.7.0 and both work: `type: "issues"`
returns only issues, `type: "pulls"` only PRs, and `milestones` filters by
name. Unfiltered, the same window returns them interleaved, so the mixing
the Gotcha describes is real — only the stated remedy was wrong.
This mattered most in gitea-workflow's no-args check-in, which lists open
issues through this skill and so reported PRs under "Open Issues" while
the skill forbade the one-parameter fix. The list flow now passes
`type: "issues"`.
references/sources.md recorded the absence as a live-verification win over
stale research docs; it now records that the earlier check was superseded
by v1.7.0, since drift runs in both directions. gitea-prs cited the same
parameter as its canonical drift example and no longer does — no
replacement example was substituted, because the obvious candidate was not
verified in this pass.
Also defaults label writes to `add_labels`: `replace_labels` clears every
label not in the array, and per-label exclusivity makes blanket replacement
destructive for a non-exclusive scope.
Verified live against gitea-mcp v1.7.0, read-only calls.
Refs #99
The retrofit (dfacf05) collapsed a Gotcha into a bidirectional claim —
"deleting a tag never deletes the release wrapping it" — that
references/call-signatures.md never confirms; that file explicitly
marks the reverse direction unconfirmed and "the more dangerous
direction to get wrong." State only the confirmed direction (deleting
a release doesn't delete its tag) and flag the reverse as unconfirmed
with a verification step, on a destructive, irreversible operation.
Found by an independent post-closure audit of #99 (agent-audit +
skill-audit re-run against every changed skill/agent).
references/commits.md cited overview.md as the authority for a
scope-gating claim, but no such file exists in this skill's package —
the only overview.md is an external research doc not shipped with the
skill. Repoint to branches.md's own Token scope section, which states
and confirms the same principle, and drop the unverifiable
write:repository enumeration detail no file in this skill actually
makes.
Found by an independent post-closure audit of #99 (agent-audit +
skill-audit re-run against every changed skill/agent).
An independent audit of the ADR-0020 retrofit (issue #99) found that
git-submodules, git-worktrees, and gitea-files each collapsed their
description length correctly during retrofit but left the capability
clause as a verb enumeration (e.g. "Create, list, lock, move, remove,
prune, or repair") instead of ADR-0020's required single clause. The
deterministic char-count gate can't catch this — it's a qualitative
rubric violation the retrofit commits' own messages never claimed to
address, only measurable length/word-count fixes.
Validated clean via skill-audit and skill-size-check after the fix;
boundary clauses and routing targets left untouched.
Refs #99
body-discipline.md required every reference load to use the literal
'If X, read references/file.md' form and called anything else a generic
pointer. ADR-0020's own cited dispatch exemplar, apm-workflow, uses a
bare table plus one closing line, so an author could not satisfy both --
and the rule reliably produced duplication in exactly the bodies the
contract exists to keep short.
Resolves#109 with its option 1: a table row already pairs a condition
with a target, so where a body dispatches, the table is the wiring. The
literal form is what a body needs when it loads a reference without a
table.
Two corrections to the issue as filed. There is no Vale conflict --
PaddingPhrase.yml only matches 'see references/ for more info' and never
fired on the exemplar, so this is a one-file prose fix and no rule
changes. And gitea-workflow carried the predicted duplication: a
three-row table restated underneath as three conditionals. Removed, body
227 -> 148 words.
Closes#109
Generated output, not authored content: scripts/sync-plugin-content.sh --all.
Claude Code has no .apm/ awareness, so this compiled mirror must track .apm/ or
the check-plugin-content-sync pre-push hook reports drift.
Deferred to a single commit at the end of the wave on purpose. sync_dir runs
rm -rf before every copy, so running it while seven agents were editing the
same plugin would have raced them; agents were told not to sync for that reason.
Refs #99
Follow-up to the review of #106, which found four parameter claims the
first pass left wrong or missing. All four verified against gitea-mcp
v1.6.0 source before changing anything.
`remove_deadline` is dropped on "create" like the others, but the new
Gotcha enumerated a closed list that omitted it — so the paragraph
contradicted its own opening sentence. The list is now open ("including")
and the parameter carries the same "update" only marker as its neighbours.
`base` is settable on "update": editPullRequestFn reads it and retargets
the PR onto a different base branch. The file documented it as required
for "create" and said nothing else, hiding a real capability. This one is
under-claiming rather than over-claiming, but a file whose subject is
which parameter applies to which method is the place to fix it.
applyDraftPrefix strips two prefixes, `WIP:` and `[WIP]`, matched with
strings.EqualFold, while only "WIP: " is ever added. The un-draft
correction said "the prefix" singular, which understates what a caller
can hand it.
README.md bundled `reviewers` and `milestone` into "creating and
updating". Capability prose rather than a parameter contract, so not
strictly false, but it is the same conflation that produced the original
bug and it is not behind any gate.
Not addressed here: SKILL.md's description still advertises updating
reviewers, its draft guidance still prescribes the manual workaround, and
its milestone-resolution instruction carries no method qualifier — so an
agent working from SKILL.md alone can still reach the failure mode. Those
edits trip skill-size-check and the Vale prefilter, pulling in the
ADR-0020 retrofit; tracked on #99 rather than done silently here.
Refs: #104
Refs: #99
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETxbGFetkbJQBHsx442Brt
The gitea-prs reference documented `milestone` as "settable on both
"create" and "update"". It is not: `pull_request_write method: "create"`
accepts the parameter, returns no error or warning, and discards it.
Verified against the gitea-mcp v1.6.0 source rather than by observation
alone. `createPullRequestFn` builds its `CreatePullRequestOption` from
owner, repo, title, body, head, base, draft, labels and deadline only —
so the drop is not limited to `milestone` as issue #104 supposed.
`assignee`, `assignees`, `reviewers` and `team_reviewers` are discarded
on create too, and `reviewers`/`team_reviewers` are discarded on
"update" as well; they are only ever read by "add_reviewers" and
"remove_reviewers".
Two properties made the original error easy to make and hard to catch,
so both are now written down next to the correction: `labels` sits
beside `milestone`, reads identically, and does apply on create; and
`issue_write method: "create"` honours `assignees` and `milestone`, so
the asymmetry is specific to pull requests.
While in the file, corrected the adjacent draft gotcha. It prescribed
reconstructing the un-prefixed title by hand to un-draft a PR;
`applyDraftPrefix` shows "update" with `draft: false` and no `title`
fetches the stored title and strips the prefix server-side.
Impact: documentation only, no behaviour change. Callers following the
old text silently created PRs with no milestone, assignee or reviewer.
Confined to references/pull-requests.md, so the ADR-0020 skill gates do
not apply and gitea-prs needs no #99 retrofit first.
Fixes: #104
Refs: #99
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ETxbGFetkbJQBHsx442Brt
Addresses PR #85's outstanding review items after grilling the open
questions against ADR-0013/CONTEXT.md/ADR-0010:
Blocking fixes:
- vale-wrap.sh: replace json.dumps() escaping (which silently defeated
Vale's frontmatter scope on any description containing a quote,
backslash, or non-ASCII char — ~58% of the corpus) with a single-quoted
YAML scalar, substituting a Unicode right single quote for embedded
apostrophes rather than '' doubling (Vale's frontmatter scanner isn't a
full YAML parser and silently truncates on '' too).
- vale-wrap.sh: fix a blank-line-inside-a-folded-description truncation
bug via indentation-based, blank-line-tolerant body capture; narrow
flattening to `>`-style scalars only (`|` already works unflattened).
- skill-audit/agent-audit Step 1: make the vale-wrap.sh invocation
cwd-independent via git rev-parse --show-toplevel, fixing a bug where
no single cwd satisfied all three Step 1 commands.
- styles/Kyberforge/VagueQualifier.yml: prune 17 tokens verified
false-positive-dominated on this repo's own voice via a real corpus
sweep (obvious, clearly, usually, several, simple, easy, completely,
simply, tiny, etc.), keep 13 with real or unattested noise. Revert the
28 prose "fixes" those tokens drove across 14 skill files back to their
original, correct wording, including a functional regression to
caveman/SKILL.md's own filler-word list (a mention, not a use) — now
guarded with vale-off comments against recurrence.
Gaps:
- --minAlertLevel=warning on the pre-commit hook and Step 1 invocation
so warning-level rules actually surface, without collapsing the
FAIL/SUGGESTION severity mapping skill-audit/agent-audit rely on.
- vale-wrap.sh: fix --config=<path> equals-form, absolute-path silent
no-op, and a zero-file-argument stdin hang.
- Route vale-run and lint-runner through a documented wrapper script
when a target repo has one, instead of unconditionally recommending
bare `vale`.
- Wire Kyberforge.VagueQualifier/SentenceOpenerThereIs into skill-audit/
agent-audit's dimension-mapping prose (Body discipline).
- Add plugins/lint/sources.md provenance for lint-runner (ADR-0010).
- Sync both marketplace.json lint-entry descriptions with plugin.json.
- Retune skill-size-check.sh's MAX_WORDS 5000->2900 (measured ~1.6-1.7
tokens/word on this repo's corpus, the old value gated at ~8,500
tokens against a stated 5,000 ceiling); fix the >/>= line-count
boundary and wc -l undercount on files with no trailing newline.
- Document the vale binary as a Setup prerequisite in AGENTS.md.
- Fix SentenceOpenerThereIs's dead regex alternative and add a real
sentence-start anchor/scope.
- Fix a stale docs/research/docs/vale/ index pointer in kyberforge's
docs README (moved to plugins/lint/ in e1a5403).
- Rewrite ADR-0013's Consequences section past-tense to describe what
actually landed, and record the styles-portability limitation
(repo-root placement stays intentional; deferred to a separate
session per this PR's review).
Test coverage: 9 new vale-wrap.sh fixtures (quotes, backslash/unicode,
blank-line paragraphs, --config= form, zero-arg/absolute-path handling,
literal-block no-regression) and boundary-pair tests for
skill-size-check.sh's line/word ceilings.
bash tests/run-tests.sh: 9 scripts + 125 bats assertions, all passing.
scripts/check-manifests.sh and claude plugin validate --strict: clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MCQ648fLSFXPHGZdQ8gn58
Deferred item from PR #85 review. Per ADR-0013: cherry-picks two low-noise
rules from trialing write-good/alex against the real corpus (VagueQualifier,
SentenceOpenerThereIs) into styles/Kyberforge rather than adopting either
package wholesale (both are tuned for blog prose and were noisy on this
repo's terse, imperative instruction files - see the ADR's rejected-rule
list). Adds a new skill-size-check pre-commit hook enforcing agentskills.io's
500-line/5,000-token SKILL.md ceiling, currently unenforced. Fixes the 28
resulting violations across 20 existing SKILL.md/agent files so the
enforcing pre-commit hook lands clean.
governance.md/CONTROLS.md were evaluated and excluded as rule sources -
they're org/CI-infrastructure controls, not prose patterns Vale can express.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QUDczvw1H3eEeMD29Q9Lbi
The deep-module split in plugins/gitea/ (ADR 0011) already covers every
domain the old plugins/bin/skills/gitea/ flat skill handled. Move its
token-access.md into plugins/gitea/references/ first, since it held
empirical scope-test results (Actions/CI, Wiki, Notifications, Packages,
User/Org) not reproduced anywhere in the new plugin, then drop the old
skill and fix a stale cross-reference pointing at it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>