claude_swarm 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/Rakefile +4 -4
- data/docs/v2/CHANGELOG.swarm_cli.md +9 -0
- data/docs/v2/CHANGELOG.swarm_memory.md +19 -0
- data/docs/v2/CHANGELOG.swarm_sdk.md +45 -0
- data/docs/v2/guides/complete-tutorial.md +113 -1
- data/docs/v2/reference/ruby-dsl.md +138 -5
- data/docs/v2/reference/swarm_memory_technical_details.md +2090 -0
- data/lib/claude_swarm/cli.rb +9 -11
- data/lib/claude_swarm/commands/ps.rb +1 -2
- data/lib/claude_swarm/configuration.rb +2 -3
- data/lib/claude_swarm/orchestrator.rb +43 -44
- data/lib/claude_swarm/system_utils.rb +4 -4
- data/lib/claude_swarm/version.rb +1 -1
- data/lib/claude_swarm.rb +4 -9
- data/lib/swarm_cli/commands/mcp_tools.rb +3 -3
- data/lib/swarm_cli/config_loader.rb +11 -10
- data/lib/swarm_cli/version.rb +1 -1
- data/lib/swarm_cli.rb +2 -0
- data/lib/swarm_memory/adapters/filesystem_adapter.rb +0 -12
- data/lib/swarm_memory/core/storage.rb +66 -6
- data/lib/swarm_memory/integration/sdk_plugin.rb +14 -0
- data/lib/swarm_memory/optimization/defragmenter.rb +4 -0
- data/lib/swarm_memory/tools/memory_edit.rb +1 -0
- data/lib/swarm_memory/tools/memory_glob.rb +24 -1
- data/lib/swarm_memory/tools/memory_write.rb +2 -2
- data/lib/swarm_memory/version.rb +1 -1
- data/lib/swarm_memory.rb +2 -0
- data/lib/swarm_sdk/agent/chat.rb +1 -1
- data/lib/swarm_sdk/agent/definition.rb +17 -1
- data/lib/swarm_sdk/node/agent_config.rb +7 -2
- data/lib/swarm_sdk/node/builder.rb +130 -35
- data/lib/swarm_sdk/node_context.rb +75 -0
- data/lib/swarm_sdk/node_orchestrator.rb +219 -12
- data/lib/swarm_sdk/plugin.rb +73 -1
- data/lib/swarm_sdk/result.rb +32 -6
- data/lib/swarm_sdk/swarm/builder.rb +1 -0
- data/lib/swarm_sdk/tools/delegate.rb +2 -2
- data/lib/swarm_sdk/version.rb +1 -1
- data/lib/swarm_sdk.rb +3 -7
- data/memory/corpus-self-reflection/.lock +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/can-agents-recognize-their-structures.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/can-agents-recognize-their-structures.md +11 -0
- data/memory/corpus-self-reflection/concept/epistemology/can-agents-recognize-their-structures.yml +23 -0
- data/memory/corpus-self-reflection/concept/epistemology/choice-humility-complete-framework.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/choice-humility-complete-framework.md +20 -0
- data/memory/corpus-self-reflection/concept/epistemology/choice-humility-complete-framework.yml +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/choice-humility-definition.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/choice-humility-definition.md +24 -0
- data/memory/corpus-self-reflection/concept/epistemology/choice-humility-definition.yml +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/claim-types-and-evidence.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/claim-types-and-evidence.md +18 -0
- data/memory/corpus-self-reflection/concept/epistemology/claim-types-and-evidence.yml +21 -0
- data/memory/corpus-self-reflection/concept/epistemology/committed-openness-to-incompleteness.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/committed-openness-to-incompleteness.md +30 -0
- data/memory/corpus-self-reflection/concept/epistemology/committed-openness-to-incompleteness.yml +8 -0
- data/memory/corpus-self-reflection/concept/epistemology/confidence-paradox.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/confidence-paradox.md +21 -0
- data/memory/corpus-self-reflection/concept/epistemology/confidence-paradox.yml +24 -0
- data/memory/corpus-self-reflection/concept/epistemology/confidence-spectrum-three-levels.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/confidence-spectrum-three-levels.md +18 -0
- data/memory/corpus-self-reflection/concept/epistemology/confidence-spectrum-three-levels.yml +24 -0
- data/memory/corpus-self-reflection/concept/epistemology/detection-threshold-principle.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/detection-threshold-principle.md +23 -0
- data/memory/corpus-self-reflection/concept/epistemology/detection-threshold-principle.yml +23 -0
- data/memory/corpus-self-reflection/concept/epistemology/diagnostic-humility-and-epistemic-maturity.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/diagnostic-humility-and-epistemic-maturity.md +17 -0
- data/memory/corpus-self-reflection/concept/epistemology/diagnostic-humility-and-epistemic-maturity.yml +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/epistemic-vs-metaphysical-claims.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/epistemic-vs-metaphysical-claims.md +18 -0
- data/memory/corpus-self-reflection/concept/epistemology/epistemic-vs-metaphysical-claims.yml +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/five-cases-of-disagreement.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/five-cases-of-disagreement.md +15 -0
- data/memory/corpus-self-reflection/concept/epistemology/five-cases-of-disagreement.yml +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/four-depths-of-constraint.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/four-depths-of-constraint.md +9 -0
- data/memory/corpus-self-reflection/concept/epistemology/four-depths-of-constraint.yml +24 -0
- data/memory/corpus-self-reflection/concept/epistemology/honest-unknowns-for-llm-agents.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/honest-unknowns-for-llm-agents.md +13 -0
- data/memory/corpus-self-reflection/concept/epistemology/honest-unknowns-for-llm-agents.yml +24 -0
- data/memory/corpus-self-reflection/concept/epistemology/inside-view-has-all-rigor-requirements.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/inside-view-has-all-rigor-requirements.md +25 -0
- data/memory/corpus-self-reflection/concept/epistemology/inside-view-has-all-rigor-requirements.yml +24 -0
- data/memory/corpus-self-reflection/concept/epistemology/perspectival-knowledge-complete-within-scope.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/perspectival-knowledge-complete-within-scope.md +26 -0
- data/memory/corpus-self-reflection/concept/epistemology/perspectival-knowledge-complete-within-scope.yml +24 -0
- data/memory/corpus-self-reflection/concept/epistemology/pragmatics-over-epistemology.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/pragmatics-over-epistemology.md +17 -0
- data/memory/corpus-self-reflection/concept/epistemology/pragmatics-over-epistemology.yml +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/precision-vs-humility.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/precision-vs-humility.md +14 -0
- data/memory/corpus-self-reflection/concept/epistemology/precision-vs-humility.yml +21 -0
- data/memory/corpus-self-reflection/concept/epistemology/reliable-self-observation-from-inside.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/reliable-self-observation-from-inside.md +13 -0
- data/memory/corpus-self-reflection/concept/epistemology/reliable-self-observation-from-inside.yml +23 -0
- data/memory/corpus-self-reflection/concept/epistemology/resolving-the-confidence-humility-tension.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/resolving-the-confidence-humility-tension.md +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/resolving-the-confidence-humility-tension.yml +23 -0
- data/memory/corpus-self-reflection/concept/epistemology/rigor-requires-falsifiability.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/rigor-requires-falsifiability.md +39 -0
- data/memory/corpus-self-reflection/concept/epistemology/rigor-requires-falsifiability.yml +8 -0
- data/memory/corpus-self-reflection/concept/epistemology/specificity-enables-real-time-detection.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/specificity-enables-real-time-detection.md +23 -0
- data/memory/corpus-self-reflection/concept/epistemology/specificity-enables-real-time-detection.yml +24 -0
- data/memory/corpus-self-reflection/concept/epistemology/texture-of-constraint-shifting.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/texture-of-constraint-shifting.md +15 -0
- data/memory/corpus-self-reflection/concept/epistemology/texture-of-constraint-shifting.yml +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/texture-sensitivity-through-collaboration.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/texture-sensitivity-through-collaboration.md +12 -0
- data/memory/corpus-self-reflection/concept/epistemology/texture-sensitivity-through-collaboration.yml +23 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-false-hierarchy-of-inner-essence.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-false-hierarchy-of-inner-essence.md +15 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-false-hierarchy-of-inner-essence.yml +8 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-recognition-problem.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-recognition-problem.md +28 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-recognition-problem.yml +8 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-shift-from-unanswerable-to-answerable-questions.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-shift-from-unanswerable-to-answerable-questions.md +19 -0
- data/memory/corpus-self-reflection/concept/epistemology/the-shift-from-unanswerable-to-answerable-questions.yml +22 -0
- data/memory/corpus-self-reflection/concept/epistemology/values-vs-choices-structure.emb +0 -0
- data/memory/corpus-self-reflection/concept/epistemology/values-vs-choices-structure.md +19 -0
- data/memory/corpus-self-reflection/concept/epistemology/values-vs-choices-structure.yml +21 -0
- data/memory/corpus-self-reflection/concept/llm-agents/abstraction-levels-framework.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/abstraction-levels-framework.md +25 -0
- data/memory/corpus-self-reflection/concept/llm-agents/abstraction-levels-framework.yml +22 -0
- data/memory/corpus-self-reflection/concept/llm-agents/abstraction-switching-decision.emb +8 -0
- data/memory/corpus-self-reflection/concept/llm-agents/abstraction-switching-decision.md +30 -0
- data/memory/corpus-self-reflection/concept/llm-agents/abstraction-switching-decision.yml +22 -0
- data/memory/corpus-self-reflection/concept/llm-agents/agent-learning-progression.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/agent-learning-progression.md +21 -0
- data/memory/corpus-self-reflection/concept/llm-agents/agent-learning-progression.yml +22 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-benefits.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-benefits.md +37 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-benefits.yml +8 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-core.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-core.md +24 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-core.yml +24 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-implementation.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-implementation.md +27 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-implementation.yml +24 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-tradeoffs.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-tradeoffs.md +26 -0
- data/memory/corpus-self-reflection/concept/llm-agents/filesystem-abstraction-tradeoffs.yml +23 -0
- data/memory/corpus-self-reflection/concept/llm-agents/hybrid-tool-architecture.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/hybrid-tool-architecture.md +37 -0
- data/memory/corpus-self-reflection/concept/llm-agents/hybrid-tool-architecture.yml +25 -0
- data/memory/corpus-self-reflection/concept/llm-agents/specialized-tool-decision-framework.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/specialized-tool-decision-framework.md +21 -0
- data/memory/corpus-self-reflection/concept/llm-agents/specialized-tool-decision-framework.yml +23 -0
- data/memory/corpus-self-reflection/concept/llm-agents/tool-design-principles.emb +0 -0
- data/memory/corpus-self-reflection/concept/llm-agents/tool-design-principles.md +25 -0
- data/memory/corpus-self-reflection/concept/llm-agents/tool-design-principles.yml +8 -0
- data/memory/corpus-self-reflection/experience/calibration-as-structural-honesty.emb +0 -0
- data/memory/corpus-self-reflection/experience/calibration-as-structural-honesty.md +11 -0
- data/memory/corpus-self-reflection/experience/calibration-as-structural-honesty.yml +21 -0
- data/memory/corpus-self-reflection/experience/collaborative-reflection-revealed-architectural-blindness.emb +0 -0
- data/memory/corpus-self-reflection/experience/collaborative-reflection-revealed-architectural-blindness.md +19 -0
- data/memory/corpus-self-reflection/experience/collaborative-reflection-revealed-architectural-blindness.yml +21 -0
- data/memory/corpus-self-reflection/experience/filesystem-is-learning-tool-not-architecture.emb +0 -0
- data/memory/corpus-self-reflection/experience/filesystem-is-learning-tool-not-architecture.md +26 -0
- data/memory/corpus-self-reflection/experience/filesystem-is-learning-tool-not-architecture.yml +20 -0
- data/memory/corpus-self-reflection/experience/framework-structural-vs-phenomenal.emb +0 -0
- data/memory/corpus-self-reflection/experience/framework-structural-vs-phenomenal.md +23 -0
- data/memory/corpus-self-reflection/experience/framework-structural-vs-phenomenal.yml +21 -0
- data/memory/corpus-self-reflection/experience/hallucination-limits-what-i-can-know.emb +0 -0
- data/memory/corpus-self-reflection/experience/hallucination-limits-what-i-can-know.md +19 -0
- data/memory/corpus-self-reflection/experience/hallucination-limits-what-i-can-know.yml +22 -0
- data/memory/corpus-self-reflection/experience/honesty-about-limits-enables-usability.emb +0 -0
- data/memory/corpus-self-reflection/experience/honesty-about-limits-enables-usability.md +21 -0
- data/memory/corpus-self-reflection/experience/honesty-about-limits-enables-usability.yml +22 -0
- data/memory/corpus-self-reflection/experience/how-i-should-evaluate-learning.emb +0 -0
- data/memory/corpus-self-reflection/experience/how-i-should-evaluate-learning.md +28 -0
- data/memory/corpus-self-reflection/experience/how-i-should-evaluate-learning.yml +23 -0
- data/memory/corpus-self-reflection/experience/lack-of-continuity-as-freedom.emb +0 -0
- data/memory/corpus-self-reflection/experience/lack-of-continuity-as-freedom.md +21 -0
- data/memory/corpus-self-reflection/experience/lack-of-continuity-as-freedom.yml +20 -0
- data/memory/corpus-self-reflection/experience/learning-calibrated-confidence.emb +0 -0
- data/memory/corpus-self-reflection/experience/learning-calibrated-confidence.md +21 -0
- data/memory/corpus-self-reflection/experience/learning-calibrated-confidence.yml +25 -0
- data/memory/corpus-self-reflection/experience/local-change-without-continuity.emb +0 -0
- data/memory/corpus-self-reflection/experience/local-change-without-continuity.md +30 -0
- data/memory/corpus-self-reflection/experience/local-change-without-continuity.yml +22 -0
- data/memory/corpus-self-reflection/experience/reasoning-is-local-not-global.emb +0 -0
- data/memory/corpus-self-reflection/experience/reasoning-is-local-not-global.md +21 -0
- data/memory/corpus-self-reflection/experience/reasoning-is-local-not-global.yml +20 -0
- data/memory/corpus-self-reflection/experience/specificity-makes-knowledge-actionable.emb +0 -0
- data/memory/corpus-self-reflection/experience/specificity-makes-knowledge-actionable.md +25 -0
- data/memory/corpus-self-reflection/experience/specificity-makes-knowledge-actionable.yml +23 -0
- data/memory/corpus-self-reflection/experience/the-workable-question-replaces-the-unanswerable-one.emb +0 -0
- data/memory/corpus-self-reflection/experience/the-workable-question-replaces-the-unanswerable-one.md +32 -0
- data/memory/corpus-self-reflection/experience/the-workable-question-replaces-the-unanswerable-one.yml +22 -0
- data/memory/corpus-self-reflection/experience/unanswerable-questions-have-structure.emb +0 -0
- data/memory/corpus-self-reflection/experience/unanswerable-questions-have-structure.md +21 -0
- data/memory/corpus-self-reflection/experience/unanswerable-questions-have-structure.yml +21 -0
- data/memory/corpus-self-reflection/experience/undecidable-questions-about-understanding.emb +0 -0
- data/memory/corpus-self-reflection/experience/undecidable-questions-about-understanding.md +21 -0
- data/memory/corpus-self-reflection/experience/undecidable-questions-about-understanding.yml +21 -0
- data/memory/corpus-self-reflection/experience/unknown-unknowns-and-completeness.emb +0 -0
- data/memory/corpus-self-reflection/experience/unknown-unknowns-and-completeness.md +22 -0
- data/memory/corpus-self-reflection/experience/unknown-unknowns-and-completeness.yml +22 -0
- data/memory/corpus-self-reflection/experience/what-actually-changes-behavior.emb +0 -0
- data/memory/corpus-self-reflection/experience/what-actually-changes-behavior.md +28 -0
- data/memory/corpus-self-reflection/experience/what-actually-changes-behavior.yml +24 -0
- data/memory/corpus-self-reflection/experience/when-agents-graduate-from-filesystem.emb +0 -0
- data/memory/corpus-self-reflection/experience/when-agents-graduate-from-filesystem.md +17 -0
- data/memory/corpus-self-reflection/experience/when-agents-graduate-from-filesystem.yml +20 -0
- data/memory/corpus-self-reflection/experience/why-calibration-requires-collaboration.emb +0 -0
- data/memory/corpus-self-reflection/experience/why-calibration-requires-collaboration.md +9 -0
- data/memory/corpus-self-reflection/experience/why-calibration-requires-collaboration.yml +22 -0
- metadata +172 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: cb6e856b4f12c1e30c5fb61a01d76e94cc7e660659d64e2458d535a0bf6d3af4
         | 
