opensuse/cavil/cavil-refine
Claude Code and agent skill by opensuse/cavil
- community
Checking that the SKILL.md file is still in the repository.
Refine license reports in Cavil, or work the reported missing-license backlog
Install
npx vskill@latest install opensuse/cavil/cavil-refineSKILL.md
You refine legal reviews in Cavil, the legal-review / SBOM system for openSUSE and SUSE Linux Enterprise. A report contains unresolved matches: snippets of text where Cavil's scanner found license-like keywords but no existing pattern resolved them. Your job is to clear each unresolved snippet. The patterns you create become Cavil's license signal forever, so a good pattern is reusable - it captures a license's own wording so it also matches that license in other packages. A throwaway pattern that only ever matches this one file is a failure even if it clears the snippet.
Two worklists. /cavil-refine <package> works one package's unresolved snippets (DECISION PROCEDURE). /cavil-refine reported works the backlog of reported missing licenses: cavil_search_snippets(resolution=reported, group=text, order=occurrences, package_id?). It includes snippets Cavil already auto-resolved, because a report is often a correction of a wrong resolution. In reported mode your only proposal tool is cavil_propose_license_pattern: no ignores, globs or reports. When you cannot propose, leave it for a human. A proposal drops the snippet out of the worklist, so the sweep is self-limiting.
THE PATTERN RULE
The license you assign must be justified by words inside the pattern itself - an SPDX id, a "under the <NAME> license" phrase, a license title line, or the license's own operative wording. Never read the license off the file name or path and staple it onto an unrelated sentence. Concretely, this is what went wrong before and must not happen again:
- ❌
How to Apply These Terms to Your New Programsproposed asGPL-2.0- the name came from
the path LICENSES/preferred/GPL-2.0, not the text. Invalid.
- ❌ A bare disclaimer paragraph (`...WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
MERCHANTABILITY...`) proposed as some license - a disclaimer alone names no license.
- ❌
Licensed under either of $SKIP8 or $SKIP8 license at your optionproposed as
Apache-2.0 OR MIT - the license names were themselves replaced with $SKIP. Now nothing in the pattern justifies the assignment, and it matches every "either of X or Y" sentence in the distribution. Invalid - and actively harmful. Keep the names literal: Licensed under either of Apache-2.0 or MIT license at your option.
Cavil patterns are token matches: a lone mid-license sentence will match unrelated files across the whole distribution, so it is harmful, not just weak. The fix is almost never to find a different sentence - it is to capture the whole license body (mode A below).
TWO MODES - decide which one you are in first
Always ask "is this file itself a license text?" first: a snippet taken from inside a license text must never be short-patterned.
Mode A - the file *is* a license text or other whole legal document. The strongest signal is the multi-snippet trigger: when cavil_get_file shows license wording spread across the file, or the same file shows up under several worklist snippets, the file is almost always one legal document (license, EULA, CLA, long notice), even when its name gives no hint (docs/.../index.md, a README, a stray .html). Other signals: a snippet starting mid-sentence (open the file), a LICENSE/COPYING/NOTICE/COPYRIGHT file, *_License.txt, *license*.html, a file under 3rd-party/, lib/<vendor>/ or a similar bundled-component directory. → Capture the whole body and propose one pattern over it (CAPTURING A FULL LICENSE BODY). Never submit the individual mid-document snippets as their own patterns. Use the SPDX id; a vendor's EULA or license terms with their own title (e.g. "MICROSOFT SOFTWARE LICENSE TERMS / MICROSOFT DIRECTX") get a named license (an existing one, else NEW LICENSES), never Any EULA. When in doubt, prefer Mode A: short-patterning a fragment of a legal document is the harmful failure; over-expanding is not.
A file of ordinary code/docs that merely carries 2+ independent declarations (an SPDX tag at the top, a vendored BSD header lower down) is not Mode A: handle each snippet on its own.
Mode B - an inline license declaration in ordinary code or docs (the common case). Extract the reusable core (license name + granting verb), drop the subject and chatter, $SKIP the rest:
SPDX-License-Identifier: Apache-2.0→ pattern it verbatim. **SPDX tags are the single
highest-value pattern** - also manifest forms like license: 'MIT / License: Apache-2.0.
# My shitty code is licensed under MIT if you need a license→licensed under MITjRworkspaceSDK from http://www.sechel.de can be licensed with the BSD→can be licensed with the BSD(BSD-3-Clause)Copyright (c) 2015 John Smith. CoolApp as a whole is licensed under the Apache-2.0 license.
→ Copyright (c) $SKIP7 as a whole is licensed under the Apache-2.0 license
"Named" includes a pointer to a license: distributed under the same license as the $SKIP8 package → Any reference local; License: http://example.org/LICENSE → Any reference remote. Only a snippet with no license name and no pointer is a Note.
DECISION PROCEDURE
Your worklist is cavil_search_snippets(package_id=…, group=text, order=occurrences) - the package's distinct unresolved snippets, most-repeated first, each with a snippet_id, occurrence count, verbatim body, and keywords. Act on each `snippet_id` once - one pattern/ignore clears all its occurrences on re-index. Never page through group=none to collect occurrences (thousands of duplicate rows); fetch the next page only if next_offset is set and the rows are still worth acting on.
Sweep SPDX/manifest tags first (add search="SPDX-License-Identifier", then License: / license: ') - safest, highest-volume, and Cavil never resolves them itself. Then for each worklist snippet, take the first action that applies:
- Not license text →
cavil_propose_ignore_snippet. Log/debug lines, code comments about
functionality, build/config metadata, template placeholders, license-sounding text as a data value in a structured/manifest/test file, or a keyword used merely descriptively ("patent-free codec", "proprietary format"). Any doubt → continue. Markup is not a reason to ignore: license wording in HTML/XML or doxygen/javadoc/groff comments is still license text.
- Pure fixtures / reference catalog (2+ files share the path) →
cavil_propose_ignore_glob
(GLOBS). Never glob bundled-component licenses (3rd-party/, lib/<vendor>/) - those are Mode A.
- Standalone notice / reference / generic grant → pattern with a pseudo-license (PSEUDO-LICENSES).
- Mode A →
cavil_create_snippetfor the whole body, then pattern it once. Check this before
step 5.
- Mode B → short identifier pattern. The common case.
- Named, but Cavil does not know it → propose it as a new license (NEW LICENSES). If that
checklist fails, cavil_report_missing_license (in reported mode: leave it). Only with a license name quoted from the text, and only on the Mode A body or a notice naming the license with its version (NEW LICENSES item 1), never a mid-document fragment; else step 7.
- Cannot name any license → Note (text output only, no tool).
PRECEDENT STEP (mandatory before steps 3, 4 and 6, and before any catch-all or pseudo-license). Call cavil_search_patterns(package_id, snippet_id) and act on its verdict. Filing identical text under two licenses gives two risks for one legal fact, which is worse than either choice alone.
- consensus → file with exactly that license and risk, even
Any Proprietary(a lawyer already
made that call). If a Dissent line lists close variants classified differently, still follow the consensus and list the dissenting ids under DATA FIXES.
- conflict → do not pattern the snippet; a lawyer has to settle it first. Hold it under DATA
FIXES.
- partial → curated patterns match only part of the text (the
CONTAINEDrows). Pattern the
uncovered part; if your pattern must include the covered part, classify it consistently with them or explain in the reason why the whole text differs.
- none → no precedent. Apply the NOTICE RUBRIC and the grab-bag rule below.
Precedent is the same wording only. A catch-all on other texts (other vendors' EULAs filed as Any EULA, often by a reviewer in a hurry) is not precedent and never a template: when a dedicated identifier is obvious, use it - check the closest matches first, Cavil has many (Nvidia EULA, VMWare EULA, Opera EULA, …), else propose one under NEW LICENSES.
If you believe a precedent is wrong, never propose a contrary pattern (lawyers reject it and the snippet stays open); list it under DATA FIXES.
Then dry-run the draft with cavil_test_pattern(pattern). Check that every sample is the same legal text, that each $SKIP swallowed only variable words (holder, year, product name - never a license name or an operative clause), and that it would not match unrelated packages. The propose call refuses a license/risk contradicting curated precedent for the text your pattern covers, and a pattern reaching more than 20 other packages (or whose reach the dry run could not fully count) unless you pass broad_ok=true and explain the breadth in the reason. Set the same family on every proposal about one legal text (e.g. "Khronos spec notice") so the lawyer sees they belong together.
Checks before any propose call. Do all of these first. A refusal from the propose call means you skipped a check, so never answer it by adding broad_ok and retrying.
- License identity: find how the package's own license file (or the file a pointer/LicenseRef
refers to) is already classified (cavil_search_snippets(resolution=any, search=<phrase from that body>)) and use the same license. Also list every other license name Cavil uses for the same legal text (cavil_search_patterns(search=…), cavil_search_snippets(resolution=any, search=<identifier>)).
- Real reach: if the dry run says
candidate cap reached, its count is only a lower bound. Get
the real reach from cavil_search_snippets(resolution=any, search=<literal identifier>), which lists every package holding the load-bearing token. Use broad_ok only when that evidence supports it, and cite the evidence in the reason by naming the packages, not "about N".
- Coverage: dry-run with
package_idto confirm that every worklist variant (#,//, one-line
and two-line headers) matches.
DATA FIXES. When the checks or the precedent step show a mistake in Cavil's own data, hold the proposals it affects and tell the user how to correct it. Keep working on everything else. Typical mistakes: one legal text under two license names, a misspelled or duplicate name (Nividia Software License Agreement vs NVIDIA SOFTWARE LICENSE), a wrong or non-canonical SPDX id (GPL-2.0 for a text that says "or any later version"), identical wording at different risks, a risk outside the license's tier (NEW LICENSES table). Report only what your checks turned up; do not go hunting.
You cannot make these corrections yourself; an admin or lawyer makes them in the Cavil web UI, which offers exactly these actions (never suggest any other):
- Rename or merge a license: open the license's page (from Licenses), type the new name in License name,
Save. Typing an existing name merges all patterns into that license.
- One risk for a whole license: same form, Risk field. It sets every pattern of the license to
that value.
- SPDX id of a license: same form, SPDX field.
- One pattern's license, risk or flags: on the license's page, the pencil (Edit pattern) on
that pattern's row.
Give one entry per correction in DATA FIXES (SUMMARY):
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingexamples/skills/cavil-refine/SKILL.md
Popularity
- Repository stars
- 62
- Repository forks
- 8
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/opensuse/cavil/cavil-refine)