Skip to content

Releases: patrick204nqh/textus

v0.55.2

Choose a tag to compare

@github-actions github-actions released this 30 Jun 00:11

Release v0.55.2

v0.55.1

Choose a tag to compare

@github-actions github-actions released this 22 Jun 12:15
ff1bee8

Fixed

  • publish_tree prune spec — converge_now now purges "done" jobs before reseeding. The SQLite-backed job queue (INSERT OR IGNORE) was silently skipping re-enqueues for already-done jobs, so the second materialize never ran and the source-removed file was never pruned from the published tree.

v0.54.2

Choose a tag to compare

@github-actions github-actions released this 18 Jun 23:33
ac53298

Added

  • Content-hash dedup in Action::Ingest: re-ingesting the same URL or file bytes silently creates a supersede chain — new entry with full content, old stripped to tombstone with a superseded_by pointer.
  • Ports::RawIndex: lightweight YAML-based O(1) index for raw lane content-hash/URL lookups, stored at .textus/.state/indexes/raw.yaml.
  • content_hash field: every new raw entry stores a sha256: content hash for fast dedup lookups.
  • Asset file move on re-ingest: asset files are moved (not copied) to the new date path on supersede.

Changed

  • .run → .state rename: the runtime artifact directory is renamed from .textus/.run/ to .textus/.state/. The state/ subdirectory becomes cursors/. Layout path methods follow automatically. Manual migration step: mv .textus/.run .textus/.state.

v0.54.1

Choose a tag to compare

@github-actions github-actions released this 17 Jun 00:55
960c1c5

Added

  • Textus::Types module: shared dry-types constrained types (RoleName, Cursor, FormatName) used across all dry-struct structs.