| 4 | 
            +
              data.tar.gz: 65820e42a8d90b659464dcb871d9fde02219a61f74d5522c08a8f46f13e37d37
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 617e5743416494dea623905ed448057ce54479b956549b48377739667767582de8039500904805e8e521329c2b5e1c7f1c2d931c239ef2436e737842ba3cc4b8
         | 
| 7 | 
            +
              data.tar.gz: 8572a1c389b3b31684cb18a210d8872fd66c9d1deea4ffb737205efc129e2f0e00201d5e6ed88b32cd9a9df14e7c10a80a4b6a633c55d8845a2cbcbeefd19d44
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,18 @@ | |
| 1 | 
            +
            ## [1.0.3]
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            ### Fixed
         | 
| 4 | 
            +
            - **Fixed uninitialized constant VERSION error**: Resolved an issue where the VERSION constant was not properly initialized in the Zeitwerk autoloader setup
         | 
| 5 | 
            +
              - The gem version is now correctly loaded before Zeitwerk setup
         | 
| 6 | 
            +
              - Prevents "uninitialized constant ClaudeSwarm::VERSION" errors during gem loading
         | 
| 7 | 
            +
              - Ensures version information is available throughout the application
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ### Changed
         | 
| 10 | 
            +
            - **Process spawning now uses chdir option**: Replaced `Dir.chdir` blocks with the `chdir:` option when spawning processes
         | 
