wikicommit-schema-propose
Detect wiki page types with no dedicated .wikicommit/schema/ file, propose a new standard (Schema.org) or custom type file, and open a PR for human review (no auto-merge). Use this only when someone e
Files2
View on GitHubSKILL.md.claude/skills/wikicommit-schema-propose/SKILL.md
GitHubwikicommit-schema-propose
Paths in this file.
references/…,scripts/…and../<other-skill>/…are relative to this Skill's directory — the one holding thisSKILL.md, which the runtime names when it loads the Skill — not to the repository root, because the Skills may be installed under.claude/skills/or.agents/skills/. Commands still run from the repository root, so spell the path out from there (python <this Skill's directory>/scripts/…). Paths starting with.wikicommit/are repository-root paths as before.
Detects type: values used by wiki pages that have no dedicated .wikicommit/schema/ file, and proposes a new schema type file via PR. .wikicommit/schema/ itself is off-limits to write directly from wikicommit-generate (that Skill's "Git operations: none, schema/: read-only" contract), so this Skill exists to be the one place schema files actually get added — and only by adding new files, never editing or deleting existing ones.
This complements coverage_gap_note (wikicommit-generate Pass 2): that mechanism records when an already-correct type is missing a field; this Skill addresses when the type itself isn't the best fit — e.g. pages generated as schema:DefinedTerm when schema:Game (with typicalAgeRange/gameItem/numberOfPlayers) would fit better, or schema:HowTo when schema:GovernmentService (with jurisdiction/availableChannel/hoursAvailable) would fit better. The two do not integrate — wikicommit-schema-propose does not consume coverage_gap_note.
Usage
/wikicommit-schema-propose
No arguments. Always runs a full scan.
Processing Flow
Step 0: Resolve Default Branch
gh repo view --json defaultBranchRef -q .defaultBranchRef.name
Record the result as <default branch> and use it everywhere below in place of a literal main — the repository's actual default branch is not guaranteed to be main. If this command fails (no GitHub remote, or gh not authenticated), fall back to main and warn the user that Step 6's branch/PR operations will fail if the repository's real default branch differs.
Step 1: Detect coverage gaps
python .wikicommit/scripts/check_schema_coverage.py
Parse each UNCOVERED: <type> (<N> pages, e.g. <path>) line — this is the deterministic, guaranteed-complete detection source (a scan of every page currently in .wikicommit/entity/). If none, report "No schema coverage gaps found" and stop.
Role:
wikicommit-generatePass 2b resolves most type-necessity judgments inline, at generation time, by writing an approved.wikicommit/schema/<Type>.mddirectly. This Skill's scan is the post-hoc safety net: pages generated by an older version, or any page that ends up using a type with no dedicated schema file through some other path. It is not the primary channel for new type proposals.
Step 2: Skip types that already have a proposal
For each detected type, compute <Type> (the type: value with the schema: prefix stripped, e.g. schema:Game → Game, schema:custom/Recipe → custom/Recipe) and <TypeSlug> (<Type> with / replaced by -, e.g. custom/Recipe → custom-Recipe) — same convention as wikicommit-merge's post-review PR branch naming.
gh pr list --head "wikicommit/schema-propose-<TypeSlug>" --state all --json number
One or more results (open or closed/rejected) → skip this type; do not re-propose it. Move to the next detected type. Do not batch this into a single unscoped gh pr list call — same --head-scoping rationale as wikicommit-merge §"Checking for Existing PRs".
Step 3: Classify as standard or custom
python .wikicommit/scripts/check_schema_org_type.py --type <Type>
- Exit
0→<Type>is a real Schema.org type. Continue with the Standard type path (Step 4). - Exit
1→ not in the Schema.org vocabulary. Continue with the Custom type path (Step 5).
Step 4: Standard type path
Read .wikicommit/schema-authoring.md and follow it. That file holds the whole procedure for writing a type file — browsing --list-properties, verifying each candidate with --property, dropping the ones reported ERROR:, the standard-type file format with default.md / Person.md as the fixed style references, the body as a list of reader questions, and how to write granularity (1–3 rules, one Boundary — rule, cross-type deference, the YAML-string discipline, and not contradicting a rule stated elsewhere in the pipeline). Four paths write type files and only the judgment differs between them, so the procedure lives in one place rather than four.
What this Skill supplies on top of it:
- The evidence. Select the candidate properties against the example page(s) from Step 1 — what those pages actually discuss — rather than against
<Type>'s definition in the abstract. This is the same judgmentwikicommit-generatePass 3 exercises when filling in a schema template. provenance: schema-propose. Do not copy theprovenance: defaultthatPerson.mdshows — each write site stamps its own origin. This applies uniformly to Step 5's custom-type path as well.- Optional commentary. You may also pick one candidate parent or near-neighbor type name to mention in the PR description. It is commentary only; this Skill still creates one file for
<Type>as-is.
Three things this step is accountable for even if that Read is skipped: every property goes through check_schema_org_type.py before it enters properties:, one granularity rule starts with Boundary — (em dash, not a colon), and provenance is schema-propose.
If .wikicommit/schema-authoring.md is not present (a wiki initialized before it shipped, or Skills updated without re-running init), read the copy in the Skill tree instead — ../wikicommit-init/scripts/templates/schema-authoring.md, the same file init.py expands, which install.sh and npx skills add carry into every installation of these Skills (the route /wikicommit-update already takes for a script an older repository does not have yet). Say which copy you read. Only if neither is readable, do not write the file: skip this type, name the missing file and /wikicommit-init --no-overwrite as the way to get it, and move on to the next detected type. Unlike a Skill whose every run needs the file, this one reaches it only when a type is actually being proposed. The gap stays visible — check_schema_coverage.py is what detected this type in the first place and will report it again on the next /wikicommit-status.
Step 5: Custom type path
- Derive
<Name>(the segment aftercustom/) from thetype:value already used by the detected pages. It must already follow the custom-type naming rule (PascalCase, word characters only, no hyphen) — this Skill only adds the missing schema file, it never renames thetype:value on existing wiki pages. If it doesn't follow the rule (e.g. contains a hyphen), skip this type, log a warning naming the offending pages, and move to the next detected type — renaming is out of scope and left to a human viawikicommit-fix. - Generate
.wikicommit/schema/custom/<Name>.mdin the custom-type format — unlike a standard type, explicitly document each property's meaning/type/constraints in prose, since the LLM has no built-in knowledge of a project-specific custom type. Pick awikicommit.basevalue that names the closest real Schema.org parent type as a reference point (informational only, not verified against the vocabulary — custom types by definition fall outside it). Setwikicommit.provenance: schema-proposehere too (Step 4's note above applies uniformly to both paths). Read.wikicommit/schema-authoring.md'sgranularitysection and follow it here as well — a custom type carriesgranularityexactly like a standard one, so the 1–3 rules, the oneBoundary —rule, cross-type deference, the YAML-string discipline (Boundary — …with an em dash, neverBoundary: …; no#mid-bullet) and the don't-contradict-the-pipeline rule all apply unchanged. Its section on the body applies too — write the body as aREADER QUESTIONSblock exactly as it describes, since what readers of the type want to know does not depend on whether the type is in the vocabulary. Its property and the rest of its file-format sections do not: they resolve names against the Schema.org vocabulary, which a custom type is by definition outside of. Use the same missing-file handling Step 4 states above (the Skill-tree copy first, and only then skip this type). - No
check_schema_org_type.pyproperty verification applies here (nothing to check against). Instead, write one or two sentences explaining why no existing Schema.org standard type fits and why thewikicommit.baseyou picked is the closest parent. Put that text in the file itself, as awikicommit.rationale:value in the samewikicommit:block — a custom type sits outside the Schema.org vocabulary, so this reasoning is the only durable record of why the type exists and is what a later reader, or a future decision to migrate the type onto a standard one, has to work from. Then reuse the same text verbatim in the PR description's "Schema.org standard type could not reasonably replace this" checklist item (the custom-type-only line in the template below), which is the human reviewer's main thing to scrutinize for a custom type.rationale:is custom-type-only — do not add it in Step 4's standard-type path, where the type's existence in the vocabulary is itself the justification. Do not confuse it with arationalekey that a given custom type may happen to declare under its ownproperties:block: that one is a property of the entities the type describes, this one is about the type's design.
Step 6: Branch, commit, PR (no auto-merge)
Repeat for each type that reached this step (mirrors wikicommit-merge's post-review PR mechanics, but this Skill's PRs are never auto-merged):
# 1. Branch from the default branch's HEAD (<default branch> from Step 0)
git checkout "<default branch>"
git checkout -B wikicommit/schema-propose-<TypeSlug>
# 2. Write the new schema file — ONE new file only, never edit/delete an existing one
# .wikicommit/schema/<Type>.md (standard type)
# .wikicommit/schema/custom/<Name>.md (custom type)
# 3. Commit
git add .wikicommit/schema/<path from step 2>
git commit -m "$(cat <<'EOF'
schema: propose <Type> for <N> uncovered pages
<Co-Authored-By line>
Generated-By: <current model ID>
EOF
)"
# 4. Push -> PR (no --auto, no gh pr merge anywhere in this Skill)
git push origin wikicommit/schema-propose-<TypeSlug>
gh pr create \
--title "$(cat <<'EOF'
schema: propose <Type>
EOF
)" \
--body "<PR Description Template below>" \
--base "<default branch>"
# 5. Return to the default branch
git checkout "<default branch>"
# 6. Brief pause before the next type's push/PR-create (GitHub secondary rate limit)
sleep 2
<!-- commit-trailers:start (this block is identical in wikicommit-merge, -schema-propose, -update, -init and -organize; tests/test_commit_trailer_vendor_table.py holds them together) -->
Commit trailers. Always write Generated-By: <current model ID>: the ID of the model actually running this Skill, exactly as the runtime reports it — the same self-reported value wikicommit-generate writes into a page's generated_by (keep any suffix; do not shorten or normalize it; never hardcode one). Then choose <Co-Authored-By line> from the start of that same ID, so the two lines can never name different vendors:
<current model ID> starts with |
<Co-Authored-By line> |
|---|---|
claude-, or claude- after a provider prefix ending in anthropic. (Bedrock, e.g. us.anthropic.claude-…) |
Co-Authored-By: <Claude display name> <noreply@anthropic.com> — the model's human-readable name, or just Claude when it is not known with confidence |
gpt- or codex |
Co-Authored-By: Codex <noreply@openai.com> |
| anything else | no Co-Authored-By line at all — Generated-By already records the model |
GitHub resolves a co-author by the email address and shows that vendor's avatar on the commit, so a line naming a vendor that did not run this Skill misattributes it; writing none is the correct answer for a model not in the table. Decide by the model, not by the harness running it — one harness can run models from more than one vendor. If the harness appends its own co-author line after this message, leave it; an identical duplicate does no harm.
<!-- commit-trailers:end -->--title is passed through a quote-delimited heredoc on both paths, never a plain double-quote embedding: on the custom-type path <Type> comes from the pages' existing type: value, which Step 5.1 only checks by reading, not by a script, so it may hold shell metacharacters — and applying the heredoc unconditionally costs nothing on the standard-type path.
Skip step 6 after the last proposed type. If git push or gh pr create errors, log it, leave the branch for cleanup, and move to the next type rather than aborting the whole run (same resilience pattern as wikicommit-merge's post-review PR loop).
PR Description Template
<!-- skill-vocabulary-exception: PR body; its reader is the developer or reviewer deciding whether to merge the schema file -->## Proposed type
`schema:<Type>` — <N> existing page(s) currently fall back to `default.md` for this type.
## Affected pages (examples)
- <path from Step 1, one per line, up to 5>
## Checklist for review
- [ ] Page count and examples above look right for this type
- [ ] Schema.org standard type could not reasonably replace this: <the `wikicommit.rationale` text written in Step 5.3, verbatim> <!-- only present for a custom-type proposal -->
- [ ] `properties:` field choices are appropriate
- [ ] `granularity` rules make sense for how this Wiki actually uses the type
- [ ] Next-best alternative type, if any: <alternatives from Step 1, or "none">
🤖 Generated with a [wikicommit-schema-propose](https://github.com/wikicommit/wikicommit) proposal — merge only after reviewing the schema file's actual content, this description alone is not sufficient review.
Completion Notice
Report, per detected type: proposed (with PR link) / skipped (duplicate proposal exists) / skipped (invalid custom name) / failed (push or PR-create error).
Notes
- Only ever adds a new file under
.wikicommit/schema/. Never edits or deletes an existing schema file. - Never touches
.wikicommit/entity/— existing pages keep using their currenttype:value; migrating them to the newly proposed type (if desired) is a separate, human-driven decision. - Never auto-merges. Every PR this Skill opens waits for a human to review and merge it manually (unlike
wikicommit-merge's bulk-update PR, or the PR thatreview-issue-close-sync.ymlopens and auto-merges once a review tracking Issue is closed). .wikicommit/schemaorg-vocab.json(built lazily bycheck_schema_org_type.py, committed to Git) has no TTL/auto-refresh — delete it manually to force a rebuild against the latest Schema.org vocabulary.