Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
Removed
Phronomy::Guardrail::Builtinmodule removed:PromptInjectionDetectorandPIIPatternDetectorare opt-in pattern-matching helpers that encode application-level policy decisions (which phrases to block, which PII categories to detect, which languages to support). Shipping them as gem defaults was misleading — their correct home is inside each application that needs them. Reference implementations are now provided in example 06 ofphronomy-examples. ExtendPhronomy::Guardrail::InputGuardraildirectly to create equivalent guardrails in your application.
[0.5.4] - 2026-05-20
New Features
VectorStore embedding dimension validation (#98): All three vector store implementations (
InMemory,RedisSearch,Pgvector) now validate that every embedding passed toaddandsearchmatches the expected dimension. Dimension is inferred automatically from the firstaddcall; alternatively it can be set explicitly viainitialize(dimension: N). A mismatch raisesArgumentErrorwith a descriptive message. Thesearchmethod never establishes the dimension — it only validates when a dimension is already known.clearretains the established dimension (schema property).dispatch_parallel/fan_outconcurrency controls (#99): Two new keyword arguments are now accepted by both methods.max_concurrency: nil(default) or a positiveInteger— caps the number of worker threads.nilmeans one thread per task (previous behaviour).on_error: :raise(default) or:skip— controls failure handling.:raiseruns all tasks to completion then re-raises the first error in input order (fail-last, not fail-fast).:skipfills failed slots withniland never raises. The underlying implementation uses aQueue-based bounded worker pool (bounded_map) for predictable resource usage.
[0.5.3] - 2026-05-20
Bug Fixes
- Ensure
from_servercloses transport on error (#95): The short-lived transport created insideMcpTool.from_serveris now wrapped inbegin/ensure, so the underlying child process (stdio) is always terminated even whenfetch_toolraises. - Correct
McpTool#closedocumentation (#94): The comment previously stated that callingexecuteaftercloseraises an error; in practice the transport reopens automatically. The comment now reflects actual behaviour.
Documentation
- Fix CHANGELOG date for v0.5.1 (#96): The v0.5.1 entry had an incorrect date of 2026-05-21; corrected to 2026-05-20.
[0.5.2] - 2026-05-20
Bug Fixes
- CHANGELOG correction for v0.5.1 MCP fix (#90): The v0.5.1 entry
incorrectly stated that a
Mutexwas added toStdioTransport#rpc_call. The actual fix was per-instance transport ownership (eachMcpToolinstance creates its own transport ininitialize). Corrected the description.
Enhancements
- Add
McpTool#close(#92): Tool instances now expose aclosemethod that shuts down the underlying stdio child process (StdioTransport) or releases the HTTP connection (HttpTransport). This gives callers a deterministic way to clean up resources instead of relying on GC.
Maintenance
Archive stale Rails integration design doc (#91): Added an archived notice to
spec/design/17_rails_integration.mdclarifying that Rails integration was removed in v0.3.0–v0.5.1 and the document is for historical reference only.Remove zombie
register_workflow_contextAPI (#93): ThePhronomy.register_workflow_context,workflow_context_registry, andreset_workflow_context_registry!methods (along with the backing@workflow_context_registryand@registry_mutexmodule-level variables) were removed fromlib/phronomy.rb. These existed to support theStateStoredeserialization guard, which was removed in a prior release. The API had no remaining callers in the codebase and was not listed in the README stability table.
[0.5.1] - 2026-05-20
Bug Fixes
Remove broken Rails generator and Railtie (#85): The generator template referenced
Phronomy::ActiveRecord::ActsAswhich no longer exists, causingrails generate phronomy:installto produce broken model files. Removedlib/generators/,lib/phronomy/railtie.rb, and all references inlib/phronomy.rb.Fix MCP transport ownership (#86):
McpToolno longer stores a shared transport at class level.from_servernow uses a short-lived transport only to fetch tool metadata and callscloseimmediately after. Each tool instance creates its ownStdioTransportorHttpTransportininitialize, so concurrent callers (e.g. viaOrchestrator#dispatch_parallel) never share stdio streams. NoMutexis needed. Also adds missingrequire "securerandom"and a no-opHttpTransport#closefor interface consistency.
Documentation
- README corrections (#87): Remove stale Rails generator installation
instructions. Clarify that
TeamCoordinatorworker state is local to a singleinvokecall (not persistent across calls). Annotate app-level examples (09_rails_chat,15_rails_secure_chat,18_rails_agent_job,19_trust_pipeline) as requiring external infrastructure. Add scope note toAgent::Orchestratorsection.
Maintenance
- Add version guard to
ruby_llm_patches.rb(#88): The monkey-patch for the upstreamhandle_error_chunkbug (ruby_llm <= 1.15.0) is now gated behind aGem::Versioncheck so upgrading ruby_llm will automatically disable the override.
[0.5.0] - 2026-05-20
Breaking Changes
Agent::Base#invokeand#stream—messagesandthread_idpromoted to top-level keyword arguments: Previously these values were passed inside theconfig:hash. They are now explicit keyword arguments. Theconfig:hash retains other runtime options such as:knowledge_sources,:user_id, and:session_id.
Before (v0.4.x):
agent.invoke(input, config: { messages: prior_msgs, thread_id: "t1" })
agent.stream(input, config: { messages: prior_msgs, thread_id: "t1" }) { |e| ... }
After (v0.5.0):
agent.invoke(input, messages: prior_msgs, thread_id: "t1")
agent.stream(input, messages: prior_msgs, thread_id: "t1") { |e| ... }
Applications that only pass :knowledge_sources, :user_id, or :session_id
in config: require no changes.
Agent::Checkpoint#initialize—original_input:is now a required keyword argument: Applications that constructCheckpointinstances directly must addoriginal_input: input. Checkpoints produced by#invokealready include this field automatically.
Fixed
ReactAgent#step— system instructions were never applied: The first iteration of the ReAct loop now callsbuild_contextto assemble the system prompt and history, matching the behaviour ofAgent::Base. Subsequent iterations re-apply instructions viabuild_cached_system_textbefore callingchat.complete. Previously, all iterations silently omitted the system prompt.Agent::Base#resume— system instructions were not re-applied after suspension: Resuming from aCheckpointnow callsbuild_cached_system_textusing the original input stored in the checkpoint, so the LLM receives the correct system prompt when the conversation continues. Previously, the LLM was called without any system instructions on resume.
[0.4.0] - 2026-05-19
Removed
Phronomy::TrustPipelineremoved: TheTrustPipelineclass and its innerTrustResultvalue object have been deleted. UsePhronomy::GeneratorVerifierinstead, which provides the same generator-verifier pattern with a cleaner, fully injectable API.
Added
Phronomy::GeneratorVerifier— Generator-Verifier coordination loop (Anthropic blog, Pattern 1). Wraps a generator agent and a verifier agent with fully injectable prompt builders, response parsers, a configurable iteration limit, and an approval-outcome raise policy.Phronomy::Agent::Orchestrator— Base class for orchestrator agents (Anthropic blog, Pattern 2). ExtendsAgent::Basewith asubagentDSL for declarative subagent registration as LLM-callable tools, plusdispatch_parallelandfan_outfor programmatic parallel invocation.Phronomy::Agent::TeamCoordinator— Agent teams coordination pattern (Anthropic blog, Pattern 3). An LLM-powered coordinator with a shared task queue and a pool of worker agents that carry conversation history across task assignments. Addscoordinator_providerDSL for independent LLM routing.Phronomy::Agent::SharedState— Shared-state coordination pattern (Anthropic blog, Pattern 5). Peer agents collaborate via aKnowledgeStore; thememberDSL registers agents with per-agent instructions;coordinationsets the team protocol;build_promptinjects a tool-usage guide automatically.Phronomy::LowConfidenceError— Exception raised byGeneratorVerifierwhenraise_policy: :raiseand verification fails after exhausting the iteration limit.
Changed
Phronomy::Graph::StateGraphevent system refactored: Per-nodeadvanceevents replaced with a unifiednode_completedevent queue, reducing event-handler registration overhead and simplifying listener registration.
[0.3.0] - 2026-05-18
Removed
Phronomy::Memorymodule fully removed:ConversationManager, allStoragebackends (InMemory, ActiveRecord), allRetrievalstrategies (Recent, Semantic, Composite), and allCompressionhelpers (ToolOutputPruner, Summary) have been deleted. Conversation history is now the responsibility of the calling application — pass prior messages viaconfig[:messages](Array<RubyLLM::Message>) and receive the updated array inresult[:messages].Phronomy::StateStoremodule fully removed:InMemory,ActiveRecord,Redis, andFileSystemstate-store backends have been deleted. The Workflow halted-state object is now returned directly frominvokeandsend_eventand must be stored by the caller if resumption is needed.Phronomy::Configuration#default_state_storeremoved: No longer meaningful without a built-in state store.Phronomy::Configuration#default_memory/#memory_async/#memory_job_queueremoved: No longer meaningful without the Memory module.- Rails integration removed:
Railtieinitializers forAgentJobandacts_as_phronomy_messageno longer load. Therails/andactive_record/directories have been deleted. Phronomy::ActorandPhronomy::ThreadActorRegistrydeleted: The Active Object pattern implementation (actor.rb,thread_actor_registry.rb) has been removed. It provided synchronous blocking only (no true async) and was architecturally inconsistent with theWorkflowRunnerhalt/resume model. All thread coordination now uses plainMutexwhere needed.Phronomy.configuration.max_actorsremoved: The configuration option is no longer meaningful withoutThreadActorRegistry.
Changed
Agent::Base#invokeand#streamno longer route execution through a per-thread Actor. Both methods now call_invoke_impl/_stream_impldirectly on the calling thread.Memory::Storage::InMemorynow stores all thread data in an instance-levelHashinstead ofThread.currentthread-local storage. The class-levelTHREAD_DATA_KEYconstant has been removed.with_thread_lockuses a per-thread-idMutexto preserve concurrent-compaction safety (issue #44).StateStore::InMemorynow stores state in an instance-levelHash. TheTHREAD_DATA_KEYconstant has been removed.VectorStore::RedisSearchuses aMutexforensure_index!andclearinstead of an Actor, preserving the thread-safety invariant on@index_created.Tool::McpTool::StdioTransport,Tracing::LangfuseTracer,TrustPipeline, andMemory::Retrieval::Semanticno longer hold a dedicated Actor instance. All operations execute directly on the calling thread.PIIPatternDetector—:my_numberreplaced by:ssn([#77]): The built-in PII detector now checks for US Social Security Numbers (\b\d{3}-\d{2}-\d{4}\b) instead of Japanese My Numbers. The JIS X 0076 check-digit validation andmy_number_valid?helper have been removed. Category key renamed from:my_numberto:ssn.PIIPatternDetector— phone pattern updated to international format ([#77]): The:phonepattern now matches 3-digit area code + 3–4-digit exchange + 4-digit subscriber number with optional E.164 country-code prefix ((?:\+\d{1,3}[.\- ]?)?\(?\d{3}\)?[.\- ]?\d{3,4}[.\- ]?\d{4}\b), replacing the previous Japan-specific pattern.
Fixed
RubyLLM::Providers::OpenAI#handle_error_chunk—NoMethodErroron single-line SSE error chunks: Some models (e.g. Qwen running via LM Studio) return SSE error events as a single line (data: {...}) without a precedingevent:line. The upstream implementation calledchunk.split("\n")[1].delete_prefix(...), which raisedNoMethodError: undefined method 'delete_prefix' for nilwhen the second element was absent. A monkey-patch inlib/phronomy/ruby_llm_patches.rbguards against this by returning an empty string when the split result has fewer than two elements.README— stale Memory API examples ([#76]): All references to the non-existentWindowMemory,ActiveRecordMemory,SemanticMemoryclasses andload_messages/memory_compressionAPI have been replaced with the correctConversationManager-based API.README—PIIPatternDetectorcomment ([#77]): Inline comment updated to# Detect SSNs, credit cards, emails, and phone numbers.README— Configuration block markdown ([#80]): Themax_actorsNote block was incorrectly placed inside the Ruby code fence; moved outside so it renders as a blockquote.README—Guardrailsstability label ([#76]): Changed fromStabletoBetato reflect that the built-in detector patterns may evolve.CHANGELOG— stale entries ([#78]): Removed the orphaned[Unreleased]section describing a never-released API, and replaced a forward"As of 0.3.0"reference with future-tense wording.McpTool— YARD class comment ([#79]): Updated to document both thestdio://andhttp:///https://transport schemes.README—max_actorsconfiguration reference ([#80]): Addedc.max_actorsexample and LRU eviction note to the Configuration section.
[0.2.2] - 2026-05-17
Fixed
Tool::Basetype validation — strict mode (#73): Removed string-coercion pass-through for:integer,:number/:float, and:booleanparameters. AStringvalue such as"42"now correctly raises a type error regardless of theon_schema_errormode. Fixes silent data corruption where the raw string was forwarded toexecuteinstead of the expected numeric/boolean type.README— correctsend_eventAPI example (#69): Fixed code sample that calledapp.send_event(:approve, config: { thread_id: ... })(positional args) which raisesArgumentErrorat runtime. Corrected toapp.send_event(state: state, event: :approve).phronomy.gemspec— excludevendor/from gem package (#70):vendor/bundle(~3 500 files, ~14 MB) was included in released gems. Added"vendor/"to the file reject list.
Added
Phronomy::Configuration#max_actors(#72): New optional attribute (defaultnil= unlimited, backward-compatible). When set,ThreadActorRegistryenforces an LRU eviction policy: the least-recently-used actor is stopped and removed before a new one is created, preventing unbounded thread growth in long-running processes.README— feature stability table (#71): Features section now uses a table with Stable / Beta / Experimental labels so users can assess maturity at a glance.TrustPipeline::Result#citations— unverified-source warning (#74): YARD documentation now explicitly states that citations are extracted from the LLM's own output and have not been verified against any external source.
CI
- Ruby 3.4 added to CI matrix (#75): Aligns test coverage with the gemspec
requirement (
>= 3.2.0) and verifies compatibility with the current stable Ruby release.
[0.2.1] — Unreleased
Changed
WorkflowRunner— state_machines fully drives execution (architecture overhaul). Previouslystate_machineswas used only for post-hoc transition validation; the next-node was calculated by Phronomy internally (resolve_next_node). After this change, all state transition decisions — including guard evaluation for routing events — will be delegated entirely tostate_machines.PhaseTrackernow exposesattr_accessor :contextso guard lambdas can access theWorkflowContextviam.context.- Guard bridge pattern:
if: ->(m) { guard_proc.call(m.context) }. - Three event types registered per workflow:
advance_<from>— unconditional after-transitions<routing_event>— guarded branching from action states (name is the event name used in the DSL, e.g.:route,:route_review)<external_event>— human-in-the-loop triggers from wait states- Invalid transitions now raise
ArgumentErrorinstead of logging warnings.
WorkflowRunnerinitializer signature changed —edges:,conditional_edges:, andwait_states:replaced byafter_transitions:,route_transitions:,external_events:, andwait_state_names:. This is an internal-only change; the publicPhronomy::Workflow.defineDSL is unchanged.
Removed (internal)
WorkflowRunner#resolve_next_node— logic moved to state_machinesWorkflowRunner#advance_phase— replaced byfire_event!Workflow::Builder#build_edges,#build_conditional_edges,#build_wait_states— replaced by unified event classification inbuild
[0.2.0] - 2026-05-13
Added
Phronomy::Graph::WorkflowRunner— state_machines-based execution engine (introduced as the internal successor toCompiledGraph).state.phase— single source of truth for graph execution state (replacescurrent_nodes+halted_beforedual attributes).state.halted?— returnstruewhen the graph is paused.CompiledGraph#add_wait_state— declared a named wait state that halts automatically when reached (later superseded bywait_stateDSL inWorkflow.define).CompiledGraph#send_event(state:, event:, input: nil)— event-driven resume API (later superseded byapp.send_event).
Removed
ParallelNodeandadd_parallel_nodeDSL. UseThread.neworConcurrent::Futureat the application level instead.Phronomy::Graph::TimeoutError(was only used byParallelNode).