---
name: Contextualize
slug: contextualize
category: AI Engineering
description: Contextualize detects when an output is technically correct but does not fit the current application context. Use it after execution to surface applicability mismatches for review, routing, or adaptation.
github: "https://github.com/jongwony/epistemic-protocols/tree/main/epharmoge/skills/contextualize"
language: JavaScript
stars: 161
forks: 15
install: "npx degit https://github.com/jongwony/epistemic-protocols/tree/main/epharmoge/skills/contextualize ~/.claude/skills/contextualize"
installs_to: ~/.claude/skills/contextualize
source_path: epharmoge/skills/contextualize/SKILL.md
collection_size: 25
category_size: 3670
collection_url: "https://dirskills.com/collections/jongwony/epistemic-protocols"
added: 2026-09-08T05:36:04.395Z
last_synced: 2026-09-08T05:36:04.395Z
canonical_url: "https://dirskills.com/skills/contextualize"
---

# Contextualize

Contextualize detects when an output is technically correct but does not fit the current application context. Use it after execution to surface applicability mismatches for review, routing, or adaptation.

**Install:**

```bash
npx degit https://github.com/jongwony/epistemic-protocols/tree/main/epharmoge/skills/contextualize ~/.claude/skills/contextualize
```

## README

# Epharmoge Protocol

Detect application-context mismatch after execution through AI-guided applicability verification, where correct results that may not fit the actual context are surfaced for user judgment. Type: `(ApplicationDecontextualized, AI, CONTEXTUALIZE, Result) → ContextualizedExecution`.

## Definition

**Epharmoge** (ἐφαρμογή): A dialogical act of verifying that results fit the actual application context — from Aristotle's notion of practical application — resolving the gap between technical correctness and contextual appropriateness through structured mismatch surfacing and user-directed adaptation.

