elide-case — a court opinion cut into a student reading, on the craft spine
SkillDev toolsUse when a court opinion that is not in the casebook has to become a casebook-style excerpt for students, "add this case to the addendum", "elide this opinion for class", "cut this case down to four pages the students can read", "make a casebook excerpt of X", "this case isn't in Choi, put it in the reader", "excerpt the Howey analysis from this opinion", "the TM mentions a case we don't have", "I want to teach this new decision next week". NEGATIVE ROUTING: compiling an addendum whose readings are already written is teaching:generate-addendum; retrieving an opinion with no elision is workflows:courtlistener.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the elide-case — a court opinion cut into a student reading, on the craft spine skill
What this skill tells your AI
The instructions your AI receives, as published by edwinhu/workflows in skills/elide-case/SKILL.md and read by ahel’s review.
What this skill carries — grep references/ for any subject the names below miss:
!d=${CLAUDE_SKILL_DIR}; command -v skill-toc >/dev/null 2>&1 && exec skill-toc "$d"; s=$HOME/.claude/skills/plugin-utils/bin/skill-toc; [ -x "$s" ] && exec "$s" "$d"; echo "(skill-toc unavailable: references and scripts are NOT listed here — install the plugin-utils plugin, or start a new session so its bin/ reaches PATH)"
Typst rules in force here — read the one that governs what you are writing; they are independent:
!k=notes,prose; command -v typst-rules >/dev/null 2>&1 && exec typst-rules "$k"; r=$HOME/.claude/skills/typst/scripts/load-constraints; [ -x "$r" ] && exec "$r" "$k"; r=$HOME/projects/typst/scripts/load-constraints; [ -x "$r" ] && exec "$r" "$k"; echo "(typst corpus unavailable: NO Typst rule is listed here — install the typst plugin, or start a new session so its bin/ reaches PATH)"
The lifecycle is craft. Read it and
follow it. This file supplies craft's spine with the domain and nothing else — the three CLARIFY
questions, the plan grammar, the task rows, the two scored checks, the one mechanical entry point, the refs
and the authority text. It ships no workflow.js and no .js of any kind, and restates none of
craft's mechanics.
The domain rules live in references/ and reach every dispatched agent through refs:
| ref | what it carries |
|---|---|
references/authenticity.md | the two Iron Laws — authentic reporter text, and compile-before-table |
references/retrieval.md | workflows:westlaw as the first route and the .westlaw.docx as the ONLY stored source, the corpus fallback (opinions vs RECAP, the 404, token gating, telling a clean source) and what that fallback's PDF cannot carry, and the two reasons to run on Gemini — a scanned source or a filter-tripping subject |
references/editing-marks.md | one elision mark per addendum, [ ] conventions, never altering subject/tense/sentence boundary, the editors'-note rule (a note is the EXCEPTION, for background), where the mechanical conventions live (the preamble, once), the layout-only widow rule, and the source-mapping marker // elide-source: that check.sh reads |
references/verification.md | what each gate leg decides, and how to read a miss rate |
The Iron Law of Compile-Before-Table. The summary table is written AFTER the compile, from the checker's computed output. Never before, never from an estimate.
Both are stated in full in references/authenticity.md, which is the refs entry every implementer
and the fidelity lens must read. Refactoring this file never weakens them.
Phase 1 — CLARIFY: three questions, asked with AskUserQuestion, never self-answered
This interview is the point of the workflow. Ask exactly these three, with AskUserQuestion, and
record every answer verbatim in the plan:
- What is the doctrinal thread, in your own words — and which assigned reading does it cut against? One thread, named by the instructor, plus the case or casebook page it is in tension with. This is what decides every sentence that survives the cut.
- Is this case taught for its HOLDING or for its REASONING? Holding means the disposition and the rule statement survive and the analytical march may be compressed. Reasoning means the analytical steps survive and the disposition may be a sentence.
- What is the page target for each reading? One MIN-MAX per reading, offered with 2-6 as the default option — the skill's established range — since a reading whose length he does not care about takes the default. A lead case and a short blog post reasonably differ, which is why the plan carries one target per row. When the request or the schedule already gives a target, pre-fill the options from it rather than posing the question blind; nothing is inferred silently, and nothing is typed at a command line.
Do not ask anything else. On 2026-09-09 the instructor declined a passage he wants kept, and declined insertion point and length as an interview axis — then reversed the length half the same day: the per-reading page target is now question 3 above, set in the interview and enforced from the plan, because a number typed at the command line is a number an agent can invent. Insertion point and class number still come from the request, or off the schedule if the request omits them.
THE INTERVIEW, AND EXACTLY WHAT ENFORCES IT
Never self-answer either question, never state an assumption and continue, never infer the thread
from the Teacher's Manual or from the case itself. Craft's CLARIFY is conversational and a
dispatched agent cannot call AskUserQuestion — a run started from a farmed-out agent has nobody
to ask, and its only correct move is to stop and report that the interview is unanswered. Elevating
the run to a session that can reach the user is the fix; guessing is not.
Measured 2026-09-09: the old Phase 1 had the model state the doctrinal target to itself. It guessed "pre-purchase efforts, against Life Partners", happened to be right, and nothing in the skill made it ask. That silent-guess path is the defect this workflow exists to remove.
The chain, with each link's real strength named. Three things carry the interview, and only one of them is software:
- The answers are recorded in the plan, under
## Doctrinal target, on the three labelled lines Phase 2 specifies. - The instructor reads and approves that plan before the run arms, and the spec hash binds what
he approved. This is the link that makes the answers his. It is a human gate, and it is the only
one there is: an instructor who approves a plan whose
## Doctrinal targetholds answers he never gave defeats the whole chain, and no software in this design closes that. scripts/check.sh --plan <path>refuses a plan whose section is missing or unfilled — absent section, orDoctrinal thread:/Cuts against:missing, empty or a placeholder, orTaught for:missing or saying neither holding nor reasoning. The leg fails closed: passing neither--plannor--no-planis itself a FAIL naming the missing flag, and--no-plan(for fixture and dev runs that check an addendum alone) prints a loud NOT CHECKED line.
What that leg proves, and what it does not. It proves the section exists and every required answer
is non-empty. It is a backstop against an orchestrator that skipped the question — nothing more.
The plan file is written by the orchestrator, so no grep of it can tell the user's answers from the
orchestrator's own, and craft's mechanicalChecks run at gate time, after IMPLEMENT, so no
mechanical leg can refuse to proceed past CLARIFY. Do not close the gap with a second
mechanicalChecks entry — P10 refuses one, and the leg belongs inside the single entry point.
Phase 2 — PLAN
Craft's Phase 2. Domain requirements on the plan:
- A
## Readings In Scopesection, one row per reading:caption | source docs/*.westlaw.docx (a docs/*.txt from an earlier run, or from the fallback route, still resolves) | page target. This section is the source of truth for the page target, and the--planleg enforces it exactly as it enforces the three Doctrinal target lines: an absent section, a row with no page target, or a placeholder one (TBD,<…>,N/A) FAILS the leg naming the offending row. The target is per reading, from interview question 3;check.shmaps each.typcaption to its row and passes that row's own MIN-MAX tocheck-addendum.py. The caption is the identifier the.typand the mechanical entry point key on — the entry point derives its per-reading checks from the captions in the.typ. Each row also generates onecut-<slug>task, which is how a per-reading re-run reaches craft'sonlyTasks. - The first two CLARIFY answers, quoted (the third is the
page targetcolumn above), under## Doctrinal target, on three labelled lines the--planleg parses —Doctrinal thread:,Cuts against:,Taught for:(holding or reasoning). A placeholder (TBD,<…>,N/A) reads as absent and fails the leg. - A
## Non-court readingssection whenever a reading is not court text — one- <caption> — <why>bullet each, and omitted entirely when every reading is an opinion. Declaring a reading non-court text is the INSTRUCTOR's call, recorded in the plan, never a marker the implementer writes into the.typ: a self-exempting marker would let fabricated text switch the verbatim check off on itself, which is the first Iron Law defeated by the file it governs. The quotes leg reads this list from--planand reports those captionsDECLARED-UNCHECKED; a// elide-unchecked:marker in the.typis no longer honoured and its presence is itself a FAIL naming the reading. - Run sizing naming the one mechanical entry point, the two
scoredCheckskeys on theScored checks:line marked ADVISORY, the two craft default lenses on theReview lenses:line, and the task rows. R readings give R + 2 tasks — oneretrieve, Rcut-<slug>, onecompile-table— and 2R scored items; with craft's two default lenses and one mechanical check the floor is 2(R + 2) + 1 + 2 + 2R = 4R + 7 agents — 11 for a single reading, 19 for four readings. - The wave assignment, stated:
retrievein wave 1, everycut-<slug>in wave 2,compile-tablein wave 3.work-dispatch.shprints the wave graph it computes; if it does not match those three lines, thedependsOnedges are wrong, not the prose.
Writable paths for a generated run are addenda/, output/addenda/ and docs/ only. notes/,
slides/ and templates/ are excluded, and so is everything else in the course tree.
Phase 3 — GOAL
Craft's Phase 3, on the PASS phrasing: a run that writes can turn a FAIL into a PASS, and craft's outer fix loop is what does it.
Condition: work-result.sh returned 0 for the plan path, and the tuicr gate returned approved.
/goal work-result.sh has returned 0 for <plansDirectory>/<slug>.md at its current hash, and the
tuicr gate has returned approved, or stop after N turns
Name the plan by path, never by a pinned digest — the FAIL loop amends and re-hashes the plan,
so a named hash self-invalidates. Name work-result.sh's exit code, which is the run's verdict:
overallPass in result.json is not the verdict and must never be read directly (craft/SKILL.md's
mechanicalChecks row). Naming the returned verdict is also what makes a gate FAIL reach a stopping
condition at all — including one carried by a lens finding, which otherwise reaches none.
The condition names no legibility or fidelity finding. A clause like "no critical|major finding
survives" would reinstate the non-terminating prose review this design exists to exclude: round
n's fix gives round n+1 new things to object to. Those two run as scoredChecks, which cannot
reach overallPass at all, so their output sits in result.json and is retrievable at Phase 5 by
a human who runs the command there. Nothing carries it to him. Both named verdicts get printed, so
both are judgeable from the transcript.
Phase 4 — the craft call
The args go in the plan's <!-- craft:dispatch --> block and the dispatch is craft's own
work-dispatch.sh — never a hand-written farm.sh --workflow line, which drops the TIER 1
plan-lint gate and both probe gates:
bash ~/.claude/skills/workflows/skills/work/scripts/work-dispatch.sh \
--run-dir /home/eh/.local/state/craft "$PLAN" # ABSOLUTE — never the course tree
Forward the provider. A provider named in this skill's $ARGUMENTS, however it is spelled,
becomes --provider codex on that line. Omitting it runs the user's codex request on claude. The
content-filter facts that make this matter are in references/retrieval.md, alongside the other
reason a run belongs on --provider gemini: a source whose text came from OCR.
--run-dir is not optional: craft resolves .craft/<run-id> against $PWD, which on an elide run is
the course directory — a tree this run writes only addenda/, output/addenda/ and docs/ in.
The args object, complete as it stands.
One task per reading, in three waves. The ## Readings In Scope table generates one cut-<slug>
row each — cut that reading and nothing else — above one shared retrieve row and below one
compile-table row. A second reading therefore adds exactly one task, and adds no lens and no
mechanical entry: the entry point derives its per-reading legs from the .typ itself. This
granularity is not cosmetic. It is what makes a per-reading re-run expressible in craft's own
vocabulary — see The FAIL loop below.
The wave shape is forced by craft's disjointness rule, not chosen for tidiness. Same-wave tasks
must have pairwise-disjoint writablePaths, checked prefix-aware and refused at arg-validation,
before any agent is dispatched. Every reading needs its source in docs/, so if each reading row
claimed docs they would all land in wave 1 claiming the same directory and a two-reading addendum
would be refused before dispatch. One row owns docs/ instead:
| wave | rows | writable paths | why disjoint |
|---|---|---|---|
| 1 | retrieve (one row, however many readings) | docs | alone in its wave |
| 2 | one cut-<slug> per reading, each dependsOn: ["retrieve"] | addenda/NN-addendum-<slug>.typ | one file each, slugs distinct |
| 3 | compile-table, dependsOn every cut-<slug> | output/addenda, addenda/NN-addendum.typ | alone in its wave |
retrieve writes docs/ and nothing else; the cut rows read it and never write it. A single-reading
run keeps all three rows — collapsing them re-introduces the overlap the moment a second reading is
added.
{
projectDir: "/home/eh/areas/secreg", // the COURSE directory — the tree being edited
goal: "<one sentence>",
// ── The deterministic floor: ONE entry point, whose exit code IS the mechanical verdict. ──
// Five legs — the plan's interview answers, typst compile, check-quotes.py per derived caption,
// check-addendum.py --target, and the strays leg (canonical widows.py/orphans.py/runts.py
// plus check-stranded-headings.py) — none short-circuiting. A second entry here would spread the
// verdict over two commands and lose one silently; P10 refuses it.
// The plan leg FAILS CLOSED: pass `--plan <md>` on a real run or `--no-plan` on a fixture run,
// and passing neither is a FAIL naming the missing flag. `--plan` also carries the plan's
// `## Non-court readings` declarations. It checks that the answers are RECORDED and non-empty;
// that they are the instructor's is carried by his approval of the plan, not by this command.
// `--plan` ALSO supplies each reading's page target, from the plan's `## Readings In Scope`
// rows, so a real run passes NO `--target`. The plan wins if one is passed anyway — the flag is
// ignored with a loud line naming the plan's values. `--target MIN-MAX` / `--no-target` remain
// the fail-closed pair on `--no-plan` fixture and dev runs, where passing neither is a FAIL
// naming the missing flag and the leg must not report length.
// The WIDOWS leg is ON BY DEFAULT, which is its fail-closed form: an absent flag RUNS the
// check, so no invocation can quietly certify page breaks nobody looked at. `--no-widows`
// is the loud waiver for fixture and dev runs; passing it with `--widows` FAILS. Its fix
// vocabulary is LAYOUT-ONLY — spacing or pagination, never the court's words, and when the
// two conflict fidelity wins and the widow stands.
mechanicalChecks: [
{
name: "elide-check",
cmd: "bash /home/eh/projects/workflows/skills/elide-case/scripts/check.sh --addendum /home/eh/areas/secreg/addenda/NN-addendum.typ --pdf /home/eh/areas/secreg/output/addenda/NN-addendum.pdf --plan /home/eh/areas/secreg/.claude/plans/<slug>.md",
},
],
Shortened here. Read the whole file on GitHub.
Signals
- GitHub stars
- 21
- Forks
- 4
- Last commit
- Sep 2026
ahel review
K6low
bundled executables the agent is told to run
Automated review, not a security audit. Ruleset v1+k2.
Advanced
- Catalog kind
- skill
- Gateway key
elide-case- Source
- github.com/edwinhu/workflows