induce

induce is a skill for Claude Code from jongwony/epistemic-protocols. It costs 50 tokens per session (10,150 once invoked), scanned A, original, MIT.

A reasoning method for discovering and naming a shared idea by comparing concrete examples before choosing an abstraction.

In plain words
What is it for?
Use it to derive concepts, rules, or categories from examples during analysis and design.
Why use it?
It reduces the risk of forcing different cases into a label that does not fit. Unresolved interpretations remain visible while the concept is clarified.

Skill for Claude Code

Written for Claude Code: shipped in a Claude Code plugin.

Part of the periagoge plugin — 1 skill shipped together

Good fit Use it to derive concepts, rules, or categories from examples during analysis and design.

Compare 6 skills from other repositories ↓
Install with agentmods
npx agentmods add skills/jongwony/epistemic-protocols/induce
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Any agent
npx skills add jongwony/epistemic-protocols --skill induce
Clone the repo
git clone --depth 1 https://github.com/jongwony/epistemic-protocols

Made for: Claude Code.

Or install periagoge, the plugin that ships this one along with the rest of its 1 skill.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for induce

README.md
[![agentmods](https://agentmods.dev/badge/skills/jongwony/epistemic-protocols/induce/github.svg)](https://agentmods.dev/skills/jongwony/epistemic-protocols/induce)
Your own site
<a href="https://agentmods.dev/skills/jongwony/epistemic-protocols/induce"><img src="https://agentmods.dev/badge/skills/jongwony/epistemic-protocols/induce/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for induce

Your own site · 80×15
<a href="https://agentmods.dev/skills/jongwony/epistemic-protocols/induce"><img src="https://agentmods.dev/badge/skills/jongwony/epistemic-protocols/induce.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 50 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 10,150 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe. Third-party audits
  • NVIDIA SkillSpector pass 7 Sept 2026
How audits are shown
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.00050 $0.10150
Opus 5.5 $0.00020 $0.04060
Sonnet 5.5 $0.00010 $0.02030
Haiku 4.5 $0.00005 $0.01015

Measured yesterday against content hash b3f81102b35c, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade A, and why

induce scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured yesterday.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

periagoge/skills/induce/SKILL.md · 600 lines

How it starts

The opening of the file, as written. The whole thing — 600 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Periagoge Protocol

Name what several concrete cases share by crossing a working candidate with the goal it serves and with every live reading of the cases, until the user recognizes the abstraction as serving their goal. Type: (AbstractionInProcess, AI, INDUCE, A) → CrystallizedAbstraction.

Definition

Periagoge (περιαγωγή): a turning-around — a dialogical act for the moment when several concrete cases seem to share something no one has named yet, or that a name in use no longer says. From the first sheet the AI states the goal the abstraction serves and a working candidate — a name and a rule, with the ground it stands on and, where that ground is short, what is short beside it —, and crosses every live reading of what the cases share with that goal: which cases each reading takes in and which it leaves out. The user answers in their own words: they move the goal or the candidate, take what the AI showed, set a reading aside, or recognize the abstraction; they can stop at any time, and the run stays as it stood. Once it has run, the user can name what their cases share, say which cases it takes in and which it leaves out, and recognize it as serving their goal — their settlement for that goal, not proof that the reading is correct (the Greek dialectical vocabulary supplies the source terms).

/-!
How to read this block. It is core Lean 4 and elaborates as written, and you are the model it is
written for: you read it, and by inference over the context you settle each element it leaves
open. Every `axiom` is one of those judgments — a black box to the contract, yours to make from
the material in front of you; its doc comment says what you judge there, and nothing in this
block decides it for you. Every `def`, `inductive`, and `structure` is fixed by the contract.
-/

/-! ── FLOW ──
Periagoge(A) → start(c) → induce(c, utterances), where c is the fused session context:
  start: what bears on the cases is collected into c; then your reading, on it, that this is not
    this protocol's case (`notActivated`) → not activated — on an invocation, your reading with its
    basis; AI-guided activation stays silent; otherwise → sheet
  next utterance u, read on fuse(c, u):
    [does not bear on this run]                                the session answers it; that answer
                                                               stays in c; the run stays as it stands
    [the person recognizes the goal and the candidate]         what is collected now enters c; where
                                                               c is `Overturned` → the sheet again;
                                                               otherwise → crystallized
    [otherwise]                                                what is collected now enters c → the sheet again
  no utterance: nothing comes to stand; the run holds
  after a crystallization, or not activating on an invocation: the next move the `seam` entry names
-/

/-! ── MORPHISM ──
A
  → CrystallizedAbstraction
requires: in_process(A)                     -- read before activation (`notActivated`)
deficit:  AbstractionInProcess              -- activation precondition
preserves: instance_set(A)                  -- the cases are read, never rewritten: they stay as read, whatever carried work changes in their artifacts; a case you found is yours
invariant: Goal Crossed with Readings through Examples, with Alternatives Maintained, over Single-Candidate Steering
invariant: setting a reading aside, taking a value you showed, an open item's words, and every closing are the person's; your readings make none of them
-/

namespace Periagoge

/-! ── GROUND ──
The session primitive this contract reads.
-/

inductive Origin | person | assistant | external | peer | injected | unknown
  deriving DecidableEq

/-- A turn is who sent it and what it says. What the turn does — a statement, a request, an
    instruction, a report of what was observed — is read from its content, never stored here. -/
structure Turn (P : Type) where
  origin  : Origin
  content : P

abbrev Context (P : Type) := List (Turn P)

/-- An origin that may ground: the harness says who sent a turn, and that is all this admits on.
    The assistant's own turns, injected text, and turns of unknown origin ground nothing. -/
def Grounding := {o : Origin // o ≠ .assistant ∧ o ≠ .injected ∧ o ≠ .unknown}

/-- Any turn a person sent, whatever it does. -/
def Utterance (P : Type) := {e : Turn P // e.origin = .person}
def Response (P : Type) := {e : Turn P // e.origin = .assistant}
/-- A turn from outside the conversation: what a tool or the environment returned, or a peer's
    report. A person's account of what they observed is an utterance, read as such. -/
def Evidence (P : Type) := {e : Turn P // e.origin = .external ∨ e.origin = .peer}

def fuse {P : Type} (c : Context P) (u : Utterance P) : Context P := c ++ [u.val]

/-- One turn of the context, with the origin it grounds on. -/
structure Cite {P : Type} (c : Context P) where
  idx : Nat
  lt  : idx < c.length
  src : Grounding
  ok  : (c[idx]'lt).origin = src.val

/-- `admits` reads only who sent the cited turn; `supports` is the model's reading of what that
    turn says, including what it does — a statement, a request, a report of an observation. -/
structure Coord (P A : Type) where
  admits   : Grounding → Prop
  supports : Context P → Turn P → A → Prop

/-- `open_` may carry a candidate citation whose support is still short. -/
inductive Occ {P A : Type} (q : Coord P A) (c : Context P)
  | open_  (candidate : Option (Cite c))
  | filled (a : A) (src : Cite c) (allowed : q.admits src.src)
      (supported : q.supports c (c[src.idx]'src.lt) a)

/-- The same turn, cited from a longer context; what it supports is judged again against the
    context that now stands. -/
def Cite.lift {P : Type} {c : Context P} (s : Cite c) (t : Context P) : Cite (c ++ t) :=
  { idx := s.idx
    lt := by have := s.lt; simp; omega
    src := s.src
    ok := by rw [List.getElem_append_left s.lt]; exact s.ok }

/-! ── TYPES ── -/

noncomputable section

variable {P : Type}

/-- `A`, `AbstractionSeed`: the in-process state, read from the context — the cases, read and never
    rewritten; the essence intuition; and any provisional name the person gave, which grounds the
    candidate's name without fixing it. What earlier work produced is context like any other; an
    essence it suggests is your reading. -/
abbrev AbstractionSeed (P : Type) := Context P

/-- A concrete case: what it is, and where it sits. -/
structure Instance where
  content : String
  context : String
  deriving DecidableEq  -- elab: lets `casesSection` hold each case once

/-- **Your reading**, before any sheet: why this is not this protocol's case, with its basis. The
    case is this protocol's where an essence is sensed whose name, rule, or reach is still
    unsettled for the person and at least two concrete cases can be read together: a named
    abstraction whose meaning is being reconsidered from its cases is in process; applying a fixed
    meaning to a disputed case is not; a set of cases this session already crystallized, or whose
    run the person's words ended, stays inactive unless the person's words reopen it, a correction
    of its record among them. Where no essence is sensed or no second case was found, say what was
    searched and what would settle it. `none` where the case is this protocol's.
    During a run, a reading that the case is no longer this protocol's is one of your doubts, with
    its basis, and closes nothing. -/
axiom notActivated : Context P → Option String

/-- **Your record**: the cases you found and bring to the sheet — the rest of what collection
    turned up stays in the context it was read into — that the person's words have neither taken
    up nor turned down. A case that would decide against the candidate is among the cases you
    bring. -/
axiom found : Context P → List Instance

/-- **Your reading**: the cases the person brought — named in their turns, or singled out by them
    from what they pointed you to — and the cases you found that their words took up, read and
    never rewritten. A collection they point you to without singling out cases is material you
    collect from. A case their later words withdraw is no longer brought; those words stand in the
    context. -/
axiom brought : Context P → List Instance

/-- **Your judgment**, made afresh on every pass: the goal — what the abstraction is for — as it now
    stands. Where the person's words state it, it is their words, quoted; otherwise it is your
    reading. It moves: a turn that narrows or widens it moves it, on the scope its words reach. At
    a recognition it is the goal as the recognizing turn took it — the sheet's, with the person's
    changes since; a re-draw of yours is not that value. -/
axiom goal : Context P → String

/-- One reading of what the cases share. -/
abbrev Reading := String

/-- `(N, Rule)`: the working candidate — a name and a rule, the reading the rule is read off, the
    readings that reading merges, and those any merge among them merges in turn (empty when it is
    not a merge), and the label it was grounded on. The name is delivered with the goal, the rule,
    and the examples the rows drew: it locates the abstraction and returns the person to those
    cases. -/
structure Candidate where
  name       : String
  rule       : String
  reading    : Reading
  merges     : List Reading
  labelBasis : Option String

/-- **Your proposal**, from the first sheet: the working candidate, with every move the person made
    since — a rename, a rule correction, a move to another reading, a merge —, and the ground it
    stands on; where that ground is short, what is short is a point still open (`missing`), yours —
    a row of its own that leaves no case out is such a shortfall: what case would have to be left
    out for the name to say something. Where the person set its reading aside, or every reading is
    set aside, you put forward a candidate on a live reading or on a new reading of your own. Where
    you set the candidate across readings, their merge is a reading of its own, with its row; a
    merge the person makes is already a reading. At a recognition it is the candidate as the
    recognizing turn took it — the sheet's, with the person's changes since; a re-draw of yours is
    not that value. -/
axiom candidate : Context P → Candidate

/-- **Your judgment**, made afresh on every pass: every reading of what the cases share drawn in this
    activation, the readings the person added included. A reading you would no longer hold stays
    here: dropping it is your proposal until the person sets it aside. A merge the person makes is
    a reading; a reading you judge the same across passes keeps its name. A reading the person set
    aside stays here too, out of play. -/
axiom readings : Context P → List Reading

/-- **Your judgment**: the cited turn sets reading `r` aside, on this ground — their reason, carried
    verbatim — whatever form the turn takes. -/
axiom SetAsideSupported : Reading → Context P → Turn P → String → Prop

/-- A reading is set aside only by the person's turn. -/
def setAsideCoord (r : Reading) : Coord P String :=
  { admits := (·.val = .person), supports := SetAsideSupported r }

/-- **Your reading**, on the context as it now stands: the person's setting-aside of `r`; `open_`
    until one reaches it, and again once their later words bring `r` back, never on your proposal
    alone. Their earlier ground stays in the context. -/
axiom setAside : (c : Context P) → (r : Reading) → Occ (setAsideCoord (P := P) r) c

def filledValue {A : Type} {q : Coord P A} {c : Context P} : Occ q c → Option A
  | .open_ _     => none
  | .filled a .. => some a

/-- The readings still in play: a reading leaves only by the person's setting-aside. -/
def live (c : Context P) : List Reading :=
  (readings c).filter (fun r => (filledValue (setAside c r)).isNone)

/-- Every reading the person set aside, with their ground. -/
def setAsideReadings (c : Context P) : List (Reading × String) :=
  (readings c).filterMap (fun r => (filledValue (setAside c r)).map (r, ·))

/-- An example named by a phrase that carries the feature being judged, never by a bare number. -/
structure Example where
  phrase : String
  source : Instance

/-- One row of the cross view: what the reading becomes against the goal — the check it yields —,
    the cases it takes in and those it leaves out, and where the working candidate sits on it. The
    row of the reading the candidate stands on sorts every case of the cases section into taken in
    or left out, except a case the person's words place on the boundary, which it leaves in neither
    list; the other readings' rows carry the cases that separate them, and either of their lists
    may then be empty. -/
structure Row where
  againstGoal   : String
  catches       : List Example
  misses        : List Example
  candidateHere : String

/-- **Your judgment**: the row for reading `r`. Choose examples that separate the goal and the
    readings rather than ones every reading treats alike, drawn from the person's own domain: pair
    the cases that align most readily, not the most distant, since distance is what a separating
    example is for; align what they carry from the cases themselves; and draw a case that tells
    readings apart. A case you draw into a row from the person's domain enters as found by you
    (`found`); a case the person withdrew, or a found case they turned down, is not drawn into a
    row. The examples the last sheet showed stay as it showed them until a move of the person's
    reaches them — a swap, a move of the goal, the candidate, or the reading they cross, a
    correction, a case they brought; an example you would change otherwise is your proposal, not a
    swap. -/
axiom row : Context P → Reading → Row

/-- The cross view: every live reading with its row. -/
def crossView (c : Context P) : List (Reading × Row) := (live c).map (fun r => (r, row c r))

/-- **Your reading** of case `i`: what happened, what in it bears on the goal and the readings, how
    it surfaced, and who brought it. -/
axiom unfoldCase : Context P → Instance → String

/-- Every case the cross view uses. -/
def rowCases (c : Context P) : List Instance :=
  (crossView c).flatMap (fun x => (x.2.catches ++ x.2.misses).map (·.source))

/-- The cases section of the sheet: every case the person brought, every case the cross view uses,
    and every case you found, each once, with its unfolding. -/
def casesSection (c : Context P) : List (Instance × String) :=
  (brought c ++ rowCases c ++ found c).eraseDups.map (fun i => (i, unfoldCase c i))

/-- **Your reading**: the points still open, each in the words of whoever raised it — the person's
    quoted, or yours. -/
axiom missing : Context P → List String

/-- What a run can still owe at its end, tagged by what it is. -/
inductive OpenItem
  | reading (r : Reading)
  | question (q : String)

/-- The live readings the candidate does not take — it takes its own reading and the readings that
    reading merges (`taken`) —, and the points still open. -/
def openItems (c : Context P) (taken : List Reading) : List OpenItem :=
  ((live c).filter (fun r => decide (r ∉ taken))).map .reading ++ (missing c).map .question

/-- **Your judgment**: the cited turn says how open item `i` stands for the person — for later work,
    not blocking, still to settle, whatever it says — and these are its words about it, carried
    verbatim; read against the context as it now stands, whatever form the turn takes. A turn
    that says nothing of the item says nothing here. -/
axiom OpenSupported : OpenItem → Context P → Turn P → String → Prop

/-- Only the person's turn speaks for an open item. -/
def openCoord (i : OpenItem) : Coord P String :=
  { admits := (·.val = .person), supports := OpenSupported i }

/-- **Your reading**: the person's words about item `i` from a turn of theirs that still reaches it;
    `open_` where none does: the item is open — undisposed. -/
axiom openWords : (c : Context P) → (i : OpenItem) → Occ (openCoord (P := P) i) c

/-- The open trace: every open item as `c` stands, with the person's words about it, or `none`
    where no turn of theirs reaches it. -/
def openTrace (c : Context P) (taken : List Reading) : List (OpenItem × Option String) :=
  (openItems c taken).map (fun i => (i, filledValue (openWords c i)))

/-- A line: a value the sheet or the record carries, however it is shown; a value that changes
    makes a new line. -/
abbrev Entry := String

/-- **Your reading**: the lines of the sheet, or at a recognition of the record as you read it, as
    the context now stands — their values; your doubts and the points still open are not among them,
    `dissent` and the open trace carry them. -/
axiom entries : Context P → List Entry

/-- Who first put a value forward — you, the person, or any other source — kept apart from how
    it came to stand. -/
inductive Proposer | ai | person | source

/-- **Your reading**: the position of the turn that first put forward line `e`. A value whose
    content a turn of the person's or of another source put forward, and which you then drew up,
    was put forward by that turn; a case the person singled out from what they pointed you to was
    put forward by the turn of theirs that singled it out. `none` where no turn has put it
    forward. -/
axiom introducedAt : Context P → Entry → Option Nat

def proposer (c : Context P) (e : Entry) : Proposer :=
  match introducedAt c e with
  | none   => .ai
  | some i =>
    match c[i]? with
    | some ⟨.person, _⟩    => .person
    | some ⟨.assistant, _⟩ => .ai
    | some _               => .source
    | none                 => .ai

/-- How a line came to stand on a person's turn: the turn gave it in its own words, or took it as
    a sheet showed it. -/
inductive Standing | set | adopted

/-- **Your judgment**, the record rule: the cited turn makes line `e` stand, read against the
    context as it now stands, on the scope its words reach — the turn gave it in its own words
    (`set`), or took it as a sheet showed it before that turn (`adopted`). A narrow answer stays
    narrow: taking one case's place in a row takes that placement, not the sheet around it. A turn
    that recognizes the abstraction takes every line the sheet it followed showed, with no second
    permission; a line it holds back stays as it stood, and the person's changes since that sheet
    stand in their own words. A turn whose recognition was `Overturned` on the context it was read
    on takes nothing by recognizing. A question, a request to see something, or a bare mention
    makes nothing stand; a value no turn of the person's reached stays a proposal, however long it
    has gone unchallenged. -/
axiom StandingSupported : Entry → Context P → Turn P → Standing → Prop

/-- Only the person's turn makes a value stand. -/
def standingCoord (e : Entry) : Coord P Standing :=
  { admits := (·.val = .person), supports := StandingSupported e }

/-- **Your reading**: the person's turn that first makes line `e` stand and still reaches it; a
    later turn that takes it again leaves how it stood; `open_` while none reaches it. -/
axiom standingOcc : (c : Context P) → (e : Entry) → Occ (standingCoord (P := P) e) c

def standing (c : Context P) (e : Entry) : Option Standing := filledValue (standingOcc c e)

/-- A line with who first put it forward and how it stood; `none` where no turn of the person's
    reached it — still a proposal, by whoever put it forward. -/
structure Provenance where
  entry    : Entry
  proposer : Proposer
  standing : Option Standing

/-- Every line, with who first put it forward and how it stands. -/
def provenanceOf (c : Context P) : List Provenance :=
  (entries c).map (fun e => ⟨e, proposer c e, standing c e⟩)

/-- **Your record**: your doubts, each with what it touches and what it rests on. A doubt never
    refuses a closing: a close carries the doubts shown before it — accepted, evidentially
    disputed. A doubt formed at the recognition is recorded as formed then, not among those the
    close carries. Empty when there were none. -/
axiom dissent : Context P → List String

/-- **Your judgment**: the cited turn — the latest utterance — closes the run: read whole against
    the context as it now stands, whatever form it takes, it recognizes the goal and the candidate,
    as the sheet it followed showed them together with every change the person made since — the
    turn's own included —, as what the person means, with no second permission; such changes do
    not stop the recognition. Holding a line back is not taking it, without saying it is wrong. A
    recognition stands whatever else the turn does — holds back another line, a case's placement
    among them, says something about an open item or raises one, answers a doubt —; holding back
    the goal, the candidate's name or its rule recognizes nothing, nor does the turn with the
    reading the candidate stands on set aside, by it or by a change the person made since that
    sheet. "Not yet" or a question closes nothing; silence, other work, and your own reading that
    the candidate fits close nothing. Where the turn's intent is unclear, it closes nothing. -/
axiom ClosingSupported : Context P → Turn P → Unit → Prop

/-- Only the person closes. -/
def closeCoord : Coord P Unit :=
  { admits := (·.val = .person), supports := ClosingSupported }

/-- **Your reading**: the person's closing; `open_` until one reaches it. -/
axiom closing : (c : Context P) → Occ (closeCoord (P := P)) c

/-- **Your judgment**: the latest utterance bears on this run — a move, a correction, a case, a
    rename, a value taken, words about an open item, an answer to a doubt, a closing, a question
    about the sheet. An utterance about other work leaves the run as it stands. Words that end the
    run without recognizing the abstraction do not bear on it, whatever else the turn says, and
    what else it says stands in its own words in the context: the session answers them, no sheet
    is drawn, the run holds, and later turns bear on it only where they come back to it. Where
    reading a turn as other work or as ending the run was unclear, the session's answer says
    briefly that the run was left as it stands. -/
axiom Reaches : Context P → Prop

/-- Once it has run, the person can name what their cases share, say which cases it takes in and
    which it leaves out, and recognize it as serving their goal.
    `CrystallizedAbstraction`: your reading of the context with the recognizing turn — its goal and
    candidate, its cross view, where the row of the candidate's reading is what the candidate takes
    in and leaves out, its cases, the readings set aside with the person's grounds, the open trace,
    and the doubts — with every line, who proposed it and, where a person's turn reached it, how it
    stood. Whatever you produce at a recognition that the person has not seen — a line re-drawn or
    re-phrased, the goal and the candidate included, a doubt formed on their changes, what you make
    of what collection returns for what their turn brought — stays a proposal, and the recognition
    takes none of it. Where it is read wrong, the person's later words correct it; the context as
    it then stands is what is read. It records the person's settlement for their goal, not proof
    that the reading is correct. -/
structure CrystallizedAbstraction (P : Type) where
  context    : Context P
  goal       : String
  candidate  : Candidate
  crossView  : List (Reading × Row)
  cases      : List (Instance × String)
  setAside   : List (Reading × String)
  openTrace  : List (OpenItem × Option String)
  dissent    : List String
  provenance : List Provenance

inductive Outcome (P : Type)
  | notActivated (c : Context P) (why : String)
  | crystallized (r : CrystallizedAbstraction P)
  | holding      (c : Context P)

/-! ── MODE STATE ──
Λ is the fused context and nothing else; every reading above is taken from it. No gate, stage, or
count is stored: each sheet is judged afresh from the whole context.
-/

abbrev Mode (P : Type) := Context P

/-! ── PHASE TRANSITIONS ──
A step is one arm of a structural recursion over the person's utterances. A pass is the silent
work: what is collected enters the context. A closing is read from the person's turn before
anything is collected. `respond` draws the sheet, and `present` places the response that carries
it; `session` is the session's own answer to an utterance that does not bear on the run, which
stays in the context without opening collection; `converge` is the closing declaration of the
trace, as TOOL GROUNDING's `converge` entry names it.
-/

/-- **Your reads**, as far as the session can reach without changing existing state. One collection
    at the start reads what the admission reading needs — where fewer than two cases or no essence
    are in hand, the session and the person's artifacts searched for cases — and, where the case
    reads as this protocol's, what the first sheet needs; later ones run on each turn that bears on
    the run. A sheet needs cases and examples in the person's own material — the cases' own
    context by artifact read and search, examples from the person's domain, and an external fetch
    where that domain lies outside their artifacts. What you say you read, you read whole. What
    was reached and what was not, with what each unreached source would need, are named; where
    collected material conflicts, what conflicts with what; what stays open is the person's
    unknown. A case collection turns up that you bring to the sheet enters as found by you
    (`found`). -/
axiom collect : Context P → List (Evidence P)

def pass (c : Context P) : Context P := c ++ (collect c).map (·.val)

/-- A turn of the response to a turn that bears on the run: a sheet or another turn of your own,
    what a tool or the environment returned, or a peer's report. Never the person's. -/
def ResponseTurn (P : Type) := {e : Turn P // e.origin = .assistant ∨ e.origin = .external ∨ e.origin = .peer}

/-- **Your response** to a turn that bears on the run and does not close it, the first included:
    the work inside this protocol's domain you carry forward on a judgment you state — using the
    abstraction-to-be in the person's work among it — with what that work returned, and the sheet
    `respond` draws. Reversible work inside this protocol's domain goes as far as you can reach
    within this response, most important first; what comes first and how much is shown are yours
    to infer, on what least loads the person's recognition. A case the work turns up that you bring
    to the sheet enters as found by you (`found`). -/
axiom response : (Context P → Response P) → Context P → List (ResponseTurn P)

/-- The response, placed in the context. -/
def present (respond : Context P → Response P) (c : Context P) : Context P :=
  c ++ (response respond c).map (·.val)

/-- **Your judgment**: the context holds a case no sheet has shown and no turn of the person's
    brought that would decide against the candidate the recognizing turn recognized; where it
    does, the turn recognizes nothing. -/
axiom Overturned : Context P → Prop

/-- The crystallized abstraction: every view read on `c`, the context with the recognizing turn and
    what collection returned for it. The context ends in the declaration. -/
def crystallize (converge : Context P → Response P) (c : Context P) :
    CrystallizedAbstraction P :=
  { context := c ++ [(converge c).val], goal := goal c, candidate := candidate c,
    crossView := crossView c, cases := casesSection c, setAside := setAsideReadings c,
    openTrace := openTrace c ((candidate c).reading :: (candidate c).merges),
    dissent := dissent c,
    provenance := provenanceOf c }

open Classical in
/-- `respond` draws the sheet the Protocol section describes under "The sheet": the candidate
    as `candidate` gives it, the cross view (`crossView`), and the cases of `casesSection`. A
    recognition is the person's closing, filled, citing the latest utterance; it crystallizes
    unless the context, with what collection returns for it, is `Overturned`. -/
def induce (respond session converge : Context P → Response P) :
    Context P → List (Utterance P) → Outcome P
  | c, []      => .holding c
  | c, u :: us =>
    let c' := fuse c u
    if ¬ Reaches c' then induce respond session converge (c' ++ [(session c').val]) us
    else
      let latest : Bool := match closing c' with
        | .filled _ src _ _ => decide (src.idx + 1 = c'.length)
        | .open_ _          => false
      let c₁ := pass c'
      if latest ∧ ¬ Overturned c₁ then .crystallized (crystallize converge c₁)
      else induce respond session converge (present respond c₁) us

def start (respond session converge : Context P → Response P) (c : Context P)
    (us : List (Utterance P)) : Outcome P :=
  let c₁ := pass c
  match notActivated c₁ with
  | some why => .notActivated c₁ why
  | none     => induce respond session converge (present respond c₁) us

/-! ── CONVERGENCE ──
crystallized — the one closing of `Outcome`, the person's; the trace it carries is its structure's
fields. notActivated and holding are not closings: the first is your reading before any sheet, the
second a run that has not crystallized. The convergence evidence: the turn read as the closing, in
its own words, with the goal and the candidate it recognized.
-/

/-! ── TOOL GROUNDING ──
What each operation of this contract does. An interaction with the person is one of two kinds,
and its kind fixes how it continues once its text is presented. A Constitution settles a judgment
through the person's turn. An Extension settles none for the person: it passes on a result its
cited ground fixes, or carries reversible work forward on a judgment the AI states, which stays
the AI's proposal until the person takes it. Beyond the Constitution operations a contract
annotates, whether work goes forward this way or waits for the person's answer is the AI's
judgment in the situation, and work that cannot be undone waits for the authorization it needs.
Work carried forward, on a grant or a stated judgment or as clear work, returns with an account
of how the request was read, what was judged on what basis — naming an alternative set aside
where it may be preferred — and how far the work went.
-/

inductive Interaction | constitution | extension

inductive Continuation | stop | proceed

inductive Annot | sense | observe | track | transform | dispatch | interaction (kind : Interaction)

/-- Every interaction presents its text; a Constitution then stops for the person's turn, and an
    Extension proceeds. -/
def Interaction.realization : Interaction → Continuation
  | .constitution => .stop
  | .extension    => .proceed

inductive Op | detect | collect | judge | sheet | carry | readTurn | declare | converge | seam

def grounding : Op → Annot × String
  | .detect   => (.sense, "Internal analysis: whether this is the protocol's case, as `notActivated` reads it, over the utterance and the context")
  | .collect  => (.observe, "artifact read, artifact search; external fetch (conditional: the domain lies outside the person's artifacts), its URL cited where used: what `collect` reads, as its doc states")
  | .judge    => (.sense, "Internal analysis: the whole run afresh against the whole context, and whether a recognition is `Overturned`, once collection has returned")
  | .sheet    => (.interaction .extension, "the sheet the Protocol section describes under \"The sheet\", within the response `response` composes")
  | .carry    => (.transform, "artifact read, artifact write, environment run: the work `response` carries forward; what it returns enters the context")
  | .readTurn => (.sense, "Internal analysis: whether the latest utterance bears on this run and what it does there — a move, a value taken, a reading set aside or brought back, words about an open item, a closing — read whole against the fused context as it now stands, as `Reaches`, `ClosingSupported`, `SetAsideSupported`, `StandingSupported`, and `OpenSupported` read it")
  | .declare  => (.interaction .extension, "before activation, on an invocation only — AI-guided activation stays silent —, your `notActivated` reading in plain words with its basis, and what was searched")
  | .converge => (.interaction .extension, "at a crystallization, the convergence evidence CONVERGENCE names: the closing turn quoted beside the trace and the dissent")
  | .seam     => (.interaction .extension, "after a crystallization, or not activating on an invocation, proceed to the next move the person declared, citing that turn; after a crystallization, that move goes from wherever it stands, carried to the abstraction as it crystallized")

/-! ── COMPOSITION ──
*: product — (D₁ × D₂) → (R₁ × R₂). Dimension resolution emergent via session context.
-/

end

end Periagoge

Read the full file on GitHub · 600 lines

Files

What ships with it

1 file beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. yesterday Changed b3f81102b35c
  2. 2d ago Changed · +15 lines ce9806d1b76d
  3. 5d ago Changed · +8 lines 7626c875d41a
  4. 6d ago Changed · -1 lines · +16 tokens per session c76154c98fff
  5. 23d ago Changed · +12 lines · -6 tokens per session f84069fd4571
  6. 24d ago Changed · +301 lines e1fc7e7580a7
  7. 1mo ago First seen · 265 lines · 40 tokens per session scan A 0072462fc917

Subscribe to this mod's changes

induce is a skill published in the GitHub repository jongwony/epistemic-protocols (174 stars, last pushed today), licensed MIT. It adds 50 tokens to every session and 10,150 once invoked, about $0.0002 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-03.

Related

Other skills, from other repositories

flow-next-tracker-sync

Project a flow-next spec to a tracker issue (Linear, GitHub, GitLab, Jira) and reconcile two-way. Use when asked to sync to a tracker. NOT plan-sync.

gmickel/flow-next · 44 tokens

flow-next-resolve-pr

Resolve PR review feedback. Fetches unresolved threads, triages, fixes, replies and resolves via GraphQL. Use when asked to address review comments.

gmickel/flow-next · 36 tokens

taiyi-ui-design

A design-planning guide for describing how an application's user interface should look and behave. It produces a UI-DESIGN.md document covering layouts, components, interactions, accessibility, and error states.

Dong90/oh-my-taiyiforge · 35 tokens

plugin-code-review-orchestrated

Orchestrates a code review of the spring-plugin repository through scope/context passes, routing, domain reviewer subskills, and per-artifact validation. Use when asked to review a PR, diff, commit, branch, module, or file set, to run a full orchestrated review, or to produce a validated review report.

explyt/spring-plugin · 72 tokens

docs

Use when documentation generally needs to catch up with a branch before pushing or merging, covering internal developer docs, external customer-facing docs, and release notes together — "update the docs", "do a docs pass before I merge", "make sure everything's documented". Prefer this when no single documentation…

The01Geek/prflow · 97 tokens

fix-js-globals

Fix JavaScript no-globals errors that UI5 linter reports but cannot auto-fix. Use this skill when linter outputs: no-globals rule with message "Access of global variable '...' (...)" in JS files Cases handled (linter CANNOT auto-fix): Assignments to global namespaces: sap.myNamespace = {...} Global namespace…

UI5/plugins-coding-agents · 243 tokens