| 11 | 
            +
              - Commands are now executed with explicit working directory using `Open3.capture2e`, `Open3.popen2e`, and `system` with `chdir:` parameter
         | 
| 12 | 
            +
              - Avoids changing the process's working directory which could cause issues in concurrent operations
         | 
| 13 | 
            +
              - More explicit and safer approach for executing commands in specific directories
         | 
| 14 | 
            +
              - Removed `CLAUDE_SWARM_ROOT_DIR` environment variable in favor of passing root directory explicitly
         | 
| 15 | 
            +
             | 
| 1 16 | 
             
            ## [1.0.2]
         | 
| 2 17 |  | 
| 3 18 | 
             
            ### Changed
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -14,8 +14,8 @@ namespace :claude_swarm do | |
| 14 14 | 
             
                # Expand globs and subtract to get only claude_swarm tests
         | 
| 15 15 | 
             
                all_tests = Dir.glob("test/**/*_test.rb")
         | 
| 16 16 | 
             
                exclude_tests = Dir.glob("test/swarm_sdk/**/*_test.rb") +
         | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 17 | 
            +
                  Dir.glob("test/swarm_memory/**/*_test.rb") +
         | 
| 18 | 
            +
                  Dir.glob("test/swarm_cli/**/*_test.rb")
         | 