```
── FLOW ──
Epharmoge(R, X) → Eval(R, X) → Mᵢ? →
  Mᵢ = ∅: Qz(zero_mismatch_finding) → Stop → [AcceptNoMismatch: R_final := Some(Λ.R), deactivate (no aspect ¬warranted; execution stands as-is) | Reopen(aspect): re-scan Eval focused on it (one attempt: any detection → the SAME Phase 0 pipeline as the Mᵢ ≠ ∅ arm below — bind_kind, split, absorb, certify, value space — and then whichever Phase 0 exit that pipeline reaches, Phase 1 where anything passed the certificate and trivial convergence where nothing did; still-∅ → relay finding, deactivate)]
  Mᵢ ≠ ∅: bind_kind each [split where non-atomic] → absorb into ∅ (same claim → merge, new → init_occurrence) → Mᵢ → ∀m ∈ Mᵢ: certify(m, local_claims) → [status = route: close m as Route(routed_deficit), value_space := None, m never registering | status = ambiguous: Qa(m, claims_supported(m)) → Stop → Attribution → attribute(m, ·) — Own: m now passes on the user's attribution; Route(d): close m as Route(d), attribution-assigned; Unattributable: close m as Residual, attribution-assigned — value_space := None on either close] → keep(status = pass) → Mᵢ_passed → ∀m ∈ Mᵢ_passed: m.value_space := Some(bind_value_space(m)) →
    Mᵢ_passed = ∅ ∧ adjudicated(Λ.R, X) (every flagged aspect carries a disposition assigned at registration — Route(routed_deficit) or Residual, by the certificate where the fit was unambiguous and by the user's attribution at Qa where it was not — via the typed disposed(a) predicate): → emit routing recommendations + surface any Residual (each flagged aspect either handed to a deficit or left unattributable by the user) → R_final := Some(Λ.R) → deactivate (trivial convergence: adjudicated by disposition, Λ.R unadapted)
    Mᵢ_passed ≠ ∅: AssessFit(R, X, Mᵢ_passed) → F → Λ.fit_map := F → Register(Mᵢ_passed) → Λ.carrier := Some(locator(C)) → SelectNext(pending, Λ.fit_map) → Mₛ → judgment_settled(Mₛ, Λ.fit_map)? →
      [Some(Overruled): judgment_relay_overruled → report the retraction + the cited fit evidence → close Mₛ as (Overruled, Keep), relay-assigned → NO Qc, no turn yielded, Λ.R untouched → next pending, or converge]
      [Some(Upheld): judgment_relay_upheld → judgment_state := Some((Upheld, basis)), Overruled/Keep dropped from the presented set]
      [None: judgment_state := None — the verdict is the user's this cycle, and the reset is what stops last cycle's relayed Upheld from being read onto this mismatch] →
      -- DISPOSITION HALF. The judgment half above has already run; what becomes of the result is always the user's:
      Qc(Mₛ scoped by the CURRENT Λ.fit_map, judgment_state) → Stop → A = (j, d) →
      [d = Adapt(direction)] adapt → R' → Λ.R := R' → close Mₛ (the act having happened, and ahead of the fold, which needs it out of pending) → Eval(Λ.R, X) → bind_kind each [split where non-atomic] → absorb into pending (same claim → merge, new → init_occurrence) → Mₑ (what the fold opened) → ∀m ∈ touched: certify(m, local_claims) → ∀m ∈ touched where status = ambiguous: Qa(m, claims_supported(m)) → Stop → Attribution → attribute(m, ·) → ∀m ∈ touched: m.value_space := Some(bind_value_space(m)) where status = pass, None otherwise (total on both outcomes, so a merged element that had a space and stopped passing does not keep it) → ∀m ∈ touched where status ≠ pass: route → close m as Route(routed_deficit); Unattributable → close m as Residual — and every such close completes the entry of an m registered before this fold, so it LEAVES pending, while an m that was not never enters → Mₑ_passed := the passing members of Mₑ (registration is for what the fold OPENED; an element registered before this fold has nothing to register) → record update(Λ.carrier: add Mₑ_passed AND bring into line the entry of every touched element ALREADY REGISTERED before this fold, whose reading, evidence, certificate, value space and stamp the fold moved — Register reaches only what the fold OPENED) → AssessFit(Λ.R, X, pending) → F' → Λ.fit_map := F' → (loop: back to Phase 1 above — judgment half, then disposition half — until control reaches a named terminal)
      [d = Keep] close Mₛ (nothing has to happen first) → no re-scan, no Mₑ; R_final is bound at convergence, not here → (pending non-empty: back to Phase 1 above; emptied by this close: the ordered terminal check)
      [d = Discard(replacement)] discard → close Mₛ as Discard (ahead of the sweep, or the mismatch the user actually withdrew is recorded Moot) → R_final := replacement, every mismatch REMAINING pending → unjudged Moot, no re-scan → deactivate (withdrawal convergence: the evaluated target is withdrawn; the replacement is carried, not adjudicated)

── MORPHISM ──
(R, X)
  → evaluate(result, context)          -- detect applicability mismatch
  → bind_kind(mismatch) [split where non-atomic] → absorb(detections, carried) → certify(element, local_claims) -- shared meta-backbone: bind each mismatch as a kind, fold the detections into what is already carried (same claim → merge, none → open one), then certify deficit fit (fail-closed) per ELEMENT against the claims inscribed in this SKILL.md, BEFORE it enters the pending/disposition flow
  → assess_fit(result, context, mismatches) -- sort applicability fit before user judgment
  → surface(fit_scoped_mismatch) -- present mismatch with fit basis and evidence
  → judge(mismatch) → dispose(result, judgment, disposition) -- TWO AXES: whether the flagged aspect stands, then what becomes of the result (adapt / keep / discard)
  → ContextualizedExecution
requires: mismatch_detected(R, X)       -- runtime checkpoint (Phase 0), and the AUTO-ACTIVATION condition ONLY (Layer 2). A user-invoked run
                                        -- (/contextualize, Layer 1) enters WITHOUT it: its Phase 0 may find Mᵢ = ∅, and that run then owes the
                                        -- zero-mismatch confirmation (Qz, `Zero-mismatch surfacing`) rather than declining to have started — which is why
                                        -- ContextualizedExecution's own guard names that confirmation as a conjunct
deficit:  ApplicationDecontextualized    -- the deficit this morphism takes, and the certificate's own_claim deficit for in-scope mismatches. It gates
                                        -- Layer 2 auto-activation; it does not gate Layer 1 invocation
preserves: X                             -- application context is fixed reference; morphism transforms R only
                                         -- WITHIN THE RUN. X is bound fresh at each activation off a session context that ACCUMULATES, so a later activation
                                         --   binds a moved X rather than the same one again — a result this run judged, and the judging itself, are among what it moved
                                         --   (Scan scope reads session context; Λ.X is bound once per activation). Reading `fixed` as `static in the world` gets a
                                         --   read-only run exactly backwards: it produces no artifact and still shifts the ground every later fit judgment is made on
invariant: Applicability over Correctness
invariant: certificate-before-registration  -- status(m.certificate) = pass strictly precedes registering a mismatch into pending, and STRICTLY PRECEDES ITS STAYING THERE where the registration already exists: an element whose evidence the fold grew is re-certified, and a status that stops passing keeps it out of pending — taking it out where it was registered before the fold, keeping it from entering where it was not. So nothing sits in pending on a certificate that does not currently pass AT ANY POINT pending IS READ, whether the element arrived by opening or by merging — not asserted mid-pass, since the re-scan writes the non-passing status and closes the element out of pending as steps of one uninterrupted pass and AssessFit, the first reader of pending after it, runs once both have happened (shared meta-backbone order, on both scans)
invariant: transformative revalidation (NON-MONOTONE) -- an Adapt disposition mutates the Eval(R, X) target into R', breeding emergent mismatches into Mₑ; re-scan mandatory; a run can have more left to settle after a disposition than before it
invariant: judgment-disposition separation -- the judgment (does the aspect stand?) and the disposition (what becomes of the result) are separate answers, the judgment relay-eligible on cited evidence, the disposition never relay-eligible on its own account — what becomes of the result is answered against the target in front of the user
invariant: relay closes only what leaves the artifact unchanged -- a relay may close a mismatch only where the close changes nothing about the result

── TYPES ──
R      = Result to be evaluated (source-agnostic: AI output, analysis conclusion, decision outcome, or any completed work product)
           -- Input type: morphism processes R uniformly; enumeration scopes the definition, not behavioral dispatch
X      = Application context (environment, constraints, user situation) — type name Context; Λ.X is its one binding, fixed at activation (preserves: X), which is why a bare X appears below rather than Λ.X. ContextChannel's Context member is an evidence source, not this type
Eval   = Applicability evaluation: (R, X) → Set(Mismatch)
MismatchId = a run-local handle naming ONE OCCURRENCE the protocol carries — assigned in ascending order at the moment the occurrence is kept
                 — on absorb's not-same arm, the same arm on either scan — and never reassigned or reused within the run
                 -- NOTHING DISPATCHES ON IT: no phase branches on its value, no convergence predicate reads it, and it never decides whether two
                 --   mismatches are the same claim — that stays identity(m). It is a handle for pointing, and pointing only (`Identity, occurrence, and reading stay distinct`)
                 -- A detection that MERGES into an element already carried is not a new occurrence and takes no id; that element keeps its own (absorb)
absorb = HOW A SCAN'S DETECTIONS BECOME WHAT THE PROTOCOL CARRIES: Set(Mismatch) × Set(Mismatch) → Set(Mismatch), folding the detections into the carried set ONE AT A
                 TIME. FIXED POSITION, and every block that scans states it at that position: AFTER bind_kind + split (so the fold ranges over atomic claims and each
                 side of the judgment below is one claim) and BEFORE certify (so whatever the fold yields is already a complete Mismatch when a certificate-assigned
                 close — Route, Residual — or a later Moot inherits one). Each detection takes one of two arms, and WHAT IS JUDGED IS WHICH CARRIED ELEMENT, IF ANY, STATES THIS
                 CLAIM — not whether some element does. The judgment yields the element itself, because that is what the merge below needs; a yes/no would
                 leave the target to be invented wherever more than one carried element reads plausibly, which uniqueness and transitivity being
                 disclaimed above makes a live possibility rather than a corner. HOW the run reaches that element is its own; THAT it names one is the
                 contract's:
                 --   an element → merge(carried, d) on the element the judgment named: it absorbs the detection and stays the element. THE MERGED ELEMENT IS WHAT THE NEXT DETECTION
                 --                MEETS, so several detections of one claim fold to one and nothing a detection carried is overwritten by a later one — merge
                 --                combines, and there is no last write to win. What that does NOT buy is order-independence: whichever detection opens the
                 --                element is the one whose id and whose STATEMENT of the claim it keeps — not its whole binding, since the evidence takes in every later detection's and the certificate and value space are re-derived over the result (merge) — and a judgment of sameness need not be transitive, so a different arrival
                 --                order can partition the same detections differently. That follows from sameness being judged, not from the fold
                 --   none      → init_occurrence(d): it enters the set as an element of its own
                 -- THE STAMP RIDES EVERY DETECTION, ahead of both arms: match_identity decides unrepaired for each one by the single rule (does it read as the
                 --   same claim as Mₛ, off identity), and absorb only routes where that answer lands — onto the element the new arm opens, or into the carried
                 --   element through merge's disjunction. NEITHER ARM DECIDES IT, which is what lets a detection reading as Mₛ's claim AND as one already
                 --   carried record both facts instead of losing the first to the second
                 -- THE SET FOLDED INTO IS WHATEVER THE PROTOCOL ALREADY CARRIES: ∅ at Phase 0, pending at the Phase 2 re-scan. "Already pending" is therefore NOT a
                 --   case this step handles apart — it is the accumulator having survived an earlier scan, and a detection meeting it takes the same two arms as one
                 --   meeting an element opened a moment ago. One operation, stated once, is what every scan path runs
                 -- ONE ELEMENT PER CLAIM is what the fold is directed to reach, not a property the contract can guarantee: sameness is judged, and a judgment carries
                 --   no invariant. What the type layer contributes is the narrowing identity(m) ranges over, which is what raises the odds the judgment lands right
merge  = Mismatch × Mismatch → Mismatch, combining two readings of ONE claim. The carried element is the left side and stays the element
                 --   id : the carried element's, untouched — the same occurrence taking on more of what is known about it
                 --   aspect, description, evidence, severity : the CURRENT READING, combined. What the combination comes out as is read at that turn from what the
                 --                two sides actually say; the protocol fixes THAT they are combined, never what the combination is
                 --   unrepaired : the disjunction of the two, the detection's side being the value match_identity decided for it (absorb, above) — a
                 --                set-only stamp, so a claim stamped on either side stays stamped
                 --   kind_binding : positive_predicate is the carried element's — it is ONE claim and this arm was taken because the run read the detection
                 --                as that claim, so it is stated once — while evidence is the UNION. The claim now stands on what both sides found it standing
                 --                on, which is the whole of what a second detection of one claim contributes to identity
                 --   certificate, value_space : RE-DERIVED from the merged binding, by the same certify and bind_value_space steps that derive them anywhere,
                 --                and never carried across unchanged. THE REPLACEMENT IS TOTAL ON BOTH PATHS: a re-derived pass writes the new space,
                 --                and a re-derived route close, or an Unattributable attribution at Qa, writes value_space := None, since a mismatch closed at
                 --                registration carries none (below) — an element that had a space before the merge must not keep it after one; a re-derived
                 --                ambiguous is put to Qa before either. The reason is that status is not fitted from the predicate alone: claimed_by collects the
                 --                claims THE EVIDENCE supports and ambiguous is "none holds on the evidence at hand", so evidence moving can move pass → route
                 --                or → ambiguous. Carrying the earlier certificate would let a stale pass route into adaptation a mismatch that now belongs to
                 --                a sibling deficit, which is the fail-closed invariant going out through the merge arm. Where the re-derived certificate no
                 --                longer passes — on the fit, or on the user's attribution where the fit was ambiguous — the element is closed exactly as any other is, and LEAVES pending if it was in it
                 -- SO IDENTITY DOES MOVE UNDER MERGING, in its evidence component: the claim is the same claim and stands on more. The certificate follows it
                 --   because the certificate was always fitted to the binding, and the binding is what grew
                 -- The field list is TOTAL: merge names every field of Mismatch and leaves none to the caller
init_occurrence = the step that turns a detection the fold judged NEW into an occurrence the protocol carries: Mismatch → Mismatch, producing every field no earlier
                 step could produce. Reached on absorb's not-same arm alone, so a detection that folds into an element already carried never passes through it. It
                 writes exactly two fields:
                 --   id        := the next handle in this run's order
                 --   unrepaired := the value match_identity already decided for this detection (absorb) — false on a Phase 0 scan for want of an Mₛ, by that same rule rather than by a separate default
Mismatch = { id: MismatchId, aspect: String, description: String, evidence: String, severity: Severity, unrepaired: Bool, kind_binding: KindBinding, certificate: DeficitFitCertificate, value_space: Option(ValueSpace) }
                 -- ASSEMBLED ACROSS THE REGISTRATION PIPELINE, not built by the scan: Eval detects an aspect and its reading, and bind_kind,
                 --   absorb (whose not-same arm runs init_occurrence), certify and bind_value_space each add what only they can produce, in the
                 --   order `Certificate before registration; revalidate after adaptation` fixes. So the whole
                 --   form is what a REGISTERED mismatch carries, and a detection on its way through has only what its stage has reached
                 -- object_ref: the per-mismatch anchor the certificate evaluates and the value-space binds over (epharmoge-local instantiation of the shared backbone's object_ref)
                 -- the mismatch's kind/domain is carried by kind_binding.label (Axis = String, emergent) — the single source of the kind label,
                 --   and a DISPLAY NAME only: which registration a mismatch IS is settled by identity(m) below, never by this label
                 -- Mismatch.evidence is the human-facing indicator shown at surfacing (a String). The typed set the certificate and identity(m)
                 --   range over is kind_binding.evidence (Set(Evidence)) — two different fields, and only the second one decides anything
                 -- THE FIELDS SPLIT FIVE WAYS, and merge (above) treats each accordingly: id is PRESERVED, the carried element's and
                 --   untouched; aspect, description, evidence and severity are the CURRENT READING and are combined; kind_binding is
                 --   IDENTITY, whose predicate cannot move while its evidence unions; unrepaired is a monotone stamp that merge takes the
                 --   disjunction of; certificate and value_space are DERIVED and are re-run over the merged bin
