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
7.5 KiB
name, description, compatibility, metadata, allowed-tools
| name | description | compatibility | metadata | allowed-tools | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| gitea-issues | Use when reading or writing Gitea issues: listing repo issues, getting a single issue's details/ comments/labels, creating an issue, updating its state, adding or editing comments, applying labels via issue_write, or searching issues/PRs across repositories. Triggers on "create an issue", "what issues are open", "get issue #N", "close issue #N", "comment on issue #N", "search issues for X" — even when the user doesn't say "Gitea" explicitly. Composes gitea-labels- milestones for all label inference/resolution and milestone lookup — do not use this skill to manage label or milestone definitions themselves (create/edit/delete a label, create/close a milestone), that's gitea-labels-milestones directly. Do not use for pull requests (use gitea-prs) or for local git branch/commit work (use gitea-branches or git-branches). | Requires Gitea MCP server configured with write:issue and write:repository token scopes. Requires git remote "origin" pointing to the Gitea instance for owner/repo resolution when invoked directly by a human; an orchestrating caller (e.g. gitea-workflow) may pass owner/repo already resolved. |
|
Bash mcp__gitea__list_issues mcp__gitea__issue_read mcp__gitea__issue_write mcp__gitea__search_issues |
Gotchas
list_issueshas notypeormilestonesparameter — despiteapi-reference.mddocumenting both. The live MCP schema (re-verified viaToolSearchat authoring time — seereferences/sources.md) only acceptsowner,repo(required),state(default"all"),labels(array of label names),since,before(ISO 8601),page,per_page(default 30). This tool provides no way to filter issues-vs-PRs or by milestone. Since issues and PRs share one number space,list_issuesresults can include PR entries with no client-side filter to exclude them. If you need to know whether a specific number is a PR, callissue_read method: "get"and checkis_pull— that field only appears on the single-item response, never in a list item. This exact drift (a prior skill trusted the research doc'stypeparam and broke) is why this skill's reference files were re-verified live rather than copied fromapi-reference.md.search_issuesdoes have a workingtypefilter ("issues"|"pulls") — unlikelist_issues. Itslabelsparameter is also shaped differently: a comma-separated string, not an array of names.- Labels are numeric IDs on write, name strings on read.
issue_write'slabelsparameter (used byadd_labels/replace_labels) takes IDs.list_issues/issue_readreturn names. Never resolve this yourself — composegitea-labels-milestones(seereferences/enrichments.md) to get IDs. - Milestone on
issue_readis{id, title}— an object, not a bare string. This skill only ever needs theid. (The bare-title-string case only happens on the PR side, which isgitea-prs' problem, not this skill's.) - Closing-keyword auto-close behavior is plausible but unconfirmed in our research docs. Our research docs confirm Gitea does NOT auto-close an issue on a plain PR merge (unlike GitHub) — closing keywords like
Fixes #N/Closes #Nin a commit message are not documented one way or the other. After a PR merges (agitea-prsoperation), always re-check the issue's state here viaissue_read method: "get"before deciding whether to close it manually — closing an already-closed issue is a harmless no-op, but don't assume a manual close is always needed. - Pagination is manual.
list_issuesandsearch_issuesreturn one page at a time. Iteratepage: 1, 2, ...until the returned count is less thanper_page. - HTTP 404 may actually mean 403. Gitea hides permission errors as not-found. If a call 404s unexpectedly, verify the token holds
write:issuescope (seereferences/issues.md's Token scope note) before concluding the issue doesn't exist.
Step 1 — Resolve owner and repo
Before any tool call, extract owner and repo from the git remote (skip this if an orchestrating caller already passed them in):
git remote get-url origin
If origin is not set or the URL is not a Gitea URL, stop and report: "No Gitea remote found — set origin to your Gitea instance URL."
Step 2 — Dispatch
| Invocation | Action |
|---|---|
/gitea-issues or /gitea-issues list |
List issues (optional state filter) |
/gitea-issues create |
Create an issue from conversation context — infers labels, checks milestone fit, applies a configured default assignee if set |
/gitea-issues <N> |
Get issue details (flag it as a PR if is_pull: true) |
/gitea-issues <N> comments |
Get an issue's comments |
/gitea-issues close <N> |
Close an issue |
/gitea-issues comment <N> |
Add a comment from conversation context |
/gitea-issues search <query> |
Cross-repo search via search_issues |
For full parameter detail on list_issues/issue_read/issue_write, read references/issues.md. For search_issues, read references/search.md. For the create-flow enrichments (label inference, milestone assignment, assignee workaround, dependency-linking), read references/enrichments.md.
Step 3 — Execute
list (default)
Call list_issues owner: <owner> repo: <repo> state: <"open"|"closed"|"all", default "all">. Remember: results may include PR entries (see Gotchas) — if the caller needs issues only, this tool cannot filter that server-side; note the limitation rather than silently mislabeling PR entries as issues.
create
- Extract
titleandbodyfrom conversation context (the most recent task, bug description, or explicit statement). Fall back to an empty body if nothing is available. - Run the enrichment sequence in
references/enrichments.md: infer labels (composinggitea-labels-milestones), check for a clearly-fitting open milestone (composing the same skill), and check for a configured default assignee. - Call
issue_write method: "create" owner: <owner> repo: <repo> title: <title> body: <body> labels: [<resolved IDs, or omit>] milestone: <resolved ID, or omit> assignees: [<default login, or omit>]. - Fire immediately — no confirmation step for the create itself.
<N> (get)
Call issue_read method: "get" owner: <owner> repo: <repo> issue_number: <N>. If is_pull: true, report that this number is actually a PR and suggest gitea-prs for full detail.
<N> comments
Call issue_read method: "get_comments" owner: <owner> repo: <repo> issue_number: <N>.
close <N>
Call issue_write method: "update" owner: <owner> repo: <repo> issue_number: <N> state: "closed". No method: "close" exists.
comment <N>
Extract the comment body from conversation context (same sourcing as create). Call issue_write method: "add_comment" owner: <owner> repo: <repo> issue_number: <N> body: <body>.
search <query>
Call search_issues query: <query>, adding owner, state, type, or labels filters if the request narrows scope (e.g. "search open PRs for X" → type: "pulls" state: "open").
Step 4 — Report
For reads: a compact table or numbered list — number, title, state, labels, milestone.
For writes: confirm what was created/updated with the issue number and URL if returned.
For errors: surface the HTTP code and message; check token scope per the Gotchas if a 404 looks wrong.