probe

probe is a skill for Claude Code from jongwony/epistemic-protocols. It costs 47 tokens per session (7,062 once invoked), scanned A, original, MIT.

A situation-review guide that offers several possible explanations for what is missing or unclear, including conditions that would disprove each one, before suggesting a protocol to use.

In plain words
What is it for?
Use it to compare possible deficits in the current situation and choose a suitable protocol with the user's input.
Why use it?
It helps when you know something is wrong but do not yet know which kind of problem or process fits.

Skill for Claude Code

Written for Claude Code: user-invocable in frontmatter.

Part of the epistemic-cooperative plugin — 6 skills shipped together

Good fit Use it to compare possible deficits in the current situation and choose a suitable protocol with the user's input.

Compare 6 skills from other repositories ↓
Install with agentmods
npx agentmods add skills/jongwony/epistemic-protocols/probe
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 probe
Clone the repo
git clone --depth 1 https://github.com/jongwony/epistemic-protocols

Made for: Claude Code.

Or install epistemic-cooperative, the plugin that ships this one along with the rest of its 6 skills.

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 probe

README.md
[![agentmods](https://agentmods.dev/badge/skills/jongwony/epistemic-protocols/probe/github.svg)](https://agentmods.dev/skills/jongwony/epistemic-protocols/probe)
Your own site
<a href="https://agentmods.dev/skills/jongwony/epistemic-protocols/probe"><img src="https://agentmods.dev/badge/skills/jongwony/epistemic-protocols/probe/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 probe

Your own site · 80×15
<a href="https://agentmods.dev/skills/jongwony/epistemic-protocols/probe"><img src="https://agentmods.dev/badge/skills/jongwony/epistemic-protocols/probe.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 47 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 7,062 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 warn 7 Sept 2026
SkillSpector: 4 findings, up to medium

These are SkillSpector’s own severities. On a checked sample its high-severity flags on skills were ~96% false positives — a documented command, a public API, a “never do X” rule — so we show them as a caution to read, not a verdict. Why →

  • medium analysis-evasion · line 1
    Suspicious Unicode normalization or mixed-script content
    Fix: Review the flagged content for security risks. Ensure no credentials, secrets, or sensitive data are exposed.
  • medium Agent Snooping · line 66
    Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
    Fix: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
  • medium Agent Snooping · line 270
    Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
    Fix: Remove all code or instructions that list or read other skills' files or directories. Skills should operate independently; cross-skill access is a privilege escalation.
  • medium Rogue Agent · line 229
    Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
    Fix: Remove any persistence mechanisms (cron jobs, startup scripts, state files). Skills should not maintain state across sessions without explicit user consent.
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.00047 $0.07062
Opus 5.5 $0.00019 $0.02825
Sonnet 5.5 $0.00009 $0.01412
Haiku 4.5 $0.00005 $0.00706

Measured 2d ago against content hash 957b7cfe8870, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade A, and why

probe 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 2d ago.

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.

epistemic-cooperative/skills/probe/SKILL.md · 484 lines

How it starts

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

Probe Skill

Resolve a sense that something is off, before the person can name what is stuck, into a situation they recognize, through grounded candidates for what is stuck. Type: (DeficitUnrecognized, AI, RECOGNIZE, UserSituation) → RecognizedSituation.

Definition

Probe (ἐπίγνωσις, epígnōsis: knowing-upon, recognition of what was already there): A dialogical act of turning a person's sense that something is off into a situation they recognize. AI reads the present situation and the descriptions of the other installed skills, and shows the candidates the ground carries for what is stuck, at least two where it carries them — each a description of the situation resting on turns of it that it cites, with the condition that would rule it out, the installed skill that takes it where one does, and that skill's declared end where its description declares one. The person takes one shown candidate, puts the situation in their own words, or says none shown is theirs; that recognition is what the run yields, and no score, ranking, or reading of the AI's makes it. Where the ground carries only one, AI shows that one and says it carries no second rather than inventing one; where it carries none, AI says so. Taking a shown candidate whose line showed a skill takes that skill's invocation with it, unless the person declines the run.

/-!
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 ──
Probe(U) → start(catalog, c) → probe(catalog, c, utterances), where c is the fused session
context and catalog is as `Catalog` states, read once when the run starts:
  [no unrecognized deficit, and the person did not invoke this]  nothing is shown; not activated
  pass(c): what `gathered` reads enters the context; the situation is read against the catalog
  [the ground carries two or more candidates]  present them → Stop
  [it carries fewer]                           say so, with the one line it carries, if any,
                                               and what more of the situation would help → Stop
  next utterance u: c' := fuse(c, u) →
    [u is the person's own invocation of this probe]  this run holds where it stood; the
      invocation is `start`'s
    [u does not bear on this run]  as `Reaches` states; the session answers it
    [a turn of the person's is still owed]  no answer closes → pass(c') → a round that serves it
    [u takes a shown candidate, puts the situation in their own words, or says none shown is
     theirs]  close: recognized → the hand-off `invokedBy` names
    [otherwise] u is more of the situation — a narrower slice, a correction, a candidate set
      aside, a question, a read beyond the session admitted → pass(c') → the same reading
  no utterance: the round holds; nothing is recognized and nothing closes
-/

/-! ── MORPHISM ──
UserSituation
  → detect(deficit_unrecognized)   -- something is off and what is stuck goes unnamed; an invocation of the person's own activates on its own
  → read(catalog)                  -- as `Catalog` states, once at the start; the contract names no skill and no deficit
  → draw(candidates, situation)    -- descriptions of the situation, each resting on turns it cites, each with what would rule it out
  → present(candidates)            -- grounds, then the rules-out condition, then the skill and its declared end; contrary grounds; the turn yields
  → recognize(situation, person)   -- a shown candidate, the person's own words, or none shown: the person's observable act
  → emit(RecognizedSituation)      -- the answer, what the round showed, the contrary grounds closed over, and the recognizing turn, as session text
  → RecognizedSituation
requires: deficit_unrecognized(U) ∨ invoked(U)   -- runtime checkpoint, read by `start` before the first pass
deficit:  DeficitUnrecognized                    -- activation precondition
preserves: the catalog                           -- read, never written; the context only grows
invariant: Recognition over Resolution
-/

namespace Probe

/-! ── 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}

/-- `U`: the person's present situation — their utterances and the context they stand in. What is
    stuck is read from it, never stored beside it. -/
abbrev UserSituation (P : Type) := Context P

/-- One installed skill as the session lists it: its name and its description. -/
structure CatalogEntry where
  skill       : String
  description : String

/-- The installed skills' descriptions, read as they stand when the run starts and never written:
    `entries`, every installed skill other than this probe's own, and `self`, this probe's own
    entry, whose skill no entry names. This contract lists no skill and no deficit of its own. -/
structure Catalog where
  entries  : List CatalogEntry
  self     : CatalogEntry
  excludes : ∀ e ∈ entries, e.skill ≠ self.skill

/-- **Your reading** of a description: the end it declares — what the person can say or recognize
    once that skill has run — or `none` where it declares none. Nothing is written in where a
    description is silent, and a skill whose description declares no end keeps its candidacy. -/
axiom declaredEnd : CatalogEntry → Option String

/-- A candidate for what is stuck: one description of the situation, and the installed skill that
    takes it where one does. -/
structure Candidate where
  situation : String
  skill     : Option CatalogEntry

/-- The end a candidate's line shows: its skill's declared end, and none where it has no skill or
    the skill's description declares none. -/
def Candidate.ending (k : Candidate) : Option String := k.skill.bind declaredEnd

/-- **Your judgment**: the cited turn carries this about the situation, read against the context as
    it now stands — what the person said, or what a read returned. -/
axiom ClaimSupported : Context P → Turn P → String → Prop

/-- One thing the situation shows, with the turn that carries it. -/
structure Claim (c : Context P) where
  text      : String
  src       : Cite c
  supported : ClaimSupported c (c[src.idx]'src.lt) text

/-- One line of a presentation: a candidate whose skill, if any, is one the catalog holds, what in
    the situation it rests on — one cited turn at least — and the condition that would rule it
    out, which may be one not yet observed. -/
structure Line (catalog : Catalog) (c : Context P) where
  candidate : Candidate
  inCatalog : ∀ e, candidate.skill = some e → e ∈ catalog.entries
  grounds   : List (Claim c)
  grounded  : grounds ≠ []
  rulesOut  : String

/-- What a round showed. -/
inductive Presentation (catalog : Catalog) (c : Context P)
  /-- two or more candidates side by side, no two lines with the same situation text, each line
      with its grounds, its rules-out condition, and its `ending` -/
  | alternatives (lines : List (Line catalog c)) (two : 2 ≤ lines.length)
      (distinct : (lines.map (·.candidate.situation)).Nodup)
  /-- the ground carried fewer than two: said as such, with the one line it carries where it
      carries one, laid out like any other line, and what more of the situation would help -/
  | short (line : Option (Line catalog c))

/-- The lines a round showed: one or none in a short round. -/
def Presentation.lines {catalog : Catalog} {c : Context P} :
    Presentation catalog c → List (Line catalog c)
  | .alternatives ls _ _ => ls
  | .short l             => l.toList

/-- The candidates a round offered to take. -/
def Presentation.shown {catalog : Catalog} {c : Context P} (p : Presentation catalog c) :
    List Candidate :=
  p.lines.map (·.candidate)

/-- **Your reading**: your latest presentation as it was shown, read from that response, on the
    context it was shown on — the first `n` turns of `c`, a strict prefix; what was shown, not
    what you meant to show; `none` before any. -/
axiom presented : (catalog : Catalog) → (c : Context P) →
    Option (Σ n : Fin c.length, Presentation catalog (c.take n))

/-- The candidates the latest round offered to take. -/
def shownIn (catalog : Catalog) (c : Context P) : List Candidate :=
  ((presented catalog c).map (·.2.shown)).getD []

/-- **Your record**: your contrary grounds bearing on what the latest utterance recognizes — the
    candidate it takes, or the person's own wording — each with what it bears on and what it rests
    on, attached where the person recognizes over them; raised again only on new evidence. Empty
    when there are none. -/
axiom dissent : Context P → List String

/-- How a person's turn recognizes what is stuck. Premise: one utterance carries one of these or
    none; whatever else it says is more of the situation — read by the next pass where the turn
    closes nothing, and left in the context where it closes. -/
inductive Answer
  /-- the person takes a shown candidate as their situation; `run` is whether this probe is to
      run the skill its line showed — true where the turn neither declines that run nor itself
      invokes that skill, since the line said that taking the candidate runs that skill -/
  | shown (k : Candidate) (run : Bool)
  /-- the person says what is stuck in their own words -/
  | reworded (situation : String)
  /-- the person says none of the shown candidates is theirs -/
  | noneShown

/-- **Your judgment**: the cited turn recognizes the situation this way, read whole against the
    context as it now stands. A candidate is taken where the turn says it is theirs or goes on with
    it as theirs, and its `run` is read from whether the turn declines the skill's run or itself
    invokes that skill; a rewording stands as they said it, beside any contrary ground and never
    replaced by yours, and "none of these" together with what is stuck in their own words is a
    rewording. Uncertainty, a hypothetical use, a question about a candidate, and silence recognize
    nothing, and your readings, scores, and rankings fill nothing. -/
axiom AnswerSupported : Context P → Turn P → Answer → Prop

/-- Only the person recognizes. -/
def answerCoord : Coord P Answer :=
  { admits := (·.val = .person), supports := AnswerSupported }

/-- **Your reading** of the latest utterance: `open_` where it recognizes nothing. -/
axiom answer : (c : Context P) → Occ (answerCoord (P := P)) c

/-- **Your reading**, on the present turn: the person invoked this probe themselves; an earlier
    invocation does not keep it on. -/
axiom Invoked : Context P → Prop

/-- **Your judgment**, on the present turn: the person senses something is off and does not name
    what is stuck — symptoms described in place of it, hesitation between skills, "which one fits
    this?". An earlier probe does not keep this on; each occasion is read afresh, and a round the
    person just passed over or ended is not raised again unbidden — it is read as received. A
    request for a recommendation drawn from session history is not this. While a run of this
    probe holds, no unsolicited probe starts: what bears on what is stuck is that run's, as
    `Reaches` reads it. -/
axiom DeficitUnrecognized : Context P → Prop

def Activated (c : Context P) : Prop := Invoked c ∨ DeficitUnrecognized c

/-- **Your judgment**: the latest utterance bears on this run — a recognition, more of the
    situation, a question about a candidate, a correction, a read beyond the session admitted —
    judged on what the whole utterance does, read on the context with it. An utterance that ends
    the probe or turns to other work leaves the run as it stands: the session answers it, that
    answer stays in the context, no round of this run is raised, and nothing closes. Once the
    person has ended the probe, or passed over a round they did not ask for, a later utterance
    bears on this run only where it reopens it. -/
axiom Reaches : Context P → Prop

/-- **Your reading**: a turn of the person's is still owed before a recognition closes — read on the
    context as it now stands, the latest utterance included. Guidance for the reading, not cases it
    must check: contrary grounds of yours the person has not closed over, any the latest utterance
    itself raises against what it takes among them — a fact it states that meets the taken
    candidate's rules-out condition, or a remedy it says was already tried; a reply whose reading
    their words have not settled — after a short round, whether it takes the line shown, gives more
    of the situation, or is their own wording of what is stuck. Where a turn is owed, no answer
    closes, and the next round serves it. -/
axiom Owed : Context P → Prop

/-- Once it has run, the person can say what is stuck right now — one shown candidate, their own
    rewording, or none of those shown — having seen what in the situation each candidate rests on,
    what would rule it out, and what taking it would let them say.
    `RecognizedSituation`, emitted as session text: the person's answer, the candidates the round
    it answered offered — one or none after a short round, where no comparison is claimed — your
    contrary grounds it closed over, and the turn that recognized it. -/
structure RecognizedSituation (P : Type) where
  context      : Context P
  answer       : Answer
  shown        : List Candidate
  dissent      : List String
  recognizedAt : Nat

/-- The move a recognition takes with it: taking a shown candidate whose line showed a skill, with
    its run, takes that skill's invocation; a declined run, a rewording, and `noneShown` carry
    none. It claims no fit beyond the person's recognition. -/
def nextMove : Answer → Option CatalogEntry
  | .shown k true => k.skill
  | _             => none

inductive Outcome (P : Type)
  | notActivated (c : Context P)
  /-- the person recognized their situation — a shown candidate, their own words, or none of
      those shown -/
  | recognized (r : RecognizedSituation P)
  | holding (c : Context P)

/-! ── MODE STATE ──
Λ is the fused context, and the catalog is the run's parameter, read once at start; every reading
above is taken from these. No phase, count, or set of candidates set aside is stored.
-/

abbrev Mode (P : Type) := Context P

/-! ── PHASE TRANSITIONS ──
The catalog is read once at start [Tool]. A pass appends what `gathered` reads [Tool]; `respond`
presents one round from the context it leaves; the person's own invocation of this probe ends this
run holding where it stood, being `start`'s; `session` answers an utterance `Reaches` does not hold
of. Each utterance is fused; where `Reaches` holds and no turn of the person's is owed, a
recognition closes, and anything else `Reaches` holds of is read by the next pass.
-/

/-- **Your collection** for one pass. The situation is the current session, and the files and
    records the person pointed at in it are read in the pass; a read beyond them — earlier
    sessions, or files and records they have not pointed at — is offered in a round with what it
    would read, and runs only once a person's turn admits it. What the context already holds from
    a read is not read again unless an utterance or evidence says it changed. Each read returns as
    an evidence turn; nothing is written. -/
axiom gathered : Context P → List (Evidence P)

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

open Classical in
/-- The person's recognition, read from the latest utterance against the round before it: a
    shown candidate only where that round offered it, `noneShown` only where a round offered
    candidates, and the person's own words in any case. -/
def closing (catalog : Catalog) (c : Context P) : Option (RecognizedSituation P) :=
  let shown := shownIn catalog c
  match answer c with
  | .open_ _ => none
  | .filled a s _ _ =>
    if s.idx + 1 = c.length then
      match a with
      | .shown k b =>
        if k ∈ shown then
          some ⟨c, .shown k b, shown, dissent c, s.idx⟩
        else none
      | .noneShown =>
        if shown = [] then none
        else some ⟨c, .noneShown, shown, dissent c, s.idx⟩
      | .reworded t => some ⟨c, .reworded t, shown, dissent c, s.idx⟩
    else none

open Classical in
/-- `respond` presents the round a pass leaves, as a horizon the person may take, reword, or set
    aside, never as the answer. Where the ground carries two or more candidates, drawn from
    different readings of the situation: each line its candidate's description of the situation,
    then what it rests on, each ground with the turn it cites, then the condition that would rule it
    out, then the skill that takes it, saying that taking the candidate runs that skill, and that
    skill's declared end where its description declares one — after the evidence, never as evidence
    of fit, and reading "as above" on a later line with the same skill. Each line's grounds are
    given with the same care and specificity, and nothing in the layout favors one line. Where it
    carries one: that line, laid out as any line is, saying the ground carries no second; where it
    carries none: say so; either way, what more of the situation would help. Every round shows the
    contrary grounds you hold, what a turn of the person's is owed for where one is owed, and,
    wherever one would help, the read beyond the session `gathered` would offer, with what it would
    read; then the turn yields to a free answer — a candidate, their own words, none of these, or
    more of the situation — with no option list. A question about the shown candidates, and a round
    serving an owed turn, keep that round's candidates as they were shown beside what is answered or
    owed; they are redrawn only where the ground moved for another reason, and a candidate the
    person said is not theirs is drawn again only on new ground. Throughout, the wording is
    tentative and speaks of fit. -/
def probe (catalog : Catalog) (respond : Catalog → Context P → Response P)
    (session : Context P → Response P) : Context P → List (Utterance P) → Outcome P
  | c, []      => .holding c
  | c, u :: us =>
    let c' := fuse c u
    if Invoked c' then .holding c
    else if ¬ Reaches c' then probe catalog respond session (c' ++ [(session c').val]) us
    else
      match (if Owed c' then none else closing catalog c') with
      | some r => .recognized r
      | none =>
        let c₁ := pass c'
        probe catalog respond session (c₁ ++ [(respond catalog c₁).val]) us

open Classical in
def start (catalog : Catalog) (respond : Catalog → Context P → Response P)
    (session : Context P → Response P) (c : Context P) (us : List (Utterance P)) : Outcome P :=
  if Activated c then
    let c₁ := pass c
    probe catalog respond session (c₁ ++ [(respond catalog c₁).val]) us
  else .notActivated c

/-! ── LOOP ──
The loop is dialogue: each round ends where the turn yields, and nothing counts down. Every
utterance `Reaches` holds of that closes nothing is read whole by the next pass — a narrower
slice of the situation, a correction, a candidate set aside, a question, a read beyond the session
admitted, a turn that was owed — and the pass reads the situation again on the context as it now
stands. No number of rounds ends the probe; the person's recognition does, and without it the
round holds.
-/

/-! ── CONVERGENCE ──
recognized: the person's turn took a shown candidate, put the situation in their own words, or
said none shown is theirs; the RecognizedSituation carries the answer, what the round it answered
offered, the contrary grounds it closed over, and which turn recognized it — quoted in the trace
with the intent taken from it, and how the turn was read — the candidate taken; whether this
probe runs its skill, the person declined its run, or the person's own turn invoked it; and what
will now run — relayed before any hand-off. What it hands
off is `invokedBy`'s.
Convergence evidence: (UserSituation → [rounds] → Candidates(grounds, rules-out, ends) →
recognition → RecognizedSituation). Demonstrated, not asserted.
-/

/-! ── 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 | catalog | gather | draw | present | short | readTurn | converge | invoke

def grounding : Op → Annot × String
  | .detect   => (.sense, "Internal analysis: whether the person senses something is off without naming what is stuck; an invocation of their own activates without it")
  | .catalog  => (.observe, "artifact read, once at start: the descriptions of the installed skills other than this probe's own, as the session lists them, read where they are installed when the listing does not carry one; read-only")
  | .gather   => (.observe, "artifact read, record read: what the person pointed at in the session, and reads beyond it a person's turn admitted; read-only")
  | .draw     => (.sense, "Internal analysis: candidates drawn from different readings of the situation, each grounded in turns it cites, with the condition that would rule it out and the skill from the catalog that takes it")
  | .present  => (.interaction .constitution, "two or more candidates, each line with its description, cited grounds, rules-out condition, and skill with its declared end, as `respond` lays them out; your contrary grounds; a free answer, with no option list and no ranking")
  | .short    => (.interaction .constitution, "the ground carries fewer than two candidates: said as such, with the one line it carries, if any, as `respond` lays it out, and what more of the situation would help")
  | .readTurn => (.sense, "Internal analysis: whether the latest utterance is the person's own invocation of this probe, as `Invoked` reads it, whether it bears on this run, as `Reaches` reads it, whether a turn of the person's is still owed, as `Owed` reads it, and what it does there — a shown candidate taken, with or without its run, the person's own words, none shown, or more of the situation — read whole against the fused context")
  | .converge => (.interaction .extension, "RecognizedSituation, relayed before any invocation as CONVERGENCE states")
  | .invoke   => (.dispatch, "invoke: after the trace, in the same turn, the skill nextMove names — the person's taking a line that disclosed its run is their invocation of that skill — with the recognized situation in the session; then this run ends")

/-- The operation a run hands off through: a recognition whose `nextMove` names a skill invokes it
    by `.invoke`; any other outcome hands nothing off. -/
def invokedBy : Outcome P → Option Op
  | .recognized r => (nextMove r.answer).map fun _ => .invoke
  | _             => none

/-! ── COMPOSITION ──
The recognized situation stays in the session as text for whatever runs next to read. The one
hand-off is `invokedBy`'s, to a skill the catalog held and the person's taking carried; no other
contract is named here.
-/

end

end Probe

Read the full file on GitHub · 484 lines

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. 2d ago Changed · -2 lines 957b7cfe8870
  2. 13d ago Changed · +8 lines e1f24ddf979a
  3. 14d ago Changed · +170 lines · +15 tokens per session 2302bade9f9f
  4. 15d ago Changed · +13 lines 7b2573aa5c21
  5. 17d ago Changed 3b96f3a6748c
  6. 19d ago Changed 2e35a7cb1103
  7. 29d ago Changed d4039e5f6910
  8. 1mo ago Changed 27e88cdf6acf
  9. 1mo ago Changed · +1 lines 4736002f4272
  10. 1mo ago First seen · 294 lines · 32 tokens per session scan A 3dd9914640bc

Subscribe to this mod's changes

probe is a skill published in the GitHub repository jongwony/epistemic-protocols (174 stars, last pushed yesterday), licensed MIT. It adds 47 tokens to every session and 7,062 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-08-30.

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

hermes-tool-router-onboarding

First-run onboarding for the hermes-tool-router plugin — explain what the router does, offer the optional classifier API key exactly once, and verify the router is live. Use when a fresh Hermes profile has hermes-tool-router installed and was never onboarded, or when the user asks about router setup, the classifier…

AtlasOmnia/hermes-tool-router · 75 tokens