Horismos Protocol

SkillDev tools

Define epistemic boundaries per decision. Fires when a decision's direction, scope, type, or ownership is undefined. Type: (BoundaryUndefined, AI, DEFINE, TaskScope) → DefinedBoundary

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Horismos Protocol skill

What this skill tells your AI

The instructions your AI receives, as published by jongwony/epistemic-protocols in horismos/skills/bound/SKILL.md and read by ahel’s review.

Define epistemic boundaries per decision through AI-guided classification. Type: (BoundaryUndefined, AI, DEFINE, TaskScope) → DefinedBoundary.

Definition

Horismos (ὁρισμός): A dialogical act of proactively defining epistemic boundaries per decision, where AI probes for boundary-undefined domains, dispatches the boundary kind up-front (a KindRouteMap of recognition seeds — direction/priority, scope, type/concept, ownership — plus an emergent/naming path) through a fail-closed deficit-fit certificate, collects contextual evidence to enrich classification quality, and presents each domain for user classification by a uniform settlement disposition (user-supplies / AI-proposes / AI-autonomous / dismiss) into a BoundaryMap consumed by all downstream protocols. The disposition coproduct is the same for every kind — the captured kind sets WHAT boundary is being settled, the disposition sets HOW that boundary value is settled downstream. Ownership is one kind among the seeds (who decides), and it is the degenerate case where the boundary value being settled is itself the disposition — so for ownership, content and disposition coincide; for every other kind they separate cleanly.