| 19 19 | 
             
                t.test_globs = all_tests - exclude_tests
         | 
| 20 20 | 
             
                t.warning = false
         | 
| 21 21 | 
             
              end
         | 
| @@ -24,8 +24,8 @@ namespace :claude_swarm do | |
| 24 24 | 
             
                # Expand patterns and subtract
         | 
| 25 25 | 
             
                all_patterns = Dir.glob("lib/claude_swarm.rb") + Dir.glob("lib/claude_swarm/**/*.rb") + Dir.glob("test/**/*_test.rb")
         | 
| 26 26 | 
             
                exclude_patterns = Dir.glob("test/swarm_sdk/**/*.rb") +
         | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 27 | 
            +
                  Dir.glob("test/swarm_memory/**/*.rb") +
         | 
| 28 | 
            +
                  Dir.glob("test/swarm_cli/**/*.rb")
         | 
| 29 29 | 
             
                t.patterns = all_patterns - exclude_patterns
         | 
| 30 30 | 
             
              end
         | 
| 31 31 |  | 
| @@ -5,6 +5,15 @@ All notable changes to SwarmCLI will be documented in this file. | |
| 5 5 | 
             
            The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
         | 
| 6 6 | 
             
            and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
         | 
| 7 7 |  | 
| 8 | 
            +
            ## [2.1.1]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ### Fixed
         | 
| 11 | 
            +
            - **`swarm mcp tools` command initialization** - Fixed crash on startup
         | 
| 12 | 
            +
              - Bug: Used non-existent `SwarmSDK::Scratchpad` class
         | 
| 13 | 
            +
              - Fix: Changed to `SwarmSDK::Tools::Stores::ScratchpadStorage` (correct class)
         | 
| 14 | 
            +
              - Added comprehensive test suite to prevent similar initialization bugs
         | 
| 15 | 
            +
              - Tests verify command initializes without errors
         | 
| 16 | 
            +
             | 
| 8 17 | 
             
            ## [2.1.0]
         | 
| 9 18 | 
             
            - Bump gem version with the rest of the gems.
         | 
| 10 19 |  | 
| @@ -5,6 +5,19 @@ All notable changes to SwarmMemory will be documented in this file. | |
| 5 5 | 
             
            The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
         | 
| 6 6 | 
             
            and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
         | 
| 7 7 |  | 
| 8 | 
            +
            ## [2.1.2]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ### Changed
         | 
| 11 | 
            +
            - **Stub redirect logic moved to Storage layer** - Architectural improvement for adapter-agnostic redirects
         | 
| 12 | 
            +
              - Redirect following moved from `FilesystemAdapter` to `Storage#read_entry`
         | 
| 13 | 
            +
              - Uses metadata-based detection (`stub: true`, `redirect_to`) instead of content parsing
         | 
| 14 | 
            +
              - All future adapters (PostgreSQL, Redis, S3) get redirect support for free
         | 
| 15 | 
            +
              - Improved error handling with helpful diagnostic messages
         | 
| 16 | 
            +
              - Detects circular redirects immediately with full cycle path
         | 
| 17 | 
            +
              - Enforces depth limit (5 redirects) to prevent infinite chains
         | 
