All notable changes to Spectre are documented in this file. The project follows
Semantic Versioning; while the version is below 1.0, a
minor release may contain documented breaking API changes.
0.3.0 — 2026-08-12
Added
Added
LLMS.md, a machine-oriented guide shipped in the Hex package and included in ExDoc's generatedllms.txt, covering the public entry points, host boundaries, Morph lifecycle, runtime-data rules, and test expectations.Added
Spectre.Morph, a host-governed evolution API whose canonical Surface bounds runtime Skill mount, replacement, and disable proposals. Morph derives real replay obligations from immutable Definition diffs, requires independent evaluation and approval, and revalidates the exact Candidate at activation and recovery. Runtime data never becomes executable code or authority.Added the opt-in
Spectre.Experienceplane with deterministic redaction, explicit retention and expiry, immutable content-addressed evidence, a verified snapshot transport, a Store behaviour, and a volatile reference adapter. Experience remains observational and never becomes canonical Instance state or authorization evidence by itself.Added policy-gated
Spectre.Reflectionand the mechanicalSpectre.Projection.Reflection. Declared, Effective and Observed facts are kept separate; Skill instructions are quoted data; missing evidence is reported as a limitation; transported projections are regenerated against exact Definition, Manifest, Activation and Experience inputs.Added
Spectre.Reflection.Operation, a compiled no-side-effect operation whose stores, Activation and policy can only come from trusted host configuration.Added the propositional
Spectre.Forgeplane, compiled multi-model critic contract, content-bound critiques, independent oracle approvals, portable Proposal lineage, a fixed ChangeSet operation subset, and explicit rebase. Critic prose and model agreement never become evaluation evidence by themselves.Added full external-evidence binding to governed ChangeSets. Composer and activation now reject changed Reflection or Experience digests; a rebase always creates a new Proposal identity.
Extended Foundation Conformance with exact Reflection and Forge verification and added the permanent
0.3.0/reflective-runtime-v1.jsonidentity fixture.
Safety and compatibility
- Forge has no publication, approval or activation API. It cannot address authority, kernel policy, evaluator registration, projection generators, or executable code. Only the existing Store-backed governance chain can turn a Proposal's ChangeSet into an activated Candidate.
- Experience recording is denied unless the host passes
enabled?: true. Built-in sensitive keys cannot be removed, non-retained evidence is purged only after explicit confirmation, and every load path revalidates full content identity. - Reflection requires an explicit host policy, actor, purpose and observation time. Its generator never calls a model or assembles inspected prompt fragments as active instructions.
- Load and transport boundaries reject ambiguous atom/string fields, duplicate snapshot evidence, duplicate keyword options, mutated Proposal structs, oversized Forge collections, nonportable data and digest drift.
- State remains writer v5, Run writer v2 and canonical Instance checkpoints schema 4. All guaranteed 0.1.6–0.2.9 fixtures remain readable and unchanged; the module-first Agent/Skill path continues to lower into the single canonical runtime model.
- This branch changes only the
spectrecore. Satellitespectre_*packages retain ownership of their version constraints and adapter conformance.
0.2.9 — 2026-08-11
Added
- Added portable, content-addressed
Spectre.Governance.ChangeSetproposals bound to an exact active Candidate, Definition, authority epoch, activation receipt, and evidence digest. The built-in vocabulary covers runtime Skill mount/replace/disable, bounded mutable config and applicability, Candidate evaluation cases, and registered state migrations. - Added the trusted
Spectre.Governance.Composerand compiled handler Registry. Composition re-reads the parent, forbids authority expansion, derives the closure, publishes Definition/Manifest and gate receipts, and returns only a governed Candidate Ref. - Added the governed Candidate state machine, content-addressed gate receipts, fixed checker-version policy, protected-corpus evaluation delta, deterministic Human Report projection, separate review and approval commits, and risk-based human approval.
- Added governed activation/recovery verification and ancestor-only
Spectre.rollback/3through the existing owner fence and activation-generation CAS. - Added conservative administered GC plans that retain by default, verify a complete ancestry-closed inventory, and leave deletion to a revalidated backend transaction or lease.
- Added the permanent 0.2.9 governance compatibility fixture and conformance matrix.
Safety and scope
- ChangeSets and operation payloads are bounded JSON-shaped data and cannot carry code references, callbacks, structs, processes, authority grants, or arbitrary dispatch targets. Host-registered handlers are constrained to their declared component classes.
- Publication, review, approval, activation, rollback, and GC remain explicit host actions. Approval never activates a Candidate; rollback never claims to reverse external Effects; a GC plan never deletes artifacts.
- Candidate-authored evaluation cases have zero protected-score weight and must pass as additional obligations. Gate and approval receipts are re-read and rebound to exact Definition, closure, corpus, checker, validity-window, and proposal identities immediately before activation.
- Protected-corpus identity covers complete canonical evaluation cases rather than ids alone, and the portable delta carries those cases so JSON reload can recompute the binding independently.
- Required gate options can only add to the constitutional gate floor. The protected corpus is non-empty and digest-bound, evaluation thresholds cannot permit score loss or regressions, and every attached receipt is revalidated for status, time, and checker policy even when its class is optional. Semantic-live evidence requires profile, variability, and expiry.
- Prompt and applicability ceilings are sealed into Candidate identity and reverified during activation and recovery. Aggregate prompt reservations are capped, wildcard applicability cannot pass a finite scope ceiling, and a governed replacement cannot erase the mounted anti-hijack corpus. Every governed mount must carry a valid id and inline Definition snapshot.
- Added explicit host rejection for evaluated Candidates, exact transported GC lineage reasons and Candidate live-reference classes, plus linear Candidate parent verification for deep immutable lineages.
- Partial GC inventories remain conservative retain-only evidence. Expired semantic-live evidence still blocks new activation; recovery and rollback expose separate explicit host-only emergency flags that retain all other receipt verification.
- Evaluated Candidate state now persists the verified Human Report and complete evaluation delta, and activation binds the stored delta to its gate receipt, making the review evidence auditable from the Store alone.
- Candidate portable loads reject unknown fields, ambiguous keyword input, malformed governance state, and promotion chains that skip a review state.
- State remains writer v5, Run remains writer v2, and canonical Instance checkpoints remain schema 4. Existing bootstrap Candidates remain valid and all earlier compatibility fixtures are unchanged.
- Because 0.2.9 had not been tagged while these contracts were finalized, untagged development governance artifacts must be regenerated; schema 1 now denotes the release contract recorded by the permanent fixture.
0.2.8 — 2026-08-10
Added
- Added
Spectre.Execution.ProgramandSpectre.Execution.Work: compiled and JSON-shaped precise Work declarations now normalize into one portable, content-addressed IR with step, infer, decide, bounded repeat, completion, failure, explicit budgets, mutable paths, and registered migrations. - Added Work components and handlers to canonical runtime Skills. Work, predicate, inference, and migration refs resolve only against the host Agent's existing operation registry and effective authority.
- Added
Spectre.Execution.Materializer,Spectre.Execution.Materialization, andSpectre.Projection.Executionto seal exact Definition, Program, input, route, continuation, plan, receipt, and budget lineage before execution. - Added effective
Spectre.Prompt.Receiptevidence and safe scalar-onlySpectre.Prompt.Materializerrendering for inference nodes. - Added
Spectre.start_execution/3and Instance integration on the existing fenced operation runtime, including normal pause/amend/resume/stop, query, checkpoint, retry, and recovery behavior. - Added typed Flow ↔ Work and Work → Work handoffs, pure registered state migration preparation/commit receipts, and deterministic rehearsal/replay that cannot dispatch real Effects.
- Added the permanent 0.2.8 data-driven Program and no-Effect rehearsal compatibility fixture.
Migration and safety
- Authored execution data cannot contain modules, Erlang/Elixir MFAs, callbacks, AST, functions, PIDs, references, executors, authority grants, or security policy. Ambiguous atom/string fields and non-portable values fail closed.
- Programs require reachable terminating graphs, positive step/attempt limits, and bounded repeats. Pure predicates and migrations are verified against registered operation contracts; inference requires a registered cognitive operation.
- Work cost and duration are capped by the current Authority Envelope. Amendments can change only declared state paths and retain exact Program, input, history, Definition, materialization, prompt receipts, and projection pins across resume and recovery.
- Canonical object expressions reload idempotently; negative list indices are rejected. Materialization, projection, prompt, handoff, migration, and rehearsal digests are recomputed at their load/admission boundaries.
- Program inference enums, authored literals, metadata, and migration
operation refs now have one JSON-stable canonical form, so
to_data -> JSON -> from_datapreserves exact Program/receipt identity. Authored expression depth is capped before digesting and constructors return errors instead of raising on hostile nesting. - Materialization verification now rebinds projection mount, route, continuation, input, and mandatory input evidence exactly as construction does. Prompt placeholders are rendered in one pass, so resolved values are never reinterpreted as template syntax.
- Prompt materialization now revalidates the canonical fragment digest,
rejects dynamic fragments with a typed error, and reserves the
inputnamespace so context data cannot spoof input evidence. Malformed prompt plans fail closed instead of reaching hashing code with invalid bytes. - Rehearsal uses the canonical evidence-digest domain whenever its values are canonical, matching Execution projections and materializations. Structured portable operation receipts use a deterministic tagged fallback in both rehearsal and migration instead of raising during receipt construction.
- Execution Closure and migration-receipt load paths now require exact durable
fields and valid version identities. Malformed keyword input is rejected
without raising, while inert ids such as
timerandqueueremain stable even when an Erlang module with the same name is loaded. - Raw canonical Skill mounts require
origin: :runtime; compiled Skills must enter through their trusted module/Definition path and cannot use origin data to skip runtime load policy. - Fixed retry-budget accounting so
retries: 0permits the initial attempt and an authorized retry is not denied after its counter is consumed. - State remains writer v5, Run remains writer v2, and canonical Instance checkpoints remain schema 4. All prior conformance and runtime Skill gates remain in the release suite.
Scope
- Data Work reuses
Spectre.Operation.Runtime; no parallel executor or checkpoint model was added. Publication, Activation, Skill lifecycle, and Effect execution remain explicit host actions. - Generated callbacks, goal hierarchies, autonomous Forge behavior, reflection, and governance remain outside this gate.
0.2.7 — 2026-08-10
Added
- Added
Spectre.Skill.Definition, a single canonical wrapper for compiled and runtime-authored Skills. Equivalent origins expose equal semantic IR while exact Refs retain origin and publisher provenance. - Added data-only runtime Flows with exact routing, closed reply fragments, and
references to operations already registered by the host Agent. The compiled
DSL gains
requires_operation/2andcall_operation/2over the same IR. - Added structured
Spectre.Skill.Applicability, executable positive/negative anti-hijack examples, and fail-closed conflict and ambiguity handling. - Added versioned per-Skill prompt budgets and
Spectre.Router.IndexProfile. Runtime mount reserves the kernel window, checks granted budget classes, and accounts for retained draining generations. - Added
Spectre.Projection.Routing, a deterministic non-executable projection with a profile-bound disposable cache key. - Added immutable
Spectre.Skill.Runtimemount, replace, and disable lifecycle with authority capabilities, revision CAS, exact Definition-pinned continuations, and drain completion. - Added the permanent 0.2.7 runtime Skill and Routing projection fixture.
Migration and safety
- Runtime Definitions reject code references, AST, executable prompt templates, uncapped fragments, undeclared or unregistered operations, ambiguous routes, failed anti-hijack examples, and authority gaps.
- Runtime operation handlers return a portable
Spectre.Operation.Request; Spectre does not execute it or widen authority. Publication, activation, and lifecycle changes remain explicit host actions. - Canonical runtime Skill loads rederive prompt usage from the restored fragments, require every fragment cap, and reject declared budget counters that do not exactly match the derived evidence.
- Runtime fragment placement, trust, provenance, and granted priority are assigned by Spectre rather than accepted from authored data. Composite placeholder values fail closed instead of invoking arbitrary string protocols.
- JSON string operation references resolve only to matching IDs already in the host Agent registry, without creating atoms. Forbidden applicability tags remain exclusion filters and cannot increase routing specificity.
- Canonical Skill structs and prebuilt
Spectre.Skill.Definitionvalues are revalidated at load and mount. Malformed route, requirement, prompt, or Routing-projection collections return indexed errors instead of protocol or function-clause exceptions. - Negative anti-hijack examples now fail when one or several routes match.
Inputs that cannot be normalized return
{:invalid_skill_input, shape}from Skill routing and response boundaries instead of crashingString.Chars. - State remains writer v5, Run remains writer v2, and canonical Instance checkpoints remain schema 4. All 0.2.6 foundation and Stack gates remain in the release suite.
- Generated callbacks, goal-driven Work, autonomous Forge behavior, empirical reflection, and governance remain outside this gate.
0.2.6 — 2026-08-10
Added
- Added
Spectre.Foundation.Conformance, an ExUnit-independent public gate that performs real decode, migration, current validation, and re-encoding for State, Run, and canonical Instance checkpoints. - Added Definition/Manifest conformance for canonical bytes and compiled module-first values, including stable Definition, authority, closure, and Manifest evidence.
- Added
Spectre.Stack.Conformance, which compiles a complete satellite package matrix through the real Stack invariants and rejects incompatible versions, missing requirements, conflicts, duplicate packages, and capability ownership collisions. - Added a permanent 0.2.6 golden fixture that pins every core compatibility artifact from 0.1.6 through 0.2.5 and the complete schema/contract matrix.
Migration and safety
- No durable writer changed: State remains v5, Run remains v2, and canonical Instance checkpoints remain schema 4. Definition, Manifest, Candidate, and Stack contracts are unchanged.
- Added integrated compiled Agent+Skill, legacy migration, corruption, and Stack composition coverage. Existing restart, activation-race, owner-fence, and ambiguous persistence suites remain part of the same release gate.
- Added migration documentation for 0.2.6 and an explicit 0.2-to-0.3 ledger. Runtime-authored values must lower into the existing canonical models, and publication or activation remains an explicit host action.
0.2.5 — 2026-08-10
Added
- Added first-class
Spectre.Skill.StateBindingvalues with stable Skill id, state schema Ref, generation, branch and parent ids, owning Definition Ref, revision CAS, owner fence, active/dormant status, retention, provenance, and a deterministic binding receipt. - Added canonical per-Skill state with one selected branch and retained branch history. Public APIs inspect branches, update active state through schema, generation, revision, authority, and owner fences, and transition dormant branches through conservative retention.
- Added activation-time
:skill_state_transitions.:resume,:fork,:migrate, and:abandonare explicit choices whenever a target Definition already owns a dormant branch;:initis accepted only when no such branch exists. - Added a permanent 0.2.5 compatibility fixture with dormant A and selected B branches bound to a schema-4 Activation.
Migration and safety
- Canonical checkpoint writers now emit schema 4. Readers accept schemas 1 through 4; schema-3 checkpoints gain an empty Skill-state section in memory.
- Definition A → B → A never merges private Skill state. A rollback with a dormant target branch fails until the host explicitly resumes, forks, migrates, or abandons it. Branch identity and parent lineage remain distinct even when schemas match.
- Writes outside the selected Skill id, branch, owner Definition, or exact state schema are rejected before commit. A saved generation or owner fence cannot authorize a stale write.
- GC is conservative. Active or Activation-referenced branches cannot become eligible; retained Runs, operations, and child branches also block collection. Purge retains a receipt-bearing tombstone and clears only state.
- Definition artifact purge now treats every non-purged Skill-state binding as a live reference.
Scope
- State migration data is supplied by trusted host code; this release does not run migration callbacks or copy/merge state implicitly. Shared Memory, artifacts, external Effects, and experience evidence are not private Skill state and are never rolled back by this mechanism.
0.2.4 — 2026-08-10
Added
- Added portable
Spectre.Event.Envelopevalues for input, reply, policy, Flow, Work, Vigil, and global events. Admission records the continuation, origin evidence, selected Definition owner, activation generation, current authority epoch, owner fence, canonical revision, and deterministic receipt. - Added same-sequencer event admission. Run and operation continuations retain their pinned Definition owner across activation; unowned input uses the active Definition. Missing, mismatched, expired, ambiguous, or incompatible events are durably quarantined instead of rebound.
- Added
Spectre.Instance.Lifecyclewith independent admission, authority, retention, and activation axes plus revision CAS and monotonic transitions. Public helpers expose drain, revoke, explicit transitions, and inspection. - Added bounded admitted and quarantine windows to canonical Instance state, and pinned Definition metadata to operation loops.
Migration and safety
- Canonical checkpoint writers now emit schema 3. Readers accept schemas 1, 2, and 3; a schema-2 Activation is migrated to an equivalent active lifecycle record in memory.
- Draining blocks new Turns and operations but preserves already-owned continuations. Closing blocks continuations. Revocation advances the current authority epoch and blocks admission, continuation, commit, retry, Effect dispatch, and operation dispatch.
- A Run's stored authority epoch is lineage only. Runtime authorization always consults the current lifecycle and current Instance owner fence.
- Added a permanent 0.2.4 compatibility fixture covering schema-3 event admission, quarantine, and Definition lifecycle recovery.
Scope
- First-class Skill state generations, branches, rollback, and retention are intentionally deferred to 0.2.5. Event delivery and transport authenticity remain host-owned; this release records their portable evidence.
0.2.3 — 2026-08-10
Added
- Added stable AgentRef/Instance identity. Compiled module, declared Definition version, and Stack digest are resolver hints rather than parts of the durable key; the former key remains available only for controlled migration.
- Added immutable bootstrap
Spectre.Definition.Candidateartifacts and content-addressed Candidate Refs. Activation always re-reads Candidate, Definition, Manifest, and publication receipt from the trusted Definition Store. - Added canonical
Spectre.Instance.Activationsnapshots with generation CAS, authority epoch, execution closure, state bindings, owner fencing token, provenance, and deterministic activation receipt. - Added the
Spectre.Instance.Ownerlease/fencing host contract. The bundled local adapter is explicitly single-owner; distributed ownership remains a host responsibility. - Added Definition pins to Runs and durable retention of all live Run continuations in canonical Instance checkpoints. New Runs use the current Activation while open Runs preserve their original Definition across activation and restart.
- Added a permanent 0.2.3 compatibility fixture containing checkpoint schema 2, an Activation, and its pinned Run.
Migration and safety
- Run checkpoint and canonical checkpoint writers now emit schema 2. Readers accept schemas 1 and 2 and immediately migrate legacy values to the current in-memory representation.
Spectre.Instance.CheckpointStore.migrate_instance_key/6lets core invoke an adapter'smigrate_instance_key/5callback to atomically move an exact legacy checkpoint to its stable key. Core verifies the migrated target byte-for-byte and rejects divergent old/new histories.- Activation is committed synchronously when durable checkpointing is enabled. Stale generations, authority/fencing rollback, ambiguous writes, missing artifacts, or closure drift fail closed.
- Owner-fence loss blocks admission, canonical commit, activation, and Effect or operation dispatch before the external boundary.
Scope
- The Candidate is a trusted-host bootstrap record, not a governed promotion state machine. Runtime-authored ChangeSets, gate receipts, self-activation, event ownership across Definition versions, first-class Skill state, and distributed consensus remain outside this release.
0.2.2 — 2026-08-10
Added
- Added Manifest Contract V2, which seals one canonical Definition Ref with a
fail-closed
Spectre.Authority.Envelope, a completeSpectre.Execution.Closure, publisher/provenance Refs, lineage, and the exact component-contract registry snapshot used during composition. - Added the trusted component contract registry. Unknown
must_understandschemas are rejected; opaque advisory and descriptive components are preserved without acquiring semantics. - Added
Spectre.Definition.Store, the volatile in-memory reference adapter, and an adapter-neutral conformance contract. Publication is immutable, idempotent, parent-aware, receipt-bearing, and verified by read-back. - Added
Spectre.Definition.Resolver. Resolution revalidates Definition, Manifest, receipt, component contracts, and caller-supplied build observations; missing or changed code is blocked by default and never hidden. - Added Stack Contract V2 plus a read-only V1 adapter. V1 declarations remain authority requests and receive grants only through an explicit host ceiling.
- Added a Manifest V2 compatibility fixture exercised on both supported OTP/Elixir CI combinations.
Safety
- Durable checkpoint configuration is rejected when paired with a volatile Definition Store.
- Activation preparation must re-read a published Definition, Manifest, and receipt from the Store. A crash after publish and before the future activation CAS can therefore leave only an immutable orphan artifact.
- Manifest schema maps use textual keys and closed enum decoding, preserving atom-safe decode before implementation modules have been loaded.
Scope
- This release does not yet change Agent identity, activate Definitions, write checkpoint schema 2, promote Candidates, or execute runtime-authored Skills. Those remain separate gated milestones.
0.2.1 — 2026-08-10
Added
- Added
Spectre.Canonical.Value, a versioned portable binary codec with explicit value tags, canonical map-key ordering, atom-safe decode, bounded collections/depth/size, and opt-in struct allowlists. Definition identity no longer depends on Erlang external-term encoding. - Added typed
Spectre.Definition.Canonicalenvelopes,Spectre.Definition.Component, and content-addressedSpectre.Definition.Refvalues. Compiled Agents and mounted Skills lower into one IR throughSpectre.Definition.canonical/2. - Compiled prompt assets now lower into governed canonical fragments carrying closed placeholder schemas, provenance, visibility, trust, priority, budget, token cap, condition Ref, and digest metadata.
- Added the deterministic projection interface and exact
Spectre.Projection.Auditgenerator. Projection digests bind Definition Ref, generator ID/version, optional evidence digest, and content. - Added a canonical Definition compatibility fixture exercised by both OTP 28 and OTP 29 CI jobs, plus property coverage for map order and cross-process digest stability.
Safety
- Canonical data rejects PID, port, reference, function, improper-list, non-byte-aligned bitstring, non-finite float, unknown atom, noncanonical map, executable EEx, and known secret-bearing configuration boundaries.
- Executable compiled callbacks and modules lower to explicit
compiled_onlycode Refs. Runtime Definition data contains neither callback functions nor quoted AST. - Definition and projection digests attest integrity only; they do not imply publisher trust, approval, or current authority.
Compatibility
- Existing module-first Agents, Skills, Instance identity, Runs, checkpoints, and execution semantics remain unchanged. Definition Store, Manifest V2, activation, and runtime-authored Skills are not part of this release.
0.2.0 — 2026-08-08
Fixed
- Reply sanitization now uses Unicode-safe, case-insensitive matching without applying byte offsets from a transformed string to the original reply.
before_actionsuppression is scoped to the owning Run, provider-qualified guard references no longer raise, andprotect/after_actiondeclarations retain source order.- Canonical checkpoints, Run values, and journal JSON maps now encode every JSONB-hostile binary consistently and restore journal phase/time values.
- Semantic-cache candidates retain their intended arbitration precedence; post-LLM clarification results remain clarifications; unloaded custom arbitrators are loaded before capability checks.
- The bounded Turn dispatcher delivers a terminal decision reached by its final allowed transition instead of reporting a loop overflow after effects have committed.
- Invalid Flow state and malformed Instance intents now fail only their owning
Run/intent instead of terminating the whole Instance. Concurrent
execute/3calls also reject while another Run advances without staling the waiting Run. - Recovery now honors retry policy and budget for crashed attempts, journal buffering preserves FIFO order within a partition, and deferred/digest delivery receipts can be re-authorized after their delivery window opens.
- Terminal operation loops, correlations, Subject link intents, semantic-cache online examples, and rule-example embeddings now have bounded retention or bounded reusable caches with explicit configuration.
- History limits and summarizer callbacks are validated, operational budgets reject unknown keys, and stable term digests use deterministic encoding.
- Instance idle shutdown is re-armed after operational/checkpoint activity; malformed optional offline semantic-cache sources degrade at runtime with a warning instead of disabling routing.
- Nested-flow prompt injections now retain the flow path where each injection
was declared. Parent and child
start/endoperations therefore compose as proper nested scopes, and repeated inner-flow names under different parents no longer collapse onto the same runtime scope. - A warm
Spectre.Classifiernow accepts every GenServer name form (including{:via, ...}), retains its startup embedding/configuration options for later calls, and still lets explicit per-call options override them. - Training and semantic-cache datasets skip unsupported label shapes instead of raising. JSONL and multi-source accumulation is now linear, and semantic cache imports index cacheable rules by label once instead of scanning every rule for every row.
classifier ..., context: ...andlabel_examples: ...now remain in the classifier configuration instead of leaking into adapter options, so both settings reach default and custom classifier prompts. Flow-taxonomy prompt rendering now builds an ordered tree in one pass, avoiding quadratic work across large sets of sibling flows.- A failed probabilistic strategy (LLM classifier error, arbitration failure)
now recovers to the agent's declared
:UNKNOWNrule when it has a handler whose checks match the input, so the agent's explicit fallback behavior runs instead of returning an unroutable lowercase:unknownroute and an empty reply. The recovered route uses strategy:unknown_fallbackand preserves the failure metadata (local,fallback_error). Spectre.State.Codecoutput is now safe for JSON database columns: binaries that JSONB cannot store verbatim (invalid UTF-8 or embedded zero bytes, e.g. compact lifecycle ids) are encoded as tagged Base64 values and decoded transparently. Legacy payloads still decode.Spectre.Classifierinterns its artifact schema atoms when the module loads, so release VMs decode classifier artifacts withbinary_to_term/2in:safemode without the host pre-loading internal Spectre atoms.
Added
Spectre.Reply.Sanitizerstrips Spectre control tokens (<al>,<intent>,<reply>wrappers,INTENT:/AL:control lines,<think>blocks, HTML comments) from model output before it becomesreply_text. It is the runtime default wherever LLM text turns into a visible reply; passsanitize_reply: falseto opt out, or mount an action planner withclean_reply/3to own the cleanup entirely.Spectre.LLM.provider_opts/2strips every runtime-context key the core attaches to adapter calls (plus anyspectre_*-prefixed key), so LLM adapters forward provider options without maintaining hand-written allowlists.Spectre.LLM.runtime_opt_keys/0exposes the list.Spectre.Router.SemanticCache.learn_eligibility/2andlearnable?/2own the learn-safety rules hosts used to re-implement: routes served from the cache itself, rules withoutlearn: true, and routes staging policy-protected actions are skipped with an explaining reason.Spectre.Router.SemanticCache.update_example/4edits an online learned example in place (:textre-embeds through the configured adapter,:labelmust stay cacheable,:verifiedtoggles review state), replacing the snapshot round-trip hosts used for edits. Custom cache adapters may implement the new optionalupdate_example/4callback.Spectre.Journal.Record.to_json_map/1renders a journal record as a JSON-safe, string-keyed map (atoms→strings, tuples→lists, calendar types→ ISO-8601, fallbackinspect/2) for direct persistence by store adapters.Spectre.ensure_instance/4starts or reuses an Instance and always returns{:ok, pid}or{:error, reason}, normalizing the supervisor's richer start shapes.Spectre.Instance.trace_id/1exposes the per-generation trace identifier without reaching intoinfo/1.Spectre.Turn.Dispatcherdrives a%Spectre.Turn{}decision to a delivered outcome so hosts stop hand-writing the decision switch: it delivers replies, auto-resolves policies the host can already satisfy (satisfied_resolution/2), executes pending effects, and falls back tofallback_reply/2/no_response/2for empty outcomes.deliver_reply/3is the only required callback and the loop is bounded.before_action :action, run: {M, :f}registers a pre-execution guard on the action lifecycle. Guards run after routing, planning, and policy approval, and can return{:suppress, reply_text}to cancel the pending effect and answer with a normal reply (emitting:effect_suppressed), or{:error, reason}to fail closed.:allmatches every action; Skills cannot declare guards; invalid guard replies fail the effect instead of allowing it.history limit, summary: {M, :f}folds chat-history entries evicted from the window into a rolling summary understate.data.chat_summaryinstead of dropping them. The default LLM classifier prompt shows the summary as "Conversation summary (older turns)" next to the recent chat, and custom classifier prompts receive it as thechat_summaryassign. A crashing summarizer keeps the previous summary and never blocks the turn.flowdeclarations now nest. A nested flow is a taxonomy grouping: rules keep the full path in the newSpectre.Rule.flow_pathfield whileflowstays the innermost name, labels stay globally unique, andinjectdeclarations plus flow options are inherited by nested flows.state.current_flownow prioritizes by membership inflow_path, so setting a parent flow prioritizes its whole subtree. String flows passed toSpectre.Router.evaluate/3resolve nested flow names as well.The default LLM fallback classifier prompt groups visible labels by flow taxonomy (indented, one
flow/header per group) instead of a flat list. Each label carries up to two example phrases from itsembedding:/bag:/jaro:declarations (classifier ..., label_examples: ntunes the cap,0disables). The prompt now also states the routed agent module, an optional agent description (classifier ..., context: "..."), and the activestate.current_flowrendered as its full nested path. Custom classifier prompt functions receive the newlabel_tree,agent,agent_context, andactive_flowassigns, and the tree rendering is exposed asSpectre.Router.LLMClassifier.label_tree/3. Agents with no flows keep the flat label list.Added
SYSTEM.md, documenting the 0.2.0 package compatibility matrix, composition patterns, complete Stack examples, library responsibilities, and the architectural rationale for a small core with explicit satellites.Directive Definitions can declare
can_start: [:work]and return stablestart_loopsintents fromapply_result/4; the parent Result, child Work, controls, correlations, and events commit atomically at one canonical revision. Re-proposing an intent whose Work already exists with the same parent and intent provenance is a committed no-op reported asalready_started: true; only an id collision with different provenance rejects the transition.Definition security can opt into exact external-trigger fencing with
trigger_correlation: :requiredor the compatiblerequire_trigger_correlation: truespelling. Public loop views now exposewait_ref, and committed trigger events distinguish:exactfrom compatible:legacycorrelation.Publication policy now controls progress and blocker projection independently with
publish_progressandpublish_blocker.
Fixed
- A terminal outcome (failure, crash, completion, budget, expiry) that races a
pending safe pause/update command now rejects that command with
:loop_terminalinside the same committed transition, instead of leaving the loop permanently wedged behind an uncommittable control plane. - Checkpoints taken between a committed Result and the advancement of a
pending safe pause/update command are accepted on restart; recovery resumes
the control sequence instead of stopping the Instance with
:operational_recovery_failed. - A retry allowed by policy but denied by an exhausted budget or a passed
expiry now produces the typed
:budget_exhausted/:expiredoutcome with limit and consumption, instead of a generic:failedoutcome. - Duplicate control commands re-arm the Instance idle timer like every other control reply.
Changed
- Accepted uncorrelated 0.2.x triggers emit
[:spectre, :instance, :uncorrelated_operation_trigger]telemetry so hosts can migrate before correlation becomes strict by default in 0.3.0. The telemetry now also covers legacy triggers delivered through durable:triggercontrol commands, not only direct trigger calls. - Documented the fixed replay and retention windows: 512 canonical journal transitions, 1,024 applied change ids, 128 completed control commands per loop, and 512 committed operational events.
- Cognitive operations must declare a closed
domainor anoutputvalidator; a spec with neither is rejected as{:unbounded_cognitive_operation, id}. - Documented the
reason,actandworkFlow verbs and the deprecation path of the legacyaskverb in the DSL and migration guides.
Safety
- Work starts attempted directly by any operational Runner, including through the isolated executor call boundary, are rejected; only Agent-side Directive reducer intents can create Work from an operational transition.
Added
- Added versioned
Spectre.WorkandSpectre.VigilDefinitions on one shared operational runtime, plus support for authorized external controllers. - Added a closed operation catalog for registered functions, Actions, Effects, planners, and finite-domain cognitive operations.
- Added temporary one-attempt Runners under dynamic supervision, with Agent ownership, epoch and fencing validation, progress throttling, timeout, retry, crash recovery, and side-effect reconciliation.
- Added durable pause, update, update-and-resume, resume, renew, stop, and trigger commands with revision, provenance, and idempotency checks.
- Added typed budgets and terminal outcomes for completion, cancellation, expiry, failure, budget exhaustion, and ambiguous external outcomes.
- Added read-only loop views, deterministic selectors, visibility checks, committed operational events, local subscriptions, and optional routing of selected events through normal Flow handling.
- Added selective post-commit operation memory and artifact publication policies.
- Added consent, revocation, destination policy, deduplication, rate limits, quiet hours, digest decisions, and durable delivery receipts without moving transport I/O into core.
- Added typed canonical sections for Flow, Work, Vigil, external controllers, loop control, correlations, and committed events.
- Added authorized read/write snapshots, section-fenced change sets, monotonic commits, deterministic stale-conflict rejection, idempotent change identifiers, and a bounded transition journal.
- Added a strict portable checkpoint codec that preserves canonical and per-section revisions, correlations, transition history, and applied-change receipts across restart.
- Added a compare-and-swap checkpoint store boundary, asynchronous coalesced persistence, flush/status APIs, and explicit reconciliation after an ambiguous write outcome.
- Added an executable full-system Agent fixture covering Flow-started Work, conversational inspection and update, Vigil registration and control, operational-event routing, failure isolation, and joint checkpoint recovery.
Changed
Spectre.Instanceis now the sole local owner of both conversational and operational canonical state for oneAgentRef + Subject.- Explicit operation idempotency keys now survive Action and Effect dispatcher boundaries.
- Generic map input without a
textfield is retained as raw structured input with empty text instead of raising throughString.Chars. - Agent Definitions can register application operations and opt selected committed operation events back into the normal Flow router.
- Agent Definition validation now accepts every public route handler supported
by the DSL and Runner, including
reason/2,act/2, andwork/2.
Safety
- Canonical restore validates loop/control correspondence, Definition compatibility, event revisions, Subject ownership, correlations, consent, delivery receipts, and portable values before the Instance starts.
- Stale, duplicate, foreign-epoch, wrong-fence, wrong-generation, and semantically invalid Runner messages are rejected before commit.
- Unknown non-idempotent side-effect outcomes are never retried automatically.
- Runtime values never create atoms from untrusted strings; closed decoders use
existing atoms only. Ordinary atom serialization continues to use
Atom.to_string/1.
Compatibility
Spectre.State,Spectre.Run, Flow, Effect, Invocation, Session, and Turn keep their 0.1.6 roles. Work is a separate operational domain and does not rename Run.- State v5 and Run v1 recovery fixtures remain permanent compatibility tests.
- See
docs/MIGRATING_TO_0_2.mdfor canonical checkpoint adapters and incremental operational adoption.
0.1.6 — 2026-07-31
Changed
- Established a recoverable consolidation baseline with an explicit normative public API manifest and uniform release documentation.
- Added no runtime functionality and made no intentional breaking API change.
0.1.5 — 2026-07-30
Added
- Per-Run lifecycle ownership inside
Spectre.Instance: staged Effects and policy Awaitables now carry their owningrun_id, allowing several retained Runs to wait independently on policy or execution boundaries. - Conversation-aware policy resumption selects the matching Run from channel origin metadata. The legacy no-origin shortcut remains available when exactly one policy boundary is open; ambiguous input fails closed.
- State schema v5 persists Run ownership and supports bounded collections of independent pending Effects and Awaitables. Schema v2-v4 snapshots remain readable and legacy unowned lifecycle is claimed by its first Instance Run.
Spectre.Context.lifecycle_run_id/1andSpectre.Effect.bind_run/2give extension-owned Effect builders the same per-Run lifecycle contract used by core Actions.
Compatibility
- Stateless calls and conversation-scoped
Spectre.Sessionkeep their single-lifecycle behavior; Run ownership is enabled only bySpectre.Instance. - Capability execution remains serialized by the Instance state lock. Calls arriving during an Invocation stay queued and continue from the latest committed State after the capability returns.
- Prism and ordinary provider callbacks remain synchronous inside one bounded Move worker. Generic provider Invocations still require a later serializable mid-turn continuation.
Fixed
- A policy or Effect boundary owned by one Run no longer rejects unrelated
Runs with
:instance_lifecycle_locked. - Resuming a retained Run rebases it onto the latest shared Instance State without losing other Runs' pending lifecycle or rolling persistence revisions backward.
- Policy acceptance, rejection, retry exhaustion, and Effect execution now mutate only the explicitly owned lifecycle entries.
0.1.4 — 2026-07-30
Added
- Subject-scoped
Spectre.Instanceprocesses keyed by the portableSpectre.AgentRef + Spectre.Subjectpair, with race-safe lookup and get-or-start through the application Registry. - An Instance-owned multi-Run scheduler with a deduplicated FIFO ready queue,
one mailbox-scheduled Move at a time, retained Run projections, bounded
terminal tombstones, and first-boundary
Spectre.Turnreplies. - A stable opaque
AgentRef + Subjectstate scope plus privacy-safe tracking of multiple channel conversation origins within the same Instance. - Correlated in-flight Effect/Action Invocation workers and internal
Spectre.Invocation.Receiptfencing across Instance generation, Run revision, Invocation id, and dispatch id. Foreign, stale, duplicate, and late receipts cannot mutate Instance state. Spectre.ExternalIdentity,Spectre.LinkIntent,Spectre.SubjectLink, andSpectre.Subject.Registryfor explicit Agent-scoped identity resolution, bounded one-time challenges, optional source confirmation, conflict rejection, revocation, and privacy-safe Journal commits.- Public
Spectre.instance/4,lookup_instance/3, andresume/4APIs.Spectre.summon/1,3select the Instance runtime when an explicit:subjectis supplied.
Compatibility
- Conversation-scoped
Spectre.Sessionremains available unchanged when:subjectis omitted. - Ordinary user input resumes the exact policy-owning Run. Effect execution remains an explicit Invocation boundary.
- The single active Effect constraint remains on global
Spectre.Statein this release. Instance serializes that lifecycle boundary; moving it onto each Run is the next lifecycle phase. - Prism and ordinary provider calls remain synchronous inside one bounded Move worker. The Instance mailbox stays responsive, but ready Runs wait for that Move or its provider timeout; generic provider Invocations require a later serializable mid-turn continuation.
Fixed
- Run start, normalization, and initial scheduling no longer block the Instance GenServer or observe stale committed State.
- Duplicate and failed Run starts cannot overwrite retained Runs or exhaust bounded capacity; terminal history and tombstones remain bounded.
- Internal reply completion cannot roll shared Instance State back after another Run commits.
- Queued callers are released if another Run opens the global lifecycle lock, and abnormal workers fail only their fenced Run.
- Portable-value validation rejects improper lists without crashing the Subject Registry.
0.1.3 — 2026-07-29
Added
- A serializable
%Spectre.Run{}continuation and the closedRuntime.start/3 -> advance/2 -> resume/3protocol. - Revision-fenced
Spectre.Run.Ref,Spectre.Run.Boundary, andSpectre.Invocationvalues, plus transport-safeSpectre.Run.Requestpolicy projections. - Versioned, atom-free Run checkpoint/restore with raw-envelope stripping, typed logical Route projection, lifecycle validation, encoded-size limits, and fail-closed rejection of PID, Port, reference, and function values in authoritative data.
- A public
Spectre.Turnprojection withref,boundary, andobservablefields using the closed reply/awaiting/needs vocabulary; transport idempotency can useSpectre.Run.Ref.token/1. - Privacy-safe Run lifecycle journal events, selectable with
events: [:run]. - An ordered, optional
Spectre.Turn.Handlerboundary for external conversational runtimes. Open Spectre policies retain precedence; typed replies cannot replace state, routes, effects, or awaitables; failures and timeouts fail closed. - Integration guidance that defines
Spectre.turn/3as the canonical local host contract while keeping input decoding, Skills, memory, actions, pre-route ownership, telemetry/journaling, durable workflows, and agent-protocol transport on separate extension surfaces.
Fixed
- Semantic-cache collection cleanup now follows Vettore 0.3.2's dedicated supervised ETS ownership model.
- Accepted exact semantic-cache hits now skip later vector search, and built-in semantic search loads persisted row embeddings instead of issuing one remote embedding request per cached row. Classifier training and cache snapshots persist the vectors needed for request-time lookup, and online learning reuses the query vector instead of embedding the same input twice.
- Semantic-cache index processes now terminate with their cache owner, so an owner restart cannot leave orphaned Vettore collections behind.
- Invoked state callbacks that crash, exit, throw, are killed, time out, or return malformed results are now treated as ambiguous writes. Sessions retain the candidate state until durable reconciliation instead of silently moving back to the previous revision.
- Strict persistence-journal failures now carry the already committed result, and Sessions retain it so an audit outage after compare-and-set cannot cause state rollback or duplicate work on the old revision.
- The application supervisor now tolerates a bounded burst across cache and
journal children instead of stopping the whole
:spectreapplication while those independent workers are being restarted.
0.1.2 — 2026-07-28
Added
Spectre.Stackwith package-local install DSL, immutable compiled definitions, dependency ordering, compatibility/conflict validation, and deterministic manifest digests.- Versioned
Spectre.Stack.InstallableandSpectre.Stack.Contract.V1contracts for ecosystem packages. - Logical, version-fenced
Spectre.Stack.Refvalues and caller-owned runtime supervision for explicitly declared resources. - Logical
stack:references on Agent definitions, resolved only when the Stack is used, with compile-time rejection of Skill-owned infrastructure. - Explicit legacy adapters for
Spectre.Extension.MountandSpectre.Action.Provider.Mount.
Security and behavior guarantees
- Package manifests and compiled configuration reject PID, port, reference, and function values.
- Installed Actions are not automatically exposed to the Agent planner or authorized for execution.
- Stack runtimes have no default global name, and stale resource Refs cannot resolve against another definition.
0.1.0 — 2026-07-20
First public preview.
Added
- OTP-native Agent and Skill DSL with flows, interrupts, input pipelines, prompt injection, actions, policies, mounted skills, state, memory, journal, classifier, embedding, and session configuration.
- Evidence-based routing through regex, bag distance, Jaro distance, embeddings, local classifiers, exact and vector semantic cache, LLM classification, and deterministic arbitration.
- A canonical lifecycle kernel for staging, approving, rejecting, cancelling, expiring, completing, failing, and replaying effects and awaitables.
- Explicit two-boundary action execution: policy approval changes state;
Spectre.Executioninvokes the host capability only after the approved state can be committed. - Optimistic state revisions, versioned state codecs, stale-session protection, idempotent terminal replay, and explicit ambiguous-persistence results.
- Pure policy matching shared by user input and trusted host resolutions.
- Structured prompt plans that preserve instruction, context-data, and task trust through capable model adapters, with a marked legacy string format.
- Built-in learned semantic cache backed by Vettore, including online review, verification, relabel, deletion, snapshot, restore, bounded index ownership, and optional local FastEmbed integration.
- Versioned, privacy-safe journal records for arbitration, policies, lifecycle, execution, and persistence, with redaction, sampling, retention metadata, synchronous or buffered delivery, and configurable failure policy.
- Privacy-safe provider boundaries with timeouts, worker cancellation, normalized failures, fallback models, telemetry, and route-evaluation receipts.
- Routing evaluation APIs and Mix tasks for datasets, classifier training, model download, and CI evaluation reports.
- Ten-agent strategy matrix covering 800 routing scenarios, including 600 malformed, unmatched, invalid-flow, invalid-pipeline, and corrupted-state cases. The full suite contains 1,177 passing tests and exceeds 90% line coverage.
Security and behavior guarantees
- Policy acceptance cannot be supplied by an ordinary classifier route while a policy awaitable is open.
- A
:waiting_policyeffect is never executable. - Dynamic prompt providers may write only trusted-as-data context fragments.
- Prompt and state deserialization reject unknown or unsafe runtime values.
- Journal, telemetry, evaluation receipts, and provider failures omit raw prompts, model output, effect arguments, and stack traces by default.
Compatibility
- Requires Elixir
~> 1.19. - Vettore is a required dependency.
- ExFastembed and SpectreKinetic integrations are optional and detected or configured by the host application.