code-jig 0.12.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. code_jig-0.12.0.dist-info/METADATA +154 -0
  2. code_jig-0.12.0.dist-info/RECORD +52 -0
  3. code_jig-0.12.0.dist-info/WHEEL +4 -0
  4. code_jig-0.12.0.dist-info/entry_points.txt +2 -0
  5. code_jig-0.12.0.dist-info/licenses/LICENSE +202 -0
  6. codejig/__init__.py +1 -0
  7. codejig/__main__.py +106 -0
  8. codejig/_core/VERSION +2 -0
  9. codejig/_core/bench/requirements.toml +4 -0
  10. codejig/_core/core/AGENTS.core.md +9 -0
  11. codejig/_core/core/agents/explorer.toml +24 -0
  12. codejig/_core/core/agents/judge.toml +19 -0
  13. codejig/_core/core/agents/reviewer.toml +10 -0
  14. codejig/_core/core/tiers.toml +4 -0
  15. codejig/_core/skills/bug-hunt/SKILL.md +131 -0
  16. codejig/_core/skills/code-analysis/SKILL.md +72 -0
  17. codejig/_core/skills/codegen/SKILL.md +46 -0
  18. codejig/_core/skills/cross-review/SKILL.md +32 -0
  19. codejig/_core/skills/grilling/SKILL.md +60 -0
  20. codejig/_core/skills/hld-trace/SKILL.md +69 -0
  21. codejig/_core/skills/improve/SKILL.md +38 -0
  22. codejig/_core/skills/redacao/SKILL.md +114 -0
  23. codejig/_core/skills/redacao/checar.py +75 -0
  24. codejig/_core/skills/redacao/reference.md +118 -0
  25. codejig/_core/skills/regression-tests/SKILL.md +53 -0
  26. codejig/_core/skills/remove-ai-attribution/SKILL.md +33 -0
  27. codejig/_core/skills/skill-validate/SKILL.md +58 -0
  28. codejig/_core/skills/web-consensus/SKILL.md +55 -0
  29. codejig/analyze.py +499 -0
  30. codejig/atomicwrite.py +49 -0
  31. codejig/collect.py +311 -0
  32. codejig/doctor.py +370 -0
  33. codejig/evidence.py +418 -0
  34. codejig/feedback.py +165 -0
  35. codejig/gitgate.py +278 -0
  36. codejig/hooks.py +64 -0
  37. codejig/humanize.py +206 -0
  38. codejig/install.py +381 -0
  39. codejig/managed.py +64 -0
  40. codejig/migrate.py +515 -0
  41. codejig/overlay.py +43 -0
  42. codejig/paths.py +40 -0
  43. codejig/probe.py +136 -0
  44. codejig/review.py +73 -0
  45. codejig/scrub.py +255 -0
  46. codejig/skillcheck.py +400 -0
  47. codejig/skilllint.py +99 -0
  48. codejig/sources.py +248 -0
  49. codejig/tiers.py +63 -0
  50. codejig/tokens.py +118 -0
  51. codejig/trace.py +137 -0
  52. codejig/watermark.py +147 -0
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import os
4
+ import re
5
+ import statistics
6
+ import sys
7
+ import urllib.parse
8
+ import urllib.request
9
+
10
+ LT = os.environ.get("LANGUAGETOOL_URL", "http://127.0.0.1:8010")
11
+ SKIP_RULES = {"WHITESPACE_RULE", "UPPERCASE_SENTENCE_START", "FORMAL_PRA_PARA", "REMOVER_EU_NÓS"}
12
+
13
+
14
+ def prose(text):
15
+ text = re.sub(r"\A---\n.*?\n---\n", "", text, flags=re.S)
16
+ text = re.sub(r"```.*?```", "", text, flags=re.S)
17
+ url = r"\((?:[^()]|\([^()]*\))*\)"
18
+ text = re.sub(r"!\[[^\]]*\]" + url, "", text)
19
+ text = re.sub(r"\[([^\]]*)\]" + url, r"\1", text)
20
+ text = re.sub(r"`[^`]*`", "X", text)
21
+ lines = [l for l in text.splitlines() if l.strip() and not l.startswith(("#", ">"))]
22
+ return [l.strip() for l in lines]
23
+
24
+
25
+ def ritmo(paragraphs):
26
+ body = " ".join(paragraphs)
27
+ sentences = [s for s in re.split(r"(?<=[.!?])\s+", body) if len(s.split()) > 1]
28
+ sl = [len(s.split()) for s in sentences]
29
+ pl = [len(p.split()) for p in paragraphs]
30
+ words = sum(pl)
31
+ cv = lambda xs: statistics.stdev(xs) / statistics.mean(xs) if len(xs) > 1 else 0.0
32
+ return {
33
+ "palavras": words,
34
+ "frases": len(sl),
35
+ "cv_frase": round(cv(sl), 2),
36
+ "paragrafos": pl,
37
+ "cv_paragrafo": round(cv(pl), 2),
38
+ "eu_por_100": round(100 * len(re.findall(r"\b(eu|meu|minha|me|comigo)\b", body, re.I)) / max(words, 1), 1),
39
+ "digitos_por_100": round(100 * len(re.findall(r"\d+", body)) / max(words, 1), 1),
40
+ }
41
+
42
+
43
+ def languagetool(paragraphs):
44
+ data = urllib.parse.urlencode({"language": "pt-BR", "text": "\n\n".join(paragraphs)}).encode()
45
+ with urllib.request.urlopen(f"{LT}/v2/check", data, timeout=60) as r:
46
+ matches = json.load(r)["matches"]
47
+ for m in matches:
48
+ if m["rule"]["id"] in SKIP_RULES or m["rule"]["id"].startswith("PT_BARBARISMS"):
49
+ continue
50
+ ctx = m["context"]
51
+ frag = ctx["text"][ctx["offset"] : ctx["offset"] + ctx["length"]]
52
+ fix = ", ".join(x["value"] for x in m["replacements"][:3])
53
+ yield f'{m["rule"]["id"]}: "{frag}" -> {fix or "?"} ({m["message"]})'
54
+
55
+
56
+ def demo():
57
+ p = prose("---\nt: x\n---\n# H\n\nEu fiz `a` e [b](u_(x)).\n\n> nota\n\nOutra frase curta. E mais uma aqui.\n")
58
+ assert p == ["Eu fiz X e b.", "Outra frase curta. E mais uma aqui."], p
59
+ r = ritmo(p)
60
+ assert r["palavras"] == 12 and r["frases"] == 3 and r["eu_por_100"] == 8.3, r
61
+
62
+
63
+ if __name__ == "__main__":
64
+ if len(sys.argv) != 2:
65
+ sys.exit("uso: checar.py artigo.md (ou --demo)")
66
+ if sys.argv[1] == "--demo":
67
+ demo()
68
+ sys.exit(0)
69
+ paragraphs = prose(open(sys.argv[1], encoding="utf-8").read())
70
+ print(json.dumps(ritmo(paragraphs), ensure_ascii=False))
71
+ try:
72
+ for line in languagetool(paragraphs):
73
+ print(line)
74
+ except OSError as e:
75
+ print(f"LanguageTool fora do ar em {LT} ({e}); suba com: podman run -d --rm --name languagetool -p 127.0.0.1:8010:8010 docker.io/erikvl87/languagetool")
@@ -0,0 +1,118 @@
1
+ # Redação: reference
2
+
3
+ ## What a technical article is
4
+
5
+ A blog post about how something was built is an *explanation* in Diátaxis terms: it answers "why is it like this", not "how do I do X". It can show code, but it is not a tutorial and should not turn into numbered steps. Source: https://diataxis.fr/explanation/
6
+
7
+ Classic style (Pinker, *The Sense of Style*): the writer shows the reader something in the world, as one equal to another. No warm-up, no persuasion tricks, no talking about the text itself.
8
+
9
+ ## Structure
10
+
11
+ - **Open with a fact, not a preamble.** The first two sentences carry a concrete thing: a number, a bug, a scene. Never "Neste post vou falar sobre", never "No cenário atual".
12
+ - **Concrete before abstract.** Show the code, the number or the failure, then name the principle. A principle with no example goes.
13
+ - **Headings say what the section shows.** "A URL decide o idioma" beats "Internacionalização". No "Introdução", no "Conclusão".
14
+ - **A number when the number is the point.** "Rápido" means nothing; "12 páginas em 4,9 s" means something. But a paragraph with three numbers, two file names and a commit hash is a changelog: keep the one number the reader will remember and link the rest.
15
+ - **Say what is missing.** An honest gap makes the rest credible. A list of virtues with no cost reads as an ad.
16
+ - **End on the next concrete thing**, a limit or an open question. No summary of what the reader just read, no moral, no call to action ("Faz isso no seu site").
17
+ - **Someone is talking.** The author has opinions, gets annoyed, is wrong, is unsure. A text where every sentence is a verified neutral fact has no one in it.
18
+
19
+ ## Portuguese (pt-BR)
20
+
21
+ Each rule with a bad → good pair.
22
+
23
+ | Rule | Ruim | Bom |
24
+ |---|---|---|
25
+ | Verb over noun (nominalização) | realizar a implementação do cache | implementar o cache |
26
+ | No gerundismo | vamos estar analisando | vamos analisar |
27
+ | "Onde" only for places | o teste onde o erro aparece | o teste em que o erro aparece |
28
+ | No "a nível de" | a nível de arquitetura | na arquitetura |
29
+ | No "o mesmo" as pronoun | abri o arquivo e editei o mesmo | abri o arquivo e o editei |
30
+ | Active voice with a subject | foi decidido que o CI roda o lint | decidi que o CI roda o lint |
31
+ | "Se" impessoal sparingly | percebe-se que o build falha | o build falha |
32
+ | Short sentences, one idea each | a sentence of 45 words with three "que" | split it |
33
+ | Crase | devido à isso / referente a página | devido a isso / referente à página |
34
+ | Hyphen, 2009 agreement | auto-avaliação, anti-padrão | autoavaliação, antipadrão |
35
+ | Decimal comma, unit spaced | 4.9s, 50 % | 4,9 s, 50% |
36
+
37
+ English terms: use the word the Brazilian developer says (*build*, *deploy*, *commit*, *bundle*, *lint*). Do not italicise them and do not force a translation nobody uses ("implantação" for deploy reads like a manual). Translate when Portuguese has a word in daily use: *teste*, *ilha* (Astro island), *janela*, *acessibilidade*. Code identifiers go in backticks and are never translated.
38
+
39
+ Person: first person singular for a personal blog ("eu medi"). "A gente" fits a casual register; pick one and keep it. Address the reader as "você".
40
+
41
+ ## AI tells
42
+
43
+ Habits that make prose worse, whoever wrote it. Remove on sight. Full list in English: https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing (the `humanizer` skill covers it, if installed).
44
+
45
+ - **Contrast that only adds weight**: "não é apenas X, é Y", "não se trata de X, mas de Y", "mais do que X, é Y". State Y.
46
+ - **Stock words**: crucial, fundamental, essencial, robusto, jornada, mergulhar, desvendar, no cenário atual, em um mundo, vale ressaltar, é importante destacar, em suma, em resumo, por fim mas não menos importante, transformador, potencializar, alavancar, ecossistema (outside its technical sense).
47
+ - **Triads by reflex**: three adjectives or three clauses where the meaning has one or two.
48
+ - **Dashes as the universal connector**: use a comma, a colon, parentheses or a full stop. At most one pair of dashes per article, and only for a real aside.
49
+ - **Closing one-liners**: a paragraph that ends with a short sentence repeating its point ("E isso faz toda a diferença.").
50
+ - **Staged run-up**: "A verdade é que", "O ponto é", "Aqui está o segredo:".
51
+ - **Bold labels and decorative lists**: prose that became bullets with a bolded first word. An article is paragraphs; a list only for things that are genuinely a list.
52
+ - **Connector piles**: "além disso", "dessa forma", "nesse sentido" opening consecutive paragraphs.
53
+ - **Inflated significance**: "um marco", "revolucionou", "mudou completamente". Say what changed and by how much.
54
+ - **Talking about the text**: "neste artigo", "como vimos acima", "vamos explorar".
55
+
56
+ ### Structural tells
57
+
58
+ Avoiding the words above is not enough: a model that drops "crucial" and every dash still writes in its own shape. These came from a draft that had none of the word-level tells and still read as machine-made from the first line.
59
+
60
+ - **Even rhythm.** Every paragraph four to six sentences of similar length, each built the same way (claim, evidence, consequence). Vary on purpose: a one-line paragraph next to a long one, a long sentence that wanders when the thought wanders, a fragment.
61
+ - **Inventory paragraphs.** "Um confere... Outro garante... Outro checa... E tem um que...", "Pra mim, X quer dizer cinco coisas", a list of facts walked through in prose. Pick the one example that matters and tell it.
62
+ - **Fact density.** Identifiers, counts and commit hashes in every paragraph. The reader cannot hold them; link the commit, keep the story.
63
+ - **Narrator without a person.** No opinion, no joke, no doubt, no "eu achava". Everything reported, nothing felt.
64
+ - **Borrowed informality.** "tá" and "pra" sprinkled over formal syntax. The register is the author's, taken from their own text, and it holds through the whole article.
65
+ - **Researched trivia.** A book's publication year, a spec's exact threshold, commit counts per year: facts the author never lived and would never say. A fact belongs when the author did it, used it or hit it.
66
+ - **Swallowed scope.** The article grew to hold everything the apuração found. One idea per post; the rest is the next pauta.
67
+
68
+ ### On AI detectors
69
+
70
+ Detectors are classifiers trained on model output. They flag predictable, even prose, and they also flag formal or non-native human writing: seven detectors marked 61% of TOEFL essays by human writers as AI (Liang et al., 2023: https://arxiv.org/abs/2304.02819). Do not chase a score and never rewrite to fool one. A flagged draft is a symptom that the author is missing from the text; the fix is the entrevista, not synonyms.
71
+
72
+ ## Checklist before the editor's last aprova
73
+
74
+ 1. Every number and name is in the fact sheet with a source.
75
+ 2. The first two sentences carry a concrete fact.
76
+ 3. No heading is generic.
77
+ 4. No paragraph ends in a one-line moral.
78
+ 5. None of the AI tells above. Search the text for "não é apenas", "crucial", "-", "além disso", "jornada".
79
+ 6. Every paragraph is one line in the file (no hard wrap).
80
+ 7. At least one honest limit is stated.
81
+ 8. Code in backticks, identifiers untranslated, decimal comma in prose.
82
+ 9. Every section carries something from the entrevista or the author's own text, and no feeling, habit or reason was invented for them.
83
+ 10. Paragraph lengths vary; no three paragraphs in a row share the same shape.
84
+ 11. The word count is within the pauta's target, and the scope is still the author's idea.
85
+ 12. No closing summary section and no call to action.
86
+
87
+ ## Reading list
88
+
89
+ Portuguese, writing:
90
+
91
+ - Othon M. Garcia, *Comunicação em Prosa Moderna* (FGV). The Brazilian classic on building a paragraph and an argument.
92
+ - *Manual de Redação da Presidência da República*, 3ª ed.: https://www.gov.br/planalto/pt-br/conheca-a-presidencia/manual-de-redacao-da-presidencia-da-republica. Clarity, concision, the "o mesmo" and gerund rules.
93
+ - *Manual de Comunicação da Secom do Senado*: https://www12.senado.leg.br/manualdecomunicacao. A newsroom style guide with one entry per style question (datas, maiúsculas) and a guide on using AI in writing.
94
+ - Microsoft pt-BR localization style guide (in the list): https://learn.microsoft.com/en-us/globalization/reference/microsoft-style-guides. How a large tech company handles English terms, "você" and capitalisation in Portuguese.
95
+
96
+ Portuguese, technical writing worth reading:
97
+
98
+ - Fabio Akita: https://akitaonrails.com/. Long-form, opinionated, full of numbers and real setups.
99
+ - Elton Minetto: https://eltonminetto.dev/. Short, direct Go and architecture posts.
100
+ - Lucas Santos: https://lsantos.dev/. Clear explanations of Node.js and TypeScript.
101
+ - Building Nubank: https://building.nubank.com/pt-br/. Engineering blog that writes for engineers, not recruiters.
102
+ - TabNews: https://www.tabnews.com.br/. Uneven, but shows what Brazilian developers actually read and discuss.
103
+
104
+ English, on writing:
105
+
106
+ - Google Technical Writing One and Two: https://developers.google.com/tech-writing
107
+ - Paul Graham, "Write Simply": https://paulgraham.com/simply.html
108
+ - Julia Evans, "Some tactics for writing in public": https://jvns.ca/blog/2023/08/07/tactics-for-writing-in-public/
109
+ - Dan Luu, "Writing non-advice": https://danluu.com/writing-non-advice/
110
+ - Steven Pinker, *The Sense of Style* (2014).
111
+
112
+ References often cited in articles about reliability:
113
+
114
+ - Google SRE book: https://sre.google/sre-book/table-of-contents/
115
+ - Kent C. Dodds, the testing trophy: https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications
116
+ - Ham Vocke, "The Practical Test Pyramid": https://martinfowler.com/articles/practical-test-pyramid.html
117
+ - Core Web Vitals: https://web.dev/articles/vitals
118
+ - WCAG 2.2: https://www.w3.org/TR/WCAG22/
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: regression-tests
3
+ description: Use when fixing a bug, changing behaviour or adding a feature in code that has tests, or when the user asks whether a change is covered by tests, wants regression tests, or wants coverage of the changed lines.
4
+ ---
5
+
6
+ # Regression tests
7
+
8
+ Every behaviour change ships with a test that fails without the change and passes with it.
9
+
10
+ ## Bug fix
11
+
12
+ 1. Write the smallest test that reproduces the bug through the public interface.
13
+ 2. Run it and watch it fail for the reason in the bug report, not for a typo or a missing import.
14
+ 3. Fix the code, not the test.
15
+ 4. Run the test, then the whole suite.
16
+
17
+ ## New or changed behaviour
18
+
19
+ Write the test first, watch it fail, implement, watch it pass. When the change comes from a requirement, tag the test with its ID (see the `hld-trace` skill).
20
+
21
+ ## Follow the repo
22
+
23
+ Put tests where the repo already keeps them, with its framework, naming and fixtures. Do not add a test framework the repo does not use.
24
+
25
+ ## Coverage of the changed lines
26
+
27
+ [diff-cover](https://github.com/Bachmann1234/diff_cover) reads a Cobertura XML report and lists the changed lines no test executes. Install it with `pip install diff-cover`.
28
+
29
+ | Stack | Produce `coverage.xml` |
30
+ |---|---|
31
+ | Python | `coverage run -m pytest`, then `coverage xml` (in PowerShell 5.1, which has no `&&`: `coverage run -m pytest; coverage xml`) |
32
+ | .NET | `DOTNET_CLI_TELEMETRY_OPTOUT=1 dotnet test --collect:"XPlat Code Coverage"` writes `TestResults/*/coverage.cobertura.xml` |
33
+ | Node with c8 | `npx c8 --reporter=cobertura npm test` writes `coverage/cobertura-coverage.xml` |
34
+ | Vitest | `npx vitest run --coverage --coverage.reporter=cobertura` writes `coverage/cobertura-coverage.xml` |
35
+ | Jest | `npx jest --coverage --coverageReporters=cobertura` writes `coverage/cobertura-coverage.xml` |
36
+
37
+ Windows PowerShell has no `NAME=value command` form: write the variable first in the same command, for example `$env:DOTNET_CLI_TELEMETRY_OPTOUT = '1'; dotnet test --collect:"XPlat Code Coverage"`.
38
+
39
+ Then:
40
+
41
+ ```
42
+ diff-cover <report.xml> --compare-branch=origin/main --include-untracked
43
+ ```
44
+
45
+ Pass several reports at once for a multi-stack repo. Every uncovered changed line is either covered by a new test or explained: generated code, logging, a branch that only a real outage reaches.
46
+
47
+ ## Is the test good enough
48
+
49
+ A test that never fails proves nothing. For important logic, run mutation testing on the changed files (the `bug-hunt` skill): a surviving mutant is a regression the tests would miss.
50
+
51
+ ## Report
52
+
53
+ Name the test that failed before the change and passes after it, the full suite result, and each changed line diff-cover listed with the test that now covers it or the reason it stays uncovered.
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: remove-ai-attribution
3
+ description: "Use when AI attribution leaked into git history - \"Co-authored-by: Codex\", \"Co-Authored-By: Claude\", \"Generated with\" lines in commit messages - and must be removed without changing anything else, when the user asks to scrub or purge AI or co-author marks from commits, or when a push is refused because \"commit messages carry AI attribution\"."
4
+ ---
5
+
6
+ # Remove AI attribution
7
+
8
+ A safety net, not the rule: the rule (no AI attribution anywhere) is in the base instructions, and the git gate strips trailers before they land. Use this only when attribution already reached commits.
9
+
10
+ `code-jig scrub` decides everything; do not re-derive its work from git logs. It rewrites commit messages only, only on commits by the user (`git config user.email`, every `codejig.email`, and each `--author`), checks that trees, authors, committers and dates are unchanged, restores every ref if that check fails, and is deterministic: the same history gives the same new SHAs on every clone.
11
+
12
+ ## Procedure
13
+
14
+ 1. `code-jig scrub --dry-run` in the repo lists the commits that carry attribution. Nothing listed: stop.
15
+ 2. Show the list and get a yes for this repo.
16
+ 3. `code-jig scrub`. It saves a backup bundle in the git directory first and prints its path: that is the safe point. Keep the path in the reply. It rewrites local branches and tags, prints one `git push --force-with-lease=...` command per branch, and never pushes.
17
+ 4. Pushing rewrites shared history. Get a yes for each push command, then run it exactly as printed: the lease refuses the push if someone pushed in the meantime.
18
+ 5. Other clones: never repair them by hand. In each one, with a yes, run this procedure from step 1. Scrub gives the same SHAs there, so after `git fetch`, `git status -sb` shows the branch even with its upstream and there is nothing to push. Anything else (ahead, behind or diverged) means that clone has its own commits: stop and ask the user.
19
+ 6. Old commits stay reachable by SHA on the server (and in pull request refs) until the host garbage-collects them. Say so; removing them needs the hosting admin or recreating the repository, which only the user decides.
20
+
21
+ ## Undo
22
+
23
+ Before pushing, the backup restores every branch and tag: `git fetch --update-head-ok <bundle> "+refs/heads/*:refs/heads/*" "+refs/tags/*:refs/tags/*"`. After pushing, restoring needs another lease-protected push, which only the user decides.
24
+
25
+ ## Common mistakes
26
+
27
+ | Mistake | Instead |
28
+ |---|---|
29
+ | Rewriting other people's commits | Only the user's identities; pass `--author` for an old address of the user, never for someone else. |
30
+ | `git push --force` | Only the printed `--force-with-lease` commands. |
31
+ | `--no-verify` to get past the gate | Scrub, then push normally. |
32
+ | Resetting other clones to the remote | Run this procedure in each clone (step 5); a clone that differs is the user's call. |
33
+ | Deleting the backup bundle | Keep it until every clone matches the remote. |
@@ -0,0 +1,58 @@
1
+ ---
2
+ name: skill-validate
3
+ description: Use when a SKILL.md is about to ship or was just edited, when a skill is reviewed or audited, when a skill seems ignored, skipped or misread by agents, or when the user says "validate this skill", "lint the skill", "check my skill", "is this skill any good".
4
+ ---
5
+
6
+ # Validate a skill
7
+
8
+ Three passes. A script decides everything a pattern can decide; a reviewer from another model family decides the rest, in a fresh context, because the author of a skill already knows what it meant to say.
9
+
10
+ ## Pass 1: mechanical
11
+
12
+ ```sh
13
+ code-jig lint-skill path/to/skill-dir
14
+ ```
15
+
16
+ `FAIL` breaks loading or a hard rule and exits 1. `WARN` is a judgement call. Run pass 2 whatever pass 1 says: its FAILs go in the report with everything else.
17
+
18
+ ## Pass 2: judgement
19
+
20
+ This skill asks for a subagent: call `spawn_agent` with `agent_type` `reviewer` and a message holding the full SKILL.md text and this rubric, then wait for it. Do not fork this conversation into it, and do not judge the rubric yourself instead.
21
+
22
+ | # | Rule |
23
+ |---|---|
24
+ | 1 | The description states triggering conditions only. A description that summarises the workflow becomes a shortcut agents take instead of reading the body. |
25
+ | 2 | Every rule the skill enforces is reachable from the body, not only from the description. |
26
+ | 3 | Guidance matches the failure: a rule broken under pressure needs a prohibition and the excuses it answers; wrong-shaped output needs a recipe naming the parts in order; an omitted element needs a slot in a template. |
27
+ | 4 | No clause that reopens a rule ("unless it matters", "where appropriate"). |
28
+ | 5 | No narrative: no session logs, dated stories, "we found this once". |
29
+ | 6 | Reference an agent can act on, not the author's reasoning. |
30
+ | 7 | One worked example, not the same pattern repeated per language. |
31
+ | 8 | Flowcharts only for non-obvious decisions; tables and lists carry reference. |
32
+ | 9 | Words a searching agent would type appear early: error strings, symptoms, tool and command names. |
33
+ | 10 | Heavy reference and scripts sit in their own files, named from SKILL.md. |
34
+
35
+ Require one line per rule, `N | PASS or FAIL | shortest quote that decides it | one-line fix`, then `VERDICT: ship` or `VERDICT: fix N, N`. Prose instead of rows means the contract was not stated firmly enough: restate it and spawn again.
36
+
37
+ ## Pass 3: Codex runs it
38
+
39
+ A skill that reads well can still name tools Codex does not have, or never trigger. After pass 2 says `VERDICT: ship` and the skill is installed (`code-jig install`); when pass 2 says fix, skip pass 3 and report it as skipped because pass 2 failed:
40
+
41
+ ```sh
42
+ code-jig skill-check path/to/skill-dir --review --live
43
+ ```
44
+
45
+ It needs an `evals.toml` next to SKILL.md with at least one `[[case]]` (`prompt`, and any of `commands`, `output`, `spawns`, `fixture`, `commits`, `sandbox`). It runs a Codex review on the `review` tier, then each case through `codex exec`, and writes `.skill-check` when everything passes. In the code-jig repository that stamp is required in the same commit as the skill.
46
+
47
+ ## Report
48
+
49
+ Merge all three passes into one table: every FAIL and WARN, every rubric row, the Codex review verdict and each live case. Validation edits nothing in the skill; the only file it writes is the `.skill-check` stamp from pass 3. When the user asks for the fixes, apply them and run all three passes again.
50
+
51
+ ## Common mistakes
52
+
53
+ | Mistake | Instead |
54
+ |---|---|
55
+ | Judging in the context that wrote the skill | Pass 2 runs in a fresh `reviewer`. |
56
+ | Treating every WARN as a defect | A reference skill may be long; the word count prompts a split, it does not demand one. |
57
+ | Accepting "looks good" | The contract is rows with quotes. No quote means it was not read. |
58
+ | Skipping pass 2 | No pattern can see a description that summarises the workflow, the defect that costs the most. |
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: web-consensus
3
+ description: Use when a question has to be settled against the live web rather than from memory - researching a topic, proving or disproving a claim, checking whether something is still true, a sourced second opinion on a factual question - or when the user says "research", "prove it", "with sources", "check if this is true", "still accurate?".
4
+ ---
5
+
6
+ # Web consensus
7
+
8
+ Cheap researchers gather evidence in parallel, a reviewer from another model family attacks it, the disputed points are researched again from scratch, a script checks every link and quote, and a judge on the strongest model writes the verdict from sources only.
9
+
10
+ ## Who does what
11
+
12
+ | Step | Subagent role | Runs on |
13
+ |---|---|---|
14
+ | Evidence, cold verification | `explorer`, one per angle or question, in parallel | `bulk` tier: fast and cheap |
15
+ | Challenge | `reviewer` | `review` tier: another model family |
16
+ | Link and quote check | `code-jig check-sources` | no model |
17
+ | Verdict | `judge` | `deep` tier: the strongest model |
18
+
19
+ This skill asks for subagents: every role in the table runs through `spawn_agent` with that `agent_type`, even when you wait for its result before the next step, because the point is a different model and a fresh context, not speed. Each subagent gets its own brief and nothing about the others, so no role can quietly agree with another, and never a fork of this conversation. You only route: write the evidence files, run the script, pass material between roles. Run the whole flow even when the answer looks obvious or one page settles it: "it's a simple fact", "the docs already say it" and "one search is enough" are the answers from memory this skill replaces. If `spawn_agent` is not available in this session, stop and say so: a consensus from one model playing every role is not this skill's output, so do not play the roles yourself.
20
+
21
+ ## Flow
22
+
23
+ 1. **Evidence.** One `explorer` per angle. Each returns claim / URL / exact quote triples and nothing else. Write them to `evidence-<angle>.jsonl` in the workspace, one JSON object per line: `{"claim": "...", "url": "...", "quote": "..."}`.
24
+ - `direct`: the question as asked.
25
+ - `disconfirming`: the strongest evidence that the expected answer is wrong: corrections, retractions, errata, dissenting primary sources.
26
+ - `primary-source`: official docs, specifications, source code, changelogs and papers only.
27
+ - `academic`, when the question has a research literature: papers, reproductions, negative results.
28
+
29
+ Vary the wording of the searches between angles. The same index returns very different results for differently worded questions.
30
+
31
+ 2. **Check.** `code-jig check-sources "evidence-*.jsonl"` (the command expands the pattern itself, so the same line works in PowerShell). It fetches each URL once and reports per claim: `ok` (the page contains the quote), `quote-missing`, `dead`, `blocked` (401/403/429: usually bot-blocking, not absence), `unreadable` (PDF or binary: quote unverified). It needs the network: in a sandbox, ask for escalation on the first run, not after a refusal. When the workspace is read-only, pipe the lines in and pass `-` as the file (`printf '%s\n' "$line1" "$line2" | code-jig check-sources -`, in PowerShell `$lines | code-jig check-sources -`), and hand the evidence to the later roles inline in their briefs. One run covers every file. When it runs, the final reply quotes its summary line (`N claims: ...`) exactly as printed. If it still cannot run, nothing is checked: say so, the verdict's first line is `UNVERIFIED:` and no claim is agreed.
32
+
33
+ 3. **Challenge.** A `reviewer` reads the evidence files and the check report, and is told not to search. Its brief asks for a sweep before anything else: one line per claim, in order, none skipped or merged. `MISMATCH` when the quote does not contain what the claim asserts, `DOUBT` when the quote alone cannot tell (a number, a name, a baseline or a causal link it never states), `OK` only when the quote plainly carries the whole claim, each claim judged against its own quote. The sweep comes first because a reviewer that picks its findings first stops at the few defects that caught its eye. Tell it that a wrong flag costs one rebuttal while a fabrication it lets pass reaches the user as fact, so it flags every claim its quote does not plainly establish, and never invents a mismatch. Then it lists the questions that would settle each dispute.
34
+
35
+ 4. **Cold verification.** For each of those questions, a fresh `explorer` gets only the question: no evidence and no challenge. Write its triples to `evidence-cold.jsonl` and run the check on it. When the challenge lists no disputes, skip this step and say so in the report; there is then only the first check report.
36
+
37
+ 5. **Verdict.** A `judge` gets the question, every evidence file, every check report (one, or two after cold verification) and the challenge. It answers in a short paragraph, then lists agreed, disputed and unsourced claims with URL and quote, its confidence, and what new evidence would change the answer. Relay the verdict; do not rewrite it, and never add that sources are independent.
38
+
39
+ ## Rules
40
+
41
+ - A claim can only be agreed when `check-sources` says `ok`, or `unreadable` with the quote confirmed by a second source.
42
+ - The searcher never dictates the answer alone. Evidence files from the same search are not independent sources; say how many distinct sites agree.
43
+ - Prefer primary sources over secondary ones, and recent over old when the subject moves.
44
+ - When results look stale, ask the user to start the session with live search (`codex -c web_search="live"`).
45
+ - If web search is not available in this session, say so and stop. Do not answer from memory.
46
+
47
+ ## Common mistakes
48
+
49
+ | Mistake | Instead |
50
+ |---|---|
51
+ | Answering from one search because the question looks easy | Run every step; the user asked for sources checked by roles that did not write them. |
52
+ | Forking this conversation into a researcher | A fresh brief; a fork re-reads everything and inherits your bias. |
53
+ | Judging in the main session | The `judge` role exists so the verdict runs on the strongest model whatever tier this session uses. |
54
+ | Treating `blocked` as `dead` | Say it was blocked; find a second source or quote it as unverified. |
55
+ | Paraphrasing in the `quote` field | The check needs the exact words on the page. |