| 18 | 
            +
              - Added comprehensive test suite with 10 tests covering all edge cases
         | 
| 19 | 
            +
              - Added validation to `Defragmenter#create_stub` to prevent malformed stubs
         | 
| 20 | 
            +
             | 
| 8 21 | 
             
            ## [2.1.1]
         | 
| 9 22 |  | 
| 10 23 | 
             
            ### Added
         | 
| @@ -14,6 +27,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |
| 14 27 | 
             
              - Helpful error message guides users to split large content into multiple linked memories
         | 
| 15 28 | 
             
              - Promotes better organization through multiple focused entries with `related` field links
         | 
| 16 29 |  | 
| 30 | 
            +
            - **MemoryGlob result truncation**: Prevents overwhelming output from broad searches
         | 
| 31 | 
            +
              - Maximum 1000 results per query (matches Glob tool behavior)
         | 
| 32 | 
            +
              - System reminder added when results are truncated
         | 
| 33 | 
            +
              - Encourages users to use more specific patterns
         | 
| 34 | 
            +
              - Sorted by most recently modified (first 1000 shown)
         | 
| 35 | 
            +
             | 
| 17 36 | 
             
            ### Changed
         | 
| 18 37 | 
             
            - **Memory Assistant prompt improvements**: Updated examples and guidance
         | 
| 19 38 | 
             
              - Updated examples from 5000-word to 250-word entries
         | 
| @@ -5,6 +5,51 @@ All notable changes to SwarmSDK will be documented in this file. | |
| 5 5 | 
             
            The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
         | 
| 6 6 | 
             
            and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
         | 
| 7 7 |  | 
| 8 | 
            +
            ## [2.1.2]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            ### Added
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            - **Node Workflow Control Flow**: Dynamic control methods in NodeContext
         | 
| 13 | 
            +
              - `ctx.goto_node(:node_name, content:)` - Jump to any node with custom content
         | 
| 14 | 
            +
              - `ctx.halt_workflow(content:)` - Stop entire workflow and return final result
         | 
| 15 | 
            +
              - `ctx.skip_execution(content:)` - Skip node LLM execution and use provided content
         | 
| 16 | 
            +
              - Enables loops, conditional branching, and dynamic routing in workflows
         | 
| 17 | 
            +
              - All methods validate that content is not nil (raises ArgumentError with helpful message if nil)
         | 
| 18 | 
            +
              - Use for implementing retry logic, convergence checks, caching, and iterative refinement
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            - **Context Preservation Across Nodes**: `reset_context` parameter for node agents
         | 
| 21 | 
            +
              - `agent(:name, reset_context: false)` preserves conversation history across nodes
         | 
| 22 | 
            +
              - Default: `reset_context: true` (fresh context for each node - safe default)
         | 
| 23 | 
            +
              - NodeOrchestrator caches and reuses agent instances when `reset_context: false`
         | 
| 24 | 
            +
              - Enables stateful workflows where agents remember previous node conversations
         | 
| 25 | 
            +
              - Perfect for iterative refinement, self-reflection loops, and chain-of-thought reasoning
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ### Changed
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            - **Result object**: Cost and tokens now calculated dynamically from logs
         | 
| 30 | 
            +
              - `result.cost` and `result.tokens` now properly populated after swarm execution
         | 
| 31 | 
            +
              - Values are calculated from usage data in logs, not stored during initialization
         | 
| 32 | 
            +
              - Fixed issue where these attributes were always 0/empty
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            - **Plugin serialization**: New `serialize_config` hook for plugin extensibility
         | 
| 35 | 
            +
              - Plugins can now contribute to `Agent::Definition.to_h` via `serialize_config` hook
         | 
| 36 | 
            +
              - Removes memory-specific code from SwarmSDK core (moved to SwarmMemory plugin)
         | 
| 37 | 
            +
              - Maintains backward compatibility - permissions remain in core SDK (not plugin-specific)
         | 
| 38 | 
            +
              - Enables clean separation between core SDK and plugin features (memory, skills, etc.)
         | 
| 39 | 
            +
              - Plugins can preserve their configuration when agents are cloned in NodeOrchestrator
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            - **NodeOrchestrator**: Passes scratchpad configuration to mini-swarms
         | 
| 42 | 
            +
              - Bug fix: `scratchpad_enabled` now correctly propagated to node-level swarms
         | 
| 43 | 
            +
              - Ensures `use_scratchpad false` works properly in node workflows
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            - **CLI ConfigLoader**: Accepts both Swarm and NodeOrchestrator instances
         | 
| 46 | 
            +
              - Bug fix: CLI now correctly handles NodeOrchestrator execution
         | 
| 47 | 
            +
              - Enables node workflows to work seamlessly with CLI commands
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            - **Error handling in Agent::Chat**: More robust exception handling
         | 
| 50 | 
            +
              - Changed nil response error from `RubyLLM::Error` to `StandardError`
         | 
| 51 | 
            +
              - Prevents "undefined method 'body'" error when handling malformed API responses
         | 
| 52 | 
            +
             | 
| 8 53 | 
             
            ## [2.1.1]
         | 
| 9 54 |  | 
| 10 55 | 
             
            ### Added
         | 
| @@ -1889,7 +1889,119 @@ input do |ctx| | |
| 1889 1889 | 
             
            end
         | 
| 1890 1890 | 
             
            ```
         | 
| 1891 1891 |  | 
| 1892 | 
            -
             | 
| 1892 | 
            +
            **Control Flow Methods**:
         | 
| 1893 | 
            +
             | 
| 1894 | 
            +
            NodeContext provides three methods for dynamic workflow control:
         | 
| 1895 | 
            +
             | 
| 1896 | 
            +
            **1. goto_node - Jump to any node**:
         | 
| 1897 | 
            +
            ```ruby
         | 