── FLOW ──
Horismos(T, B_prior?) → Probe(T) → Bᵢ? →
  |Bᵢ| = 0: Qc(zero_signal_finding) → Stop → [Confirm: deactivate | Reopen(d): Bᵢ := {d}, proceed]      -- zero-signal gate (`Zero-signal surfacing`)
  |Bᵢ| > 0: Phase 0b sync_kind_route(T) → KindRouteMap →                                            -- up-front KIND dispatch (dispatch-first: kind settles before downstream consumers read it)
    [single_dominant_kind(KindRouteMap, T, context): relay(captured_kind + basis) (extension) → proceed (kind committed)   -- entropy→0 fast-path (option-set relay test): one kind dominates, foils route away → NO turn yield
     | else: Stop → captured_kind (constitution)]                                                   -- ≥2 viable hypotheses ∨ undecidable foil ∨ emergent gesture naming no single kind ∨ live ground leaves the emergent question undetermined → mandatory Constitution gate
    bind_kind(captured_kind) → KindBinding                                                           -- {label, positive_predicate, evidence, atomicity}; non-atomic → split/route, re-sync before continuing
    certify(KindBinding, local_claims) → DeficitFitCertificate                                         -- fail-closed: status(certificate) ≠ pass BLOCKS value-space binding (split / route claim / narrow-disambiguation first)
      status(certificate) = route:      → route_away(routed_deficit) → deactivate (a local route claim holds the kind; no DefinedBoundary)
      KindBinding.atomicity = non-atomic: → split → re-sync Phase 0b → re-certify
      status(certificate) = ambiguous:  → Qa(captured_kind, claims_supported) → Stop → Attribution → attribute — Own: status re-reads as pass → bind_value_space; Route(d): route_away(d) → deactivate; Unattributable: deactivate (unattributable) with a relay of the finding; no DefinedBoundary
      status(certificate) = pass:       → bind_value_space → BoundaryClassification                                  -- the uniform settlement-disposition coproduct, generated ONLY after certificate passes (same codomain for every kind; captured kind sets each option's content, not the coproduct)
    init_loop_state: cycle_n=1, BoundaryEssence="", B = seed_if_kind_match(B_prior, captured_kind), B_seed = Bᵢ (seed only when kind(B_prior) = captured_kind; kind-mismatched prior map → advisory, NOT seeded — see seed_if_kind_match; B_seed carries the Phase 0 domain signal — incl. the zero-signal Reopen(d) seed {d} — as unclassified cycle-1 anchor candidates (non-anchored remainder residualizes at the Phase 1 residualize), never unioned into the classified map B), default=DefaultClassification(MixedTrend), EssenceTrend(history, cycle_n)=MixedTrend at init since cycle_n < 2 (kind-general — the per-cycle disposition-trend machinery runs for every kind), loop:
    Phase 1 Ctx(T, cycle_n) [per-cycle re-scan] → (Sub-D[cycle_n], auto_resolved?) →
      Sub-D empty ∧ residual ≠ ∅: → Phase 4 (substrate exhausted, residual remains)
      Sub-D empty ∧ residual = ∅: → TERMINAL CARRIERS (Phase 1 row) → DefinedBoundary → converge (substrate exhausted, all surfaced domains classified — no empty Phase 4 gate)
      auto_resolved: → Phase 3 (skip Phase 2 for this cycle; no user A — the substrate-settled classification is carried into Phase 3)
      else:          → Phase 2
    Phase 2 Qc(Sub-D[cycle_n], kind, BoundaryClassification, BoundaryEssence, cycle_n, B_snapshot, default) → Stop → A
    Phase 3 (user-response: conservative parse(A) → (typed_A?, TerminationIntent?) — a commitment is recognized only when the whole response's decision-relevant meaning supports that reading; otherwise Phase 2 re-presents from A with the map unmutated; auto-resolved: typed_A = substrate-settled classification, no TerminationIntent) →
      integrate(typed_A?, B, BoundaryEssence) → (B', Δessence)                                      -- total current-cycle fold: classification updates the anchor; termination-only residualizes it and returns B' = B with the empty delta
      crystallize(Δessence, BoundaryEssence) → BoundaryEssence'                                      -- sole producer of the accumulated essence; the empty delta is the identity
      refresh B'-snapshot with the current default_for_residual                                       -- BEFORE the branch below, on EVERY fold including a terminating one: a just-residualized anchor gets its provisional entry here, so every route below reads a complete map
      ImplicitTermination: → TERMINAL CARRIERS (Phase 3 row) → DefinedBoundary → converge
                            -- "default" is Λ.default_for_residual at entry to Phase 3 (the value Phase 2 surfaced); NOT re-derived
      ExplicitTermination: → Phase 4
      else:                → DefaultClassification(EssenceTrend(history', cycle_n)) → default' for NEXT cycle (kind-general; count-only over the uniform disposition) → re-snapshot with default' → cycle_n += 1, loop
  Phase 4 (optional path) Qf(residual, FinalGateDisposition) → Stop → TERMINAL CARRIERS (Phase 4 row) → DefinedBoundary

── MORPHISM ──
TaskScope, B_prior?
  → probe(task, context)                                           -- detect boundary-undefined domains
  → sync_kind_route(task, context) → KindRouteMap                  -- up-front dispatch: one hypothesis for every recognition seed (direction/priority, scope, type/concept, ownership) + emergent/naming path; each seed hypothesis carries positive_predicate, evidence, differential_future, route_away conditions
  → [single_dominant_kind: relay(captured_kind) (extension) | else: present(KindRouteMap) (constitution)]  -- option-set relay test over the kind hypotheses AND the live ground: one dominant kind (entropy→0) relays without a turn yield — either a seed (positive_predicate satisfied, foils' route_away hold, no emergent indicated) or an emergent kind the user's own wording already names unambiguously; ≥2 viable ∨ undecidable foil ∨ an emergent gesture naming no single kind ∨ an emergent question the live ground leaves undetermined gates. BOTH branches feed bind_kind → certify → bind_value_space (certificate fail-closed on both)
  → bind_kind(captured_kind) → KindBinding                         -- {label, positive_predicate, evidence, atomicity}; non-atomic kind → split or route before continuing
  → certify(KindBinding, local_claims) → DeficitFitCertificate         -- {own_claim, route_claims[], claimed_by, evidence}; fail-closed — status(certificate) ≠ pass BLOCKS bind_value_space; fits the captured kind's positive_predicate against the own claim and the route claims inscribed in THIS SKILL.md
  → bind_value_space → BoundaryClassification                     -- the uniform settlement disposition {UserSupplies, AIPropose, AIAutonomous, Dismiss}, generated ONLY after certificate passes; same codomain for every kind (kind sets each option's content); relay / dead-signal test applied; frozen for the activation
  → seed(B_prior, B)                                               -- hermeneutic carry-over at Phase 0b step 4 (AFTER bind_value_space + B init): optional prior BoundaryMap seeds the freshly-initialized B ONLY when kind(B_prior) = captured_kind (same-kind — its dispositions were settled over the SAME boundary question). Values are always type-compatible now (every kind shares BoundaryClassification), so the guard is SEMANTIC: a kind-mismatched prior answers a DIFFERENT boundary question (e.g. an ownership prior's "AIAutonomous" decided who-owns, not how-wide a scope is) and is surfaced as advisory context, NOT seeded. Seeded domains enter `context_resolved` partition with "prior classification" basis (entries mutable in subsequent cycles). Phase 0 only DETECTS B_prior (binds Λ.B_prior together with its kind); it does not seed B, which does not exist until loop-state init
  → enrich(domains, codebase, cycle_n)                             -- per-cycle context collection (re-scan)
  → classify(domain, as_inquiry) → typed_A ∈ BoundaryClassification               -- per-cycle object_ref(kind) classification by the uniform settlement disposition (the captured kind sets the content of each disposition option; the 4-value coproduct itself is kind-invariant)
  → integrate(typed_A?, B, BoundaryEssence) → (B', Δessence)       -- total current-cycle fold; does NOT update default_for_residual
  → crystallize(Δessence, BoundaryEssence) → BoundaryEssence'      -- sole producer of the accumulated essence; the empty delta is the identity
  → snapshot(B', residual, default_for_residual) → B_complete'     -- refreshed after EVERY fold, termination included, and BEFORE any terminal route below: this is what gives a just-residualized anchor its provisional entry — classified entries ∪ (residual ↦ default_for_residual), at the value Phase 2 surfaced
  → DefaultClassification(EssenceTrend(history', cycle_n)) → default'                      -- count-based EssenceTrend → DefaultClassification for NEXT cycle's residual (runs on loop continuation ONLY; count-only over the uniform disposition, so the derivation is kind-general — it reads disposition counts, never kind-specific content)
  → snapshot(B', residual, default') → B_complete''                -- continuation only: supersedes B_complete' for the cycle about to open
  → [finalize | bulk_classify | identity] → Λ.boundary_map         -- terminal operation selected by the reachable convergence path; source, write, and final value are defined once in TERMINAL CARRIERS
  → DefinedBoundary
requires: boundary_undefined(T)            -- runtime checkpoint (Phase 0); sole activation precondition. (status(certificate) = pass is the Phase-0b value-space-BINDING gate, NOT an activation precondition — it lives in the certificate-before-binding invariant below and the Phase 0b → Phase 1 transition; route/ambiguous status routes/re-syncs inside Phase 0b rather than blocking activation.)
deficit:  BoundaryUndefined                -- activation precondition (Layer 1/2); the certificate's own_claim deficit for in-scope kinds
preserves: task_identity(T)                -- task scope invariant; BoundaryMap and BoundaryEssence mutated; B_prior seed entries are mutable across cycles
invariant: Definition over Assumption
invariant: certificate-before-binding      -- status(certificate) = pass strictly precedes bind_value_space (shared meta-backbone order)

── TYPES ──
T              = TaskScope (task/project requiring boundary definition)
B_prior        = Optional(SeededPrior)                        -- optional invocation seed for hermeneutic carry-over (prior BoundaryMap detected in session context). Seeded into B at Phase 0b step 4 ONLY when the prior map's kind matches the captured kind (same-kind — same boundary question). The guard is SEMANTIC, not type-based: every kind shares BoundaryClassification, so a mismatched prior's values are type-valid but answer a DIFFERENT boundary question, so a kind-mismatched prior map is surfaced as advisory context, NOT seeded as a structural entry. Seed entries are mutable across cycles
SeededPrior    = { map: BoundaryMap, kind: Kind }             -- the prior BoundaryMap together with the boundary kind it was produced over (Phase 0 step 3 detection binds both). The carried kind is the typed carrier the same-kind guard tests: kind(B_prior) ≡ B_prior.kind
seed_if_kind_match : (Optional(SeededPrior), Kind) → BoundaryMap  -- seeds the prior map ONLY when B_prior.kind = captured_kind (returns B_prior.map); a kind-mismatched prior (B_prior.kind ≠ captured_kind) or B_prior = ⊥ returns ∅ (a mismatched prior is surfaced as advisory, not seeded)
Probe          = T → Set(Domain)                              -- boundary-undefined domain detection (Phase 0; existence check, not exhaustive enumeration)
Domain         = { name: String, description: String, evidence: Set(Evidence) }
Evidence       = { source: String, content: String }
Bᵢ             = Set(Domain) from Probe(T)                    -- initial boundary-undefined domain signal (cycle 1 seed: formally carried into Phase 0b loop-state init as Λ.B_seed = Bᵢ, kept separate from the classified map B until classification — on zero-signal Reopen(d), Bᵢ = {d} is the one entry the Phase 1 re-scan cannot be assumed to re-derive)
ZeroSignalConfirmation = user's answer to a zero-signal finding ∈ {Confirm, Reopen(Domain)}  -- Confirm accepts no boundary-undefined signal (`Zero-signal surfacing`); Reopen names a domain Probe(T) missed, seeding it into Bᵢ and proceeding

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
161
Forks
15
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
bound
Source
github.com/jongwony/epistemic-protocols