Changed

  • MCP surface → official mcp SDK (PR #223): the hand-rolled JSON-RPC 2.0 stdio loop is replaced by the official mcp gem (~> 0.20). Protocol version auto-negotiates up to 2025-11-25 (was hardcoded 2024-11-05). Catalog.build_tools generates MCP::Tool instances from verb contracts; Server manages session lifecycle and delegates dispatch. routing.rb, the MCP::Session alias, and ToolSchemas are deleted.
  • Session, Envelope, Container → Dry::Struct (PR #223): Data.define replaced with Dry::Struct for typed, loudly-failing construction at object creation time. Session enforces RoleName and non-negative Cursor; Envelope enforces known FormatName; Container has typed port references.
  • Manifest validator → dry-schema + Semantics (PR #223): the 318-line programmatic validator is split into contract.rb (dry-schema structural contract) and semantics.rb (cross-field rules, walk-based unknown-key detection, ADR migration hints). Public interface Validator.validate! unchanged.
  • Mustache → ERB (PR #223): mustache gem removed; all 8 .mustache templates converted to .erb using ERB#result_with_hash. Produce::Render now uses ERB.new(template, trim_mode: "-").result_with_hash(ctx).

Removed

  • mustache runtime dependency (replaced by Ruby stdlib ERB).
  • MCP::Routing module, MCP::Session alias, MCP::ToolSchemas module — superseded by the SDK.

textus 0.54.0 — Workflow system, raw ingest pipeline, MCP resources

Choose a tag to compare

@patrick204nqh patrick204nqh released this 16 Jun 15:40
2611aa8

Added

  • Workflow system (PR #218): Ruby DSL files in .textus/workflows/ replace the step/ extension model. Workflow::Registry (loaded from .textus/workflows/**/*.rb) is resolved by Produce::Engine at produce time; Workflow::Runner threads data through each named step and persists. Core components: Workflow::Context, Workflow::Pattern (glob matching), Workflow::DSL, Workflow::Collector, Workflow::Registry, Workflow::Loader, Workflow::Runner.
  • artifacts.index produced workflow: pre-computed full-store catalog (artifacts.index) served as a produced artifact — enumerates every manifest entry with its key, lane, format, etag, and generated_at timestamp.
  • MCP resources/list and resources/read (PR #221): machine-lane produced entries are now exposed as MCP resources at textus://<key> URIs with correct MIME types. Clients discover them via the resources capability advertised in the initialize handshake.
  • Raw ingest pipeline (PR #219, ADR 0114, ADR 0116): new raw zone-kind with a write-once gate and an ingest capability/verb (Action::Ingest). Doctor checks and an asset sentinel guard the lane. The raw bijection entry maps raw → ingest.

Changed

  • artifacts.derived.* → artifacts.*: the derived key segment is dropped — all machine-lane entries flatten to artifacts.<name> in both the manifest and the on-disk store. Workflows, boot, and all other callers updated.
  • boot reads from artifacts.index: inline computation removed from the boot action; the pre-computed catalog drives the response. --lean flag removed (PR #220).
  • pulse slimmed: stale, doctor, and next_due_at removed from the pulse envelope; index_etag added so clients can cheaply detect catalog drift without a full list.
  • ContractDrift moved to core (PR #220): Textus::ContractDrift extracted from the MCP surface into the core library so it is reusable across surfaces.
  • MCP Server refactored per Sandi Metz rules (PR #220): routing extracted to Routing module; methods decomposed to ≤ 5 lines each.
  • Plugin manifest wiring (PR #220): claude_plugin uses the installed textus binary (external use); mcp_config keeps bundle exec (dev environment). --lean references removed from the plugin manifest spec.
  • Namespace renames (PR #218, internal): entry/ → format/, envelope/io/ → envelope/, Ports::Queue → Ports::JobStore, background/ → jobs/, pipeline/ → produce/.
  • Workflows reorganised: workflow files split into artifacts/ and config/ subdirectories under .textus/workflows/.

Removed

  • Step system (PR #218): entire lib/textus/step/ directory deleted along with all step-related specs, container.steps, dead hooks.rb doctor check, and ports/audit_subscriber.rb. Migration: rewrite step files as .textus/workflows/*.rb using the Workflow DSL.
  • Jobs::Refresh (ADR 0115): workflow-based periodic re-derivation replaces the background refresh job.
  • handler_permit manifest field (PR #218): doctor-only field with no runtime enforcement deleted along with its policy class and schema key.
  • Dead guards and constants: derived_write? no-op guard from WriteVerb#cascade_to_rdeps; publish_each runtime guard from Entry::Publish; duplicate inline check_action! from put/key_delete/reject; BURN = :sync constant; cross-lane notebook side-effect from Action::Ingest.
  • source.from: fetch and source.from: derive narrowed to external only — fetch/derive methods removed from Produced; freshness/pulse use retention rules; boot drops intake/derived keys.

Fixed

  • MCP resources capability missing from initialize handshake (PR #221): the server only advertised tools, so MCP clients never called resources/list. Adding "resources" => {} makes all 9 produced artifacts discoverable as resources.
  • adr_log workflow: include_keyless: true added for tree-publish of knowledge.decisions.
  • SpecLayout violations (PR #221): workflow_index_spec and workflow/errors_spec (string-described) moved to spec/conformance/workflow/.

v0.53.0

Choose a tag to compare

@github-actions github-actions released this 14 Jun 18:10

Added

  • bin/dev: local script for syncing skills from GitHub during development.

Changed

  • Gate dispatch consolidated (PR #215): removed redundant container: param from Gate#dispatch (always @container); removed dead Textus::Dispatch module; removed double auth call in Accept; removed dead else branch and role_filter from RoleScope verb dispatch.
  • Background::Planner::Planner renamed to Planner::Plan to resolve the double-name antipattern.
  • Writer#put decomposed (38→12 lines): extracted into 8 single-purpose sub-methods (resolve, uid, serialize, schema-validate, etag-check, persist, envelope, audit).
  • Gate::Auth#check! / check_action! deduplicated: shared predicate-evaluation logic extracted into evaluate_predicates.
  • Init.run split (30→10 lines): 8 focused class methods (check_target!, create_directories, write_steps_readme, write_manifest, scaffold_agent, setup_state_dirs, write_gitignore, build_result).
  • auth/writer/reader helpers pulled into WriteVerb: removed 4-file duplication from Put, KeyMv, KeyDelete, Reject.
  • Action::Base#args auto-generated from initialize params: ~115 lines of boilerplate removed across 25 action classes.
  • AuditLog#verify_integrity: per-line checking extracted into check_line_integrity + iterate_with_prev_seq.
  • Error#initialize: 5-param constructor replaced with ErrorInfo parameter object (backward-compatible).
  • EventBus#invoke: replaced Thread.new/kill with Timeout.timeout.
  • Hand-rolled Mustache replaced with mustache gem: 117 lines of template engine deleted.
  • RuboCop formatting applied across the codebase.

Changed (breaking)

  • The proposal payload key frontmatter → _meta (ADR 0113). A proposal entry's proposed metadata moved from the top-level frontmatter: key to _meta:, so a proposal now carries the exact { _meta, body } envelope shape accept replays — retiring the only place the on-disk word "frontmatter" appeared as a runtime data key. accept reads env.meta["_meta"] and the schema_valid special case shrinks to a dig-with-fallback. No shim (house style): a proposal authored with the old key accepts with empty metadata and fails schema validation loudly. Migration: re-author any in-flight proposal with _meta: instead of frontmatter: — proposals are transient queue entries, not durable canon.

v0.52.0

Choose a tag to compare

@github-actions github-actions released this 09 Jun 01:48
0dbb1b0

The "who may write what" tables stop being hand-copied across the canon docs and become a fourth generated reference doc, projected from the source of truth on every drain.

Added

  • docs/reference/authority.md is a produced reference doc (ADR 0112). A new authority registry handler projects the artifacts.derived.authority entry — the zone-kind↔capability bijection (from Schema::Vocabulary::LANES), this manifest's zones, and its roles with the zone-kinds each can write — rendered through authority.mustache. It joins verbs.md / schema.md / adr-log.md on the ADR 0097/0102 produced-docs pattern; GeneratorDrift + HandlerAllowlist guard it (no new doctor check).

Changed

  • The authority model's SSoT splits along the produce/guard seam (ADR 0112, refining ADR 0098). The current-values tables move to the generated authority.md; reference/zones.md drops its three hand-maintained tables, keeps what each capability means as prose, and links to the generated values. explanation/concepts.md and the docs index re-point accordingly; the orientation template now names four generated reference docs.

v0.51.0

Choose a tag to compare

@github-actions github-actions released this 08 Jun 05:18
39e4dc2

build folds into reconcile, materialization becomes system-pushed, the producer kinds and machine zones collapse onto one source + retention grammar, and the machine-derivable reference docs graduate to produced artifacts.

Changed (breaking)

  • build is removed; tend is now reconcile (ADR 0087). One verb runs the full two-phase produce → destructive-sweep under a shared lock, and every canon write reactively rebuilds its dependent produced entries (source.on_write: sync | async). Migration: drop all build calls (CLI + MCP); rename scripted/cron tend to reconcile — the verb, the MCP tool id, and the audit-log verb string.
  • Capabilities collapse to four — author, keep, propose, reconcile (ADR 0090). The fetch and build capabilities fold into reconcile; automation defaults to [reconcile]. Migration: a role with can: [fetch] / can: [build] (or the interim ingest) becomes can: [reconcile]; the old spellings are rejected at load with a hint.
  • One machine zone-kind and one produced entry-kind (ADR 0091, 0095). Zone-kinds become canon | workspace | machine | queue — the former quarantine + derived zone-kinds fold into one machine kind (the kind ⟺ capability mapping is a bijection again; at most one machine zone). Entry-kinds become leaf | nested | produced — the former derived + intake entry-kinds fold into one produced kind, with the produce-method (intake / derived / external) read off source.from. Migration: kind: quarantine / kind: derived on a zone → kind: machine; kind: derived / kind: intake on an entry → kind: produced. Both are rejected at load with a fold hint; no shim.
  • source: + retention: replace upkeep / lifecycle / materialize / intake / compute / template (ADR 0093). The old slots conflated production (how an entry's bytes are made) with retention (when an aged entry is retired). They split into an entry-level source: { from: project | handler | command } — one "acquire data from upstream" concept, where from must agree with kind: — and a glob-matched retention: { ttl, action: drop | archive } rule; both run through one produce engine. This is strictly more expressive (re-pull hourly and archive at 90 days is now sayable). The lifecycle: { on_expire: warn } form is removed (warn was dead since 0.50's pure-read get). Migration: rewrite upkeep: / lifecycle: / materialize: (and the old intake: / compute: / template: blocks) into source: + retention:. Old manifests fail at load with mechanical fold hints; no shim.
  • A source produces data; publish: is a list of targets (ADR 0094). A produced entry's stored form is data (e.g. .json); rendering moves entirely to the publish path. publish: is now a list — each element a { to:, template?:, inject_boot?: } file target (copies the data verbatim, or renders it through that target's own template) or a { tree: } subtree mirror — so one dataset can render to differently-shaped targets (CLAUDE.md vs AGENTS.md) without bespoke handler code. Published artifacts are clean content; textus's _meta provenance stays in the stored entry. Migration: the map publish: { to: [...] } / publish: { tree: } forms (and the older publish_to: / publish_tree:) are rejected at load — publish: is a list.
  • Hook events renamed (ADR 0094). RPC :resolve_intake → :resolve_handler; pub-sub :entry_put → :entry_written, :build_completed → :entry_produced (plus :entry_published and produce_failed). Migration: update hook subscriptions to the new names; old names fail at registration.

Added

  • Reference docs are produced, not hand-authored (ADR 0097, 0098). docs/reference/verbs.md and docs/reference/schema.md (projected from the live verb/schema registry) and the new docs/reference/adr-log.md (projected from the ADR files) are kind: produced entries published out, with a CI gate that fails when reconcile is not a no-op. Do not hand-edit them — edit the upstream source (the verb/schema code, or an ADR) and run reconcile; doctor flags a stale hand-edit as generator_drift.
  • The root README.md, CONTRIBUTING.md, and SECURITY.md are canon, published out (ADR 0103, 0104). They are authored under .textus/zones/knowledge/ and published verbatim to the repo root with an editor banner (the same pattern as docs/); a hand-edit to a front-door doc is clobbered by reconcile and caught by the CI no-op gate.

Changed

  • Docs SSoT/DRY cleanup (ADR 0098). The duplicated ADR index is single-sourced — the mechanical status board lives in docs/reference/adr-log.md, and the curated decisions README becomes an annotated reading guide; the verb producer depends on Read::Capabilities rather than reaching into Dispatcher internals; a conformance guard keeps the events / zones / mcp projections covered.

Internal

  • The architecture is now executable, and the produce / schema / port layers are decomposed (ADR 0092, 0099–0101, 0105–0109). The hexagonal layering is enforced by a conformance guard with the layer map written to lib/textus/ARCHITECTURE.md (0106); the verb token gains a build-time route ⟺ contract bijection guard (0105); the divergent staleness comparisons collapse into one Domain::Freshness::Evaluator (0099); the produce pipeline is gathered under lib/textus/produce/ with an acquire ÷ render split and the fetch_* fossils renamed (0100); two interface fossils are removed (0101); manifest/schema.rb splits its validation walk into Schema::Validator and its constants into Schema::Vocabulary + Schema::Keys (0107, 0109); every port becomes one shape — an instantiable class (0108, 0109); and the conformance spec tier is consolidated (67→19 loose) and coupled to the contract rather than to fixture spelling (0092). No behaviour, manifest-grammar, or verb-surface change.

v0.50.0

Choose a tag to compare

@github-actions github-actions released this 05 Jun 01:41
13448e8

freshness collapses into pulse, the contract-drift guard stops deadlocking, and boot gains a lean session-start projection shipped via a plugin.

Added

  • boot --lean (ADR 0084) — a compact orientation projection (protocol, store_root, zones, agent_quickstart, contract_etag) for cheap session-start injection. The full boot envelope now also carries contract_etag. --lean is a contract arg, so it threads to every surface (CLI flag, MCP lean tool arg, Ruby kwarg).
  • textus ships as a Claude Code plugin (ADR 0084) — a single self-contained .claude-plugin/plugin.json with an inline SessionStart hook (startup/clear/compact) that runs boot --lean, so enabling the plugin auto-orients each session. The agent-invokable boot tool is unchanged; the hook is additive. Plugin data is kept inside .claude-plugin/ (a separate concern from the gem), not a top-level hooks/ dir.
  • Agent-integration config is textus-managed, projected from canon (ADR 0086). This repo's .mcp.json and .claude-plugin/plugin.json are now build artifacts — textus build projects them from knowledge.project + Textus::VERSION (so the plugin version can never drift off the gem) the same way it projects CLAUDE.md. The plugin manifest also gains an inline mcpServers stanza (enable the plugin → MCP server and orientation hook in one). A new provenance: false derived-entry flag lets the JSON renderer emit config without a _meta block. Downstream consumers are unaffected — init --with-agent still scaffolds a write-once .mcp.json (a build must never clobber a user's config).

Changed

  • The contract-drift guard applies to mutating verbs only; boot self-heals (ADR 0083). A mid-session manifest/hook/schema edit no longer deadlocks every MCP verb behind "re-run boot": pure reads and boot bypass the guard, boot re-arms the session's cached contract_etag, and only mutating verbs (the Write:: family + the destructive Maintenance:: verbs tend/zone_mv/key_mv_prefix/key_delete_prefix) enforce it. "Re-run boot" now actually recovers instead of looping. Refines ADR 0074.
  • tend returns a health summary, not full issues[] (ADR 0085) — matching pulse; doctor stays the sole owner of detailed health output.

Removed (breaking)

  • The public freshness verb (ADR 0085). Observability is now two verbs on orthogonal axes — pulse (transient/temporal: changed + stale + next_due_at) and doctor (structural correctness). The lifecycle scan that backed freshness becomes a Ruby-only internal (empty surfaces, ADR 0073) consumed by pulse and the hook context; per-entry detail is reconstructable from get (carries stale/last_fetched_at) + rule_explain (the lifecycle: ttl + on_expire). Migration: replace textus freshness with textus pulse (for the stale list / next_due_at) or get + rule_explain (for one entry's verdict). SPEC's generator-drift attribution is corrected to doctor's generator_drift check.

v0.49.0

Choose a tag to compare

@github-actions github-actions released this 04 Jun 14:04
65218ba

The single-key mutation verbs gain the key_ family stem, and the migrate orchestrator is removed.

Changed (breaking)

  • mv → key_mv and delete → key_delete, renamed everywhere the token is load-bearing: the verb / MCP-tool id, the guard transition symbol, the manifest guard: transition key, and the audit-log verb string. The single-key verbs now share the key_ stem with their bulk cousins key_mv_prefix/key_delete_prefix; zone_mv is unchanged. The CLI is unchanged — key mv, key delete, key mv-prefix, key delete-prefix keep their spelling. Migration: manifests with guard: { mv: … } / guard: { delete: … } blocks must rename those keys to key_mv / key_delete; MCP clients pinned to the mv/delete tool ids must update; audit rows written before this release keep their mv/delete verb strings (readers must accept both).

Removed (breaking)

  • The migrate verb (YAML-plan orchestrator). It was non-transactional and added a second input format for no capability the primitives lack — its zone_mv/key_mv_prefix/key_delete_prefix ops remain individually callable, each with --dry-run. Removed from the CLI and the MCP catalog.