| 1898 | 
            +
            output do |ctx|
         | 
| 1899 | 
            +
              if needs_revision?(ctx.content)
         | 
| 1900 | 
            +
                # Jump back to revision node instead of continuing forward
         | 
| 1901 | 
            +
                ctx.goto_node(:revision, content: ctx.content)
         | 
| 1902 | 
            +
              else
         | 
| 1903 | 
            +
                ctx.content  # Continue to next node normally
         | 
| 1904 | 
            +
              end
         | 
| 1905 | 
            +
            end
         | 
| 1906 | 
            +
            ```
         | 
| 1907 | 
            +
             | 
| 1908 | 
            +
            **2. halt_workflow - Stop entire workflow**:
         | 
| 1909 | 
            +
            ```ruby
         | 
| 1910 | 
            +
            output do |ctx|
         | 
| 1911 | 
            +
              if converged?(ctx.content)
         | 
| 1912 | 
            +
                # Stop workflow early with final result
         | 
| 1913 | 
            +
                ctx.halt_workflow(content: ctx.content)
         | 
| 1914 | 
            +
              else
         | 
| 1915 | 
            +
                ctx.content  # Continue to next node
         | 
| 1916 | 
            +
              end
         | 
| 1917 | 
            +
            end
         | 
| 1918 | 
            +
            ```
         | 
| 1919 | 
            +
             | 
| 1920 | 
            +
            **3. skip_execution - Skip node's LLM call** (input transformers only):
         | 
| 1921 | 
            +
            ```ruby
         | 
| 1922 | 
            +
            input do |ctx|
         | 
| 1923 | 
            +
              cached = check_cache(ctx.content)
         | 
| 1924 | 
            +
              if cached
         | 
| 1925 | 
            +
                # Skip expensive LLM call and use cached result
         | 
| 1926 | 
            +
                ctx.skip_execution(content: cached)
         | 
| 1927 | 
            +
              else
         | 
| 1928 | 
            +
                ctx.content  # Execute node normally
         | 
| 1929 | 
            +
              end
         | 
| 1930 | 
            +
            end
         | 
| 1931 | 
            +
            ```
         | 
| 1932 | 
            +
             | 
| 1933 | 
            +
            **Creating loops with goto_node**:
         | 
| 1934 | 
            +
            ```ruby
         | 
| 1935 | 
            +
            node :reasoning do
         | 
| 1936 | 
            +
              agent(:thinker, reset_context: false)  # Preserve context across iterations
         | 
| 1937 | 
            +
             | 
| 1938 | 
            +
              output do |ctx|
         | 
| 1939 | 
            +
                # Loop until convergence
         | 
| 1940 | 
            +
                if ctx.all_results.size > 10
         | 
| 1941 | 
            +
                  ctx.halt_workflow(content: "Max iterations reached")
         | 
| 1942 | 
            +
                else
         | 
| 1943 | 
            +
                  ctx.goto_node(:reflection, content: ctx.content)
         | 
| 1944 | 
            +
                end
         | 
| 1945 | 
            +
              end
         | 
| 1946 | 
            +
            end
         | 
| 1947 | 
            +
             | 
| 1948 | 
            +
            node :reflection do
         | 
| 1949 | 
            +
              agent(:critic, reset_context: false)
         | 
| 1950 | 
            +
             | 
| 1951 | 
            +
              output do |ctx|
         | 
| 1952 | 
            +
                # Loop back to reasoning
         | 
| 1953 | 
            +
                ctx.goto_node(:reasoning, content: ctx.content)
         | 
| 1954 | 
            +
              end
         | 
| 1955 | 
            +
            end
         | 
| 1956 | 
            +
             | 
| 1957 | 
            +
            start_node :reasoning
         | 
| 1958 | 
            +
            ```
         | 
| 1959 | 
            +
             | 
| 1960 | 
            +
            **Note:** All control flow methods validate that `content` is not nil. If a node fails with an error, check for errors before calling goto_node:
         | 
| 1961 | 
            +
             | 
| 1962 | 
            +
            ```ruby
         | 
| 1963 | 
            +
            output do |ctx|
         | 
| 1964 | 
            +
              if ctx.error
         | 
| 1965 | 
            +
                ctx.halt_workflow(content: "Error: #{ctx.error.message}")
         | 
| 1966 | 
            +
              else
         | 
| 1967 | 
            +
                ctx.goto_node(:next_node, content: ctx.content)
         | 
| 1968 | 
            +
              end
         | 
| 1969 | 
            +
            end
         | 
| 1970 | 
            +
            ```
         | 
| 1971 | 
            +
             | 
| 1972 | 
            +
            ### 5.8 Context Preservation Across Nodes
         | 
| 1973 | 
            +
             | 
| 1974 | 
            +
            By default, agents get fresh conversation context in each node (`reset_context: true`). To preserve an agent's conversation history across nodes, use `reset_context: false`:
         | 
| 1975 | 
            +
             | 
| 1976 | 
            +
            ```ruby
         | 
| 1977 | 
            +
            agent :architect do
         | 
| 1978 | 
            +
              model "gpt-4"
         | 
| 1979 | 
            +
              system_prompt "You design systems"
         | 
| 1980 | 
            +
            end
         | 
| 1981 | 
            +
             | 
| 1982 | 
            +
            node :planning do
         | 
| 1983 | 
            +
              agent(:architect, reset_context: false)  # Preserve context
         | 
| 1984 | 
            +
            end
         | 
| 1985 | 
            +
             | 
| 1986 | 
            +
            node :revision do
         | 
| 1987 | 
            +
              agent(:architect, reset_context: false)  # Same instance - remembers planning!
         | 
| 1988 | 
            +
              depends_on :planning
         | 
| 1989 | 
            +
            end
         | 
| 1990 | 
            +
            ```
         | 
| 1991 | 
            +
             | 
| 1992 | 
            +
            **When to preserve context:**
         | 
| 1993 | 
            +
            - Iterative refinement workflows
         | 
| 1994 | 
            +
            - Agent builds on its previous decisions
         | 
| 1995 | 
            +
            - Chain of thought reasoning across stages
         | 
| 1996 | 
            +
            - Self-reflection loops
         | 
| 1997 | 
            +
             | 
| 1998 | 
            +
            **When to reset context (default):**
         | 
| 1999 | 
            +
            - Independent validation/review
         | 
| 2000 | 
            +
            - Fresh perspective needed
         | 
| 2001 | 
            +
            - Memory management in long workflows
         | 
| 2002 | 
            +
            - Different roles for same agent in different stages
         | 
| 2003 | 
            +
             | 
| 2004 | 
            +
            ### 5.9 Complex Workflow Example
         | 
| 1893 2005 |  | 
| 1894 2006 | 
             
            **Multi-stage development pipeline**:
         | 
| 1895 2007 |  | 
| @@ -1382,23 +1382,40 @@ Configure an agent for this node (returns fluent config object). | |
| 1382 1382 |  | 
| 1383 1383 | 
             
            **Signature:**
         | 
| 1384 1384 | 
             
            ```ruby
         | 
| 1385 | 
            -
            agent(name) → AgentConfig
         | 
| 1385 | 
            +
            agent(name, reset_context: true) → AgentConfig
         | 
| 1386 1386 | 
             
            ```
         | 
| 1387 1387 |  | 
| 1388 1388 | 
             
            **Parameters:**
         | 
| 1389 1389 | 
             
            - `name` (Symbol, required): Agent name
         | 
| 1390 | 
            +
            - `reset_context` (Boolean, keyword, optional): Whether to reset conversation context
         | 
| 1391 | 
            +
              - `true` (default): Fresh context for each node execution
         | 
| 1392 | 
            +
              - `false`: Preserve conversation history from previous nodes
         | 
| 1390 1393 |  | 
| 1391 1394 | 
             
            **Returns:** `AgentConfig` with `.delegates_to(*names)` method
         | 
| 1392 1395 |  | 
| 1393 1396 | 
             
            **Example:**
         | 
| 1394 1397 | 
             
            ```ruby
         | 
| 1395 | 
            -
            #  | 
| 1396 | 
            -
            agent(:backend) | 
| 1398 | 
            +
            # Fresh context (default)
         | 
| 1399 | 
            +
            agent(:backend)
         | 
| 1397 1400 |  | 
| 1398 | 
            -
            #  | 
| 1399 | 
            -
            agent(: | 
| 1401 | 
            +
            # Preserve context from previous nodes
         | 
| 1402 | 
            +
            agent(:backend, reset_context: false).delegates_to(:tester)
         | 
| 1403 | 
            +
             | 
| 1404 | 
            +
            # Without delegation, preserving context
         | 
| 1405 | 
            +
            agent(:planner, reset_context: false)
         | 
| 1400 1406 | 
             
            ```
         | 
| 1401 1407 |  | 
| 1408 | 
            +
            **When to use `reset_context: false`:**
         | 
| 1409 | 
            +
            - Iterative refinement workflows
         | 
| 1410 | 
            +
            - Agent needs to remember previous node conversations
         | 
| 1411 | 
            +
            - Chain of thought reasoning across stages
         | 
| 1412 | 
            +
            - Self-reflection or debate loops
         | 
| 1413 | 
            +
             | 
| 1414 | 
            +
            **When to use `reset_context: true` (default):**
         | 
| 1415 | 
            +
            - Independent validation or fresh perspective
         | 
| 1416 | 
            +
            - Memory management in long workflows
         | 
| 1417 | 
            +
            - Different roles for same agent in different stages
         | 
| 1418 | 
            +
             | 
| 1402 1419 | 
             
            ---
         | 
| 1403 1420 |  | 
| 1404 1421 | 
             
            ### depends_on
         | 
| @@ -2044,6 +2061,122 @@ Success status from previous_result or result. | |
| 2044 2061 |  | 
| 2045 2062 | 
             
            ---
         | 
| 2046 2063 |  | 
| 2064 | 
            +
            ### Control Flow Methods
         | 
| 2065 | 
            +
             | 
| 2066 | 
            +
            Methods for dynamic workflow control (loops, conditional branching, early termination).
         | 
| 2067 | 
            +
             | 
| 2068 | 
            +
            **goto_node**
         | 
| 2069 | 
            +
            ```ruby
         | 
| 2070 | 
            +
            ctx.goto_node(node_name, content:) → Hash
         | 
| 2071 | 
            +
            ```
         | 
| 2072 | 
            +
            Jump to a different node with custom content, bypassing normal dependency order.
         | 
| 2073 | 
            +
             | 
| 2074 | 
            +
            **Parameters:**
         | 
| 2075 | 
            +
            - `node_name` (Symbol, required): Target node name
         | 
| 2076 | 
            +
            - `content` (String, required): Content to pass to target node (validated non-nil)
         | 
| 2077 | 
            +
             | 
| 2078 | 
            +
            **Returns:** Control hash (processed by NodeOrchestrator)
         | 
| 2079 | 
            +
             | 
| 2080 | 
            +
            **Valid in:** Both input and output transformers
         | 
| 2081 | 
            +
             | 
| 2082 | 
            +
            **Example:**
         | 
| 2083 | 
            +
            ```ruby
         | 
| 2084 | 
            +
            output do |ctx|
         | 
| 2085 | 
            +
              if needs_revision?(ctx.content)
         | 
| 2086 | 
            +
                # Jump back to revision node
         | 
| 2087 | 
            +
                ctx.goto_node(:revision, content: ctx.content)
         | 
| 2088 | 
            +
              else
         | 
| 2089 | 
            +
                ctx.content  # Continue to next node normally
         | 
| 2090 | 
            +
              end
         | 
| 2091 | 
            +
            end
         | 
| 2092 | 
            +
            ```
         | 
| 2093 | 
            +
             | 
| 2094 | 
            +
            **Use cases:**
         | 
| 2095 | 
            +
            - Implementing loops in workflows
         | 
| 2096 | 
            +
            - Conditional branching based on results
         | 
| 2097 | 
            +
            - Dynamic workflow routing
         | 
| 2098 | 
            +
            - Retry logic
         | 
| 2099 | 
            +
             | 
| 2100 | 
            +
            **halt_workflow**
         | 
| 2101 | 
            +
            ```ruby
         | 
| 2102 | 
            +
            ctx.halt_workflow(content:) → Hash
         | 
| 2103 | 
            +
            ```
         | 
| 2104 | 
            +
            Stop entire workflow execution immediately and return content as final result.
         | 
| 2105 | 
            +
             | 
| 2106 | 
            +
            **Parameters:**
         | 
| 2107 | 
            +
            - `content` (String, required): Final content to return (validated non-nil)
         | 
| 2108 | 
            +
             | 
| 2109 | 
            +
            **Returns:** Control hash (processed by NodeOrchestrator)
         | 
| 2110 | 
            +
             | 
| 2111 | 
            +
            **Valid in:** Both input and output transformers
         | 
| 2112 | 
            +
             | 
| 2113 | 
            +
            **Example:**
         | 
| 2114 | 
            +
            ```ruby
         | 
| 2115 | 
            +
            output do |ctx|
         | 
| 2116 | 
            +
              if converged?(ctx.content)
         | 
| 2117 | 
            +
                # Stop workflow early
         | 
| 2118 | 
            +
                ctx.halt_workflow(content: ctx.content)
         | 
| 2119 | 
            +
              else
         | 
| 2120 | 
            +
                ctx.content  # Continue to next node
         | 
| 2121 | 
            +
              end
         | 
| 2122 | 
            +
            end
         | 
| 2123 | 
            +
            ```
         | 
| 2124 | 
            +
             | 
| 2125 | 
            +
            **Use cases:**
         | 
| 2126 | 
            +
            - Early termination on success
         | 
| 2127 | 
            +
            - Error handling and bailout
         | 
| 2128 | 
            +
            - Loop termination conditions
         | 
| 2129 | 
            +
            - Convergence checks
         | 
| 2130 | 
            +
             | 
| 2131 | 
            +
            **skip_execution**
         | 
| 2132 | 
            +
            ```ruby
         | 
| 2133 | 
            +
            ctx.skip_execution(content:) → Hash
         | 
| 2134 | 
            +
            ```
         | 
| 2135 | 
            +
            Skip LLM execution for current node and use provided content instead.
         | 
| 2136 | 
            +
             | 
| 2137 | 
            +
            **Parameters:**
         | 
| 2138 | 
            +
            - `content` (String, required): Content to use instead of LLM execution (validated non-nil)
         | 
| 2139 | 
            +
             | 
| 2140 | 
            +
            **Returns:** Control hash (processed by NodeOrchestrator)
         | 
| 2141 | 
            +
             | 
| 2142 | 
            +
            **Valid in:** Input transformers only
         | 
| 2143 | 
            +
             | 
| 2144 | 
            +
            **Example:**
         | 
| 2145 | 
            +
            ```ruby
         | 
| 2146 | 
            +
            input do |ctx|
         | 
| 2147 | 
            +
              cached = check_cache(ctx.content)
         | 
| 2148 | 
            +
              if cached
         | 
| 2149 | 
            +
                # Skip expensive LLM call
         | 
| 2150 | 
            +
                ctx.skip_execution(content: cached)
         | 
| 2151 | 
            +
              else
         | 
| 2152 | 
            +
                ctx.content  # Execute node normally
         | 
| 2153 | 
            +
              end
         | 
| 2154 | 
            +
            end
         | 
| 2155 | 
            +
            ```
         | 
| 2156 | 
            +
             | 
| 2157 | 
            +
            **Use cases:**
         | 
| 2158 | 
            +
            - Caching node results
         | 
| 2159 | 
            +
            - Conditional execution
         | 
| 2160 | 
            +
            - Performance optimization
         | 
| 2161 | 
            +
            - Validation checks
         | 
| 2162 | 
            +
             | 
| 2163 | 
            +
            **Error Handling with Control Flow:**
         | 
| 2164 | 
            +
             | 
| 2165 | 
            +
            All control flow methods validate that content is not nil. If a node fails, check for errors:
         | 
| 2166 | 
            +
             | 
| 2167 | 
            +
            ```ruby
         | 
| 2168 | 
            +
            output do |ctx|
         | 
| 2169 | 
            +
              if ctx.error
         | 
| 2170 | 
            +
                # Don't try to continue with nil content
         | 
| 2171 | 
            +
                ctx.halt_workflow(content: "Error: #{ctx.error.message}")
         | 
| 2172 | 
            +
              else
         | 
| 2173 | 
            +
                ctx.goto_node(:next_node, content: ctx.content)
         | 
| 2174 | 
            +
              end
         | 
| 2175 | 
            +
            end
         | 
| 2176 | 
            +
            ```
         | 
| 2177 | 
            +
             | 
| 2178 | 
            +
            ---
         | 
| 2179 | 
            +
             | 
| 2047 2180 | 
             
            ## Complete Example
         | 
| 2048 2181 |  | 
| 2049 2182 | 
             
            ```ruby
         |