htm 0.0.17 → 0.0.20

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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md +1 -1
  3. data/.architecture/decisions/adrs/011-database-side-embedding-generation-with-pgai.md +4 -4
  4. data/.architecture/decisions/adrs/012-llm-driven-ontology-topic-extraction.md +1 -1
  5. data/.envrc +12 -25
  6. data/.irbrc +7 -7
  7. data/.tbls.yml +2 -2
  8. data/CHANGELOG.md +130 -1
  9. data/README.md +13 -1
  10. data/Rakefile +8 -3
  11. data/SETUP.md +12 -12
  12. data/bin/htm_mcp +0 -4
  13. data/db/seed_data/README.md +2 -2
  14. data/db/seeds.rb +3 -3
  15. data/docs/api/database.md +37 -37
  16. data/docs/api/embedding-service.md +140 -110
  17. data/docs/api/htm.md +1 -1
  18. data/docs/api/yard/HTM/ActiveRecordConfig.md +8 -2
  19. data/docs/api/yard/HTM/Config.md +173 -0
  20. data/docs/api/yard/HTM/ConfigSection.md +28 -0
  21. data/docs/api/yard/HTM/Database.md +7 -8
  22. data/docs/api/yard/HTM/JobAdapter.md +1 -1
  23. data/docs/api/yard/HTM.md +0 -57
  24. data/docs/api/yard/index.csv +76 -61
  25. data/docs/api/yard-reference.md +2 -1
  26. data/docs/architecture/adrs/001-postgresql-timescaledb.md +1 -1
  27. data/docs/architecture/adrs/003-ollama-embeddings.md +45 -36
  28. data/docs/architecture/adrs/004-hive-mind.md +1 -1
  29. data/docs/architecture/adrs/008-robot-identification.md +1 -1
  30. data/docs/architecture/adrs/011-pgai-integration.md +4 -4
  31. data/docs/architecture/index.md +11 -9
  32. data/docs/architecture/overview.md +11 -7
  33. data/docs/assets/images/balanced-strategy-decay.svg +41 -0
  34. data/docs/assets/images/class-hierarchy.svg +1 -1
  35. data/docs/assets/images/eviction-priority.svg +43 -0
  36. data/docs/assets/images/exception-hierarchy.svg +2 -2
  37. data/docs/assets/images/hive-mind-shared-memory.svg +52 -0
  38. data/docs/assets/images/htm-architecture-overview.svg +3 -3
  39. data/docs/assets/images/htm-core-components.svg +4 -4
  40. data/docs/assets/images/htm-layered-architecture.svg +1 -1
  41. data/docs/assets/images/htm-memory-addition-flow.svg +2 -2
  42. data/docs/assets/images/htm-memory-recall-flow.svg +2 -2
  43. data/docs/assets/images/memory-topology.svg +53 -0
  44. data/docs/assets/images/two-tier-memory-architecture.svg +55 -0
  45. data/docs/database_rake_tasks.md +5 -5
  46. data/docs/development/rake-tasks.md +11 -11
  47. data/docs/development/setup.md +97 -65
  48. data/docs/development/testing.md +1 -1
  49. data/docs/examples/basic-usage.md +133 -0
  50. data/docs/examples/config-files.md +170 -0
  51. data/docs/examples/file-loading.md +208 -0
  52. data/docs/examples/index.md +116 -0
  53. data/docs/examples/llm-configuration.md +168 -0
  54. data/docs/examples/mcp-client.md +172 -0
  55. data/docs/examples/rails-integration.md +173 -0
  56. data/docs/examples/robot-groups.md +210 -0
  57. data/docs/examples/sinatra-integration.md +218 -0
  58. data/docs/examples/standalone-app.md +216 -0
  59. data/docs/examples/telemetry.md +224 -0
  60. data/docs/examples/timeframes.md +143 -0
  61. data/docs/getting-started/installation.md +117 -60
  62. data/docs/getting-started/quick-start.md +35 -18
  63. data/docs/guides/configuration.md +515 -0
  64. data/docs/guides/file-loading.md +322 -0
  65. data/docs/guides/getting-started.md +42 -11
  66. data/docs/guides/index.md +3 -3
  67. data/docs/guides/long-term-memory.md +1 -1
  68. data/docs/guides/mcp-server.md +47 -29
  69. data/docs/guides/propositions.md +264 -0
  70. data/docs/guides/recalling-memories.md +4 -4
  71. data/docs/guides/search-strategies.md +3 -3
  72. data/docs/guides/tags.md +318 -0
  73. data/docs/guides/telemetry.md +229 -0
  74. data/docs/index.md +10 -18
  75. data/docs/multi_framework_support.md +8 -8
  76. data/docs/{architecture → robots}/hive-mind.md +8 -111
  77. data/docs/robots/index.md +73 -0
  78. data/docs/{guides → robots}/multi-robot.md +3 -3
  79. data/docs/{guides → robots}/robot-groups.md +14 -13
  80. data/docs/{architecture → robots}/two-tier-memory.md +13 -149
  81. data/docs/robots/why-robots.md +85 -0
  82. data/docs/setup_local_database.md +19 -19
  83. data/docs/using_rake_tasks_in_your_app.md +14 -14
  84. data/examples/README.md +50 -6
  85. data/examples/basic_usage.rb +31 -21
  86. data/examples/cli_app/README.md +8 -8
  87. data/examples/cli_app/htm_cli.rb +5 -5
  88. data/examples/config_file_example/README.md +256 -0
  89. data/examples/config_file_example/config/htm.local.yml +34 -0
  90. data/examples/config_file_example/custom_config.yml +22 -0
  91. data/examples/config_file_example/show_config.rb +125 -0
  92. data/examples/custom_llm_configuration.rb +7 -7
  93. data/examples/example_app/Rakefile +2 -2
  94. data/examples/example_app/app.rb +8 -8
  95. data/examples/file_loader_usage.rb +9 -9
  96. data/examples/mcp_client.rb +5 -5
  97. data/examples/rails_app/Gemfile.lock +48 -56
  98. data/examples/rails_app/README.md +1 -1
  99. data/examples/robot_groups/multi_process.rb +5 -5
  100. data/examples/robot_groups/robot_worker.rb +5 -5
  101. data/examples/robot_groups/same_process.rb +9 -9
  102. data/examples/sinatra_app/app.rb +1 -1
  103. data/examples/timeframe_demo.rb +1 -1
  104. data/lib/htm/active_record_config.rb +12 -25
  105. data/lib/htm/circuit_breaker.rb +0 -2
  106. data/lib/htm/config/defaults.yml +246 -0
  107. data/lib/htm/config.rb +888 -0
  108. data/lib/htm/database.rb +23 -27
  109. data/lib/htm/embedding_service.rb +0 -4
  110. data/lib/htm/integrations/sinatra.rb +3 -7
  111. data/lib/htm/job_adapter.rb +76 -16
  112. data/lib/htm/jobs/generate_embedding_job.rb +1 -7
  113. data/lib/htm/jobs/generate_propositions_job.rb +2 -12
  114. data/lib/htm/jobs/generate_tags_job.rb +1 -8
  115. data/lib/htm/loaders/defaults_loader.rb +143 -0
  116. data/lib/htm/loaders/xdg_config_loader.rb +116 -0
  117. data/lib/htm/mcp/cli.rb +200 -58
  118. data/lib/htm/mcp/server.rb +3 -3
  119. data/lib/htm/proposition_service.rb +2 -12
  120. data/lib/htm/railtie.rb +3 -4
  121. data/lib/htm/tag_service.rb +1 -8
  122. data/lib/htm/version.rb +1 -1
  123. data/lib/htm/workflows/remember_workflow.rb +212 -0
  124. data/lib/htm.rb +125 -5
  125. data/mkdocs.yml +33 -8
  126. metadata +83 -10
  127. data/config/database.yml +0 -77
  128. data/docs/api/yard/HTM/Configuration.md +0 -229
  129. data/docs/telemetry.md +0 -391
  130. data/lib/htm/configuration.rb +0 -799
@@ -6,64 +6,10 @@ HTM implements a sophisticated two-tier memory architecture that balances the co
6
6
 
7
7
  The two-tier architecture addresses a fundamental challenge in LLM-based applications: LLMs have limited context windows but need to maintain awareness across long conversations spanning days, weeks, or months.
8
8
 
9
- <svg viewBox="0 0 800 500" xmlns="http://www.w3.org/2000/svg" style="background: transparent;">
10
- <!-- Title -->
11
- <text x="400" y="30" text-anchor="middle" fill="#E0E0E0" font-size="18" font-weight="bold">Two-Tier Memory Architecture</text>
12
-
13
- <!-- Working Memory (Hot Tier) -->
14
- <rect x="50" y="80" width="300" height="180" fill="rgba(33, 150, 243, 0.2)" stroke="#2196F3" stroke-width="3" rx="5"/>
15
- <text x="200" y="110" text-anchor="middle" fill="#E0E0E0" font-size="16" font-weight="bold">Working Memory (Hot)</text>
16
- <text x="80" y="140" fill="#B0B0B0" font-size="12">Capacity: Token-limited (128K)</text>
17
- <text x="80" y="160" fill="#B0B0B0" font-size="12">Storage: In-memory Ruby Hash</text>
18
- <text x="80" y="180" fill="#B0B0B0" font-size="12">Speed: O(1) lookups</text>
19
- <text x="80" y="200" fill="#B0B0B0" font-size="12">Lifetime: Process lifetime</text>
20
- <text x="80" y="220" fill="#B0B0B0" font-size="12">Eviction: Importance + Recency</text>
21
- <text x="80" y="240" fill="#4CAF50" font-size="12" font-weight="bold">Fast, Token-Aware, Volatile</text>
22
-
23
- <!-- Long-Term Memory (Cold Tier) -->
24
- <rect x="450" y="80" width="300" height="180" fill="rgba(156, 39, 176, 0.2)" stroke="#9C27B0" stroke-width="3" rx="5"/>
25
- <text x="600" y="110" text-anchor="middle" fill="#E0E0E0" font-size="16" font-weight="bold">Long-Term Memory (Cold)</text>
26
- <text x="480" y="140" fill="#B0B0B0" font-size="12">Capacity: Unlimited</text>
27
- <text x="480" y="160" fill="#B0B0B0" font-size="12">Storage: PostgreSQL + TimescaleDB</text>
28
- <text x="480" y="180" fill="#B0B0B0" font-size="12">Speed: O(log n) with indexes</text>
29
- <text x="480" y="200" fill="#B0B0B0" font-size="12">Lifetime: Permanent</text>
30
- <text x="480" y="220" fill="#B0B0B0" font-size="12">Retrieval: RAG (semantic + temporal)</text>
31
- <text x="480" y="240" fill="#4CAF50" font-size="12" font-weight="bold">Durable, Searchable, Persistent</text>
32
-
33
- <!-- Data Flow: Add Memory -->
34
- <path d="M 200 280 L 200 320 L 400 320 L 400 280" stroke="#4CAF50" stroke-width="3" fill="none" marker-end="url(#arrow-green)"/>
35
- <text x="300" y="310" text-anchor="middle" fill="#4CAF50" font-size="12" font-weight="bold">Add Memory</text>
36
- <text x="300" y="330" text-anchor="middle" fill="#B0B0B0" font-size="10">(Stored in both tiers)</text>
37
-
38
- <!-- Data Flow: Eviction -->
39
- <path d="M 350 360 L 600 360" stroke="#FF9800" stroke-width="3" marker-end="url(#arrow-orange)"/>
40
- <text x="475" y="350" text-anchor="middle" fill="#FF9800" font-size="12" font-weight="bold">Eviction</text>
41
- <text x="475" y="380" text-anchor="middle" fill="#B0B0B0" font-size="10">(Token limit → move to LTM only)</text>
42
-
43
- <!-- Data Flow: Recall -->
44
- <path d="M 600 400 L 200 400" stroke="#9C27B0" stroke-width="3" marker-end="url(#arrow-purple)"/>
45
- <text x="400" y="390" text-anchor="middle" fill="#9C27B0" font-size="12" font-weight="bold">Recall</text>
46
- <text x="400" y="420" text-anchor="middle" fill="#B0B0B0" font-size="10">(RAG search → load back to WM)</text>
47
-
48
- <!-- Never Forget Note -->
49
- <rect x="150" y="450" width="500" height="40" fill="rgba(76, 175, 80, 0.1)" stroke="#4CAF50" stroke-width="1" rx="3"/>
50
- <text x="400" y="475" text-anchor="middle" fill="#4CAF50" font-size="13" font-weight="bold">Never Forget: Evicted memories stay in LTM forever (explicit deletion only)</text>
51
-
52
- <defs>
53
- <marker id="arrow-green" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
54
- <polygon points="0 0, 10 3, 0 6" fill="#4CAF50"/>
55
- </marker>
56
- <marker id="arrow-orange" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
57
- <polygon points="0 0, 10 3, 0 6" fill="#FF9800"/>
58
- </marker>
59
- <marker id="arrow-purple" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
60
- <polygon points="0 0, 10 3, 0 6" fill="#9C27B0"/>
61
- </marker>
62
- </defs>
63
- </svg>
9
+ ![Two-Tier Memory Architecture](../assets/images/two-tier-memory-architecture.svg)
64
10
 
65
11
  !!! info "Related ADR"
66
- See [ADR-002: Two-Tier Memory Architecture](adrs/002-two-tier-memory.md) for the complete architectural decision record.
12
+ See [ADR-002: Two-Tier Memory Architecture](../architecture/adrs/002-two-tier-memory.md) for the complete architectural decision record.
67
13
 
68
14
  ## Working Memory (Hot Tier)
69
15
 
@@ -209,55 +155,13 @@ Nodes are evicted in this order:
209
155
  3. **High importance, old** (e.g., importance: 9.0, age: 5 days)
210
156
  4. **High importance, recent** (e.g., importance: 9.0, age: 1 hour) ← **Kept longest**
211
157
 
212
- <svg viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg" style="background: transparent;">
213
- <!-- Title -->
214
- <text x="400" y="30" text-anchor="middle" fill="#E0E0E0" font-size="16" font-weight="bold">Eviction Priority (Lower → Higher retention)</text>
215
-
216
- <!-- Priority bars -->
217
- <rect x="50" y="80" width="150" height="50" fill="rgba(244, 67, 54, 0.6)" stroke="#F44336" stroke-width="2" rx="3"/>
218
- <text x="125" y="110" text-anchor="middle" fill="#E0E0E0" font-size="12" font-weight="bold">Tier 1: Evict First</text>
219
-
220
- <rect x="220" y="80" width="150" height="50" fill="rgba(255, 152, 0, 0.6)" stroke="#FF9800" stroke-width="2" rx="3"/>
221
- <text x="295" y="110" text-anchor="middle" fill="#E0E0E0" font-size="12" font-weight="bold">Tier 2</text>
222
-
223
- <rect x="390" y="80" width="150" height="50" fill="rgba(255, 193, 7, 0.6)" stroke="#FFC107" stroke-width="2" rx="3"/>
224
- <text x="465" y="110" text-anchor="middle" fill="#E0E0E0" font-size="12" font-weight="bold">Tier 3</text>
225
-
226
- <rect x="560" y="80" width="150" height="50" fill="rgba(76, 175, 80, 0.6)" stroke="#4CAF50" stroke-width="2" rx="3"/>
227
- <text x="635" y="110" text-anchor="middle" fill="#E0E0E0" font-size="12" font-weight="bold">Tier 4: Keep Longest</text>
228
-
229
- <!-- Details -->
230
- <text x="125" y="160" text-anchor="middle" fill="#B0B0B0" font-size="11">Importance: 1.0</text>
231
- <text x="125" y="180" text-anchor="middle" fill="#B0B0B0" font-size="11">Age: 5 days</text>
232
- <text x="125" y="200" text-anchor="middle" fill="#F44336" font-size="10" font-weight="bold">Low value, stale</text>
233
-
234
- <text x="295" y="160" text-anchor="middle" fill="#B0B0B0" font-size="11">Importance: 1.0</text>
235
- <text x="295" y="180" text-anchor="middle" fill="#B0B0B0" font-size="11">Age: 1 hour</text>
236
- <text x="295" y="200" text-anchor="middle" fill="#FF9800" font-size="10" font-weight="bold">Low value, recent</text>
237
-
238
- <text x="465" y="160" text-anchor="middle" fill="#B0B0B0" font-size="11">Importance: 9.0</text>
239
- <text x="465" y="180" text-anchor="middle" fill="#B0B0B0" font-size="11">Age: 5 days</text>
240
- <text x="465" y="200" text-anchor="middle" fill="#FFC107" font-size="10" font-weight="bold">High value, older</text>
241
-
242
- <text x="635" y="160" text-anchor="middle" fill="#B0B0B0" font-size="11">Importance: 9.0</text>
243
- <text x="635" y="180" text-anchor="middle" fill="#B0B0B0" font-size="11">Age: 1 hour</text>
244
- <text x="635" y="200" text-anchor="middle" fill="#4CAF50" font-size="10" font-weight="bold">High value, fresh</text>
245
-
246
- <!-- Example scenario -->
247
- <text x="50" y="250" fill="#E0E0E0" font-size="13" font-weight="bold">Example Eviction Scenario:</text>
248
- <text x="50" y="280" fill="#B0B0B0" font-size="11">Working Memory: 127,500 / 128,000 tokens (99% full)</text>
249
- <text x="50" y="300" fill="#B0B0B0" font-size="11">New memory to add: 5,000 tokens</text>
250
- <text x="50" y="320" fill="#B0B0B0" font-size="11">Need to free: 4,500 tokens</text>
251
-
252
- <text x="50" y="350" fill="#4CAF50" font-size="11">Eviction: Remove Tier 1 and Tier 2 nodes until 4,500+ tokens freed</text>
253
- <text x="50" y="370" fill="#4CAF50" font-size="11">Result: Tier 3 and Tier 4 nodes preserved (high importance)</text>
254
- </svg>
158
+ ![Eviction Priority](../assets/images/eviction-priority.svg)
255
159
 
256
160
  !!! warning "Importance Matters"
257
161
  **Assign meaningful importance scores!** Low-importance memories (1.0-3.0) will be evicted first. Use higher scores (7.0-10.0) for critical information like architectural decisions, user preferences, and long-term facts.
258
162
 
259
163
  !!! info "Related ADR"
260
- See [ADR-007: Working Memory Eviction Strategy](adrs/007-eviction-strategy.md) for detailed rationale and alternatives considered.
164
+ See [ADR-007: Working Memory Eviction Strategy](../architecture/adrs/007-eviction-strategy.md) for detailed rationale and alternatives considered.
261
165
 
262
166
  ### Context Assembly Strategies
263
167
 
@@ -352,50 +256,10 @@ context = htm.create_context(strategy: :balanced)
352
256
  # Recent debugging context + important architectural decisions
353
257
  ```
354
258
 
355
- <svg viewBox="0 0 800 400" xmlns="http://www.w3.org/2000/svg" style="background: transparent;">
356
- <!-- Title -->
357
- <text x="400" y="30" text-anchor="middle" fill="#E0E0E0" font-size="16" font-weight="bold">Balanced Strategy: Importance Decay Over Time</text>
358
-
359
- <!-- Axes -->
360
- <line x1="100" y1="350" x2="700" y2="350" stroke="#808080" stroke-width="2"/>
361
- <line x1="100" y1="350" x2="100" y2="80" stroke="#808080" stroke-width="2"/>
362
-
363
- <!-- X-axis labels -->
364
- <text x="100" y="375" text-anchor="middle" fill="#B0B0B0" font-size="11">0h</text>
365
- <text x="250" y="375" text-anchor="middle" fill="#B0B0B0" font-size="11">1h</text>
366
- <text x="400" y="375" text-anchor="middle" fill="#B0B0B0" font-size="11">3h</text>
367
- <text x="550" y="375" text-anchor="middle" fill="#B0B0B0" font-size="11">6h</text>
368
- <text x="700" y="375" text-anchor="middle" fill="#B0B0B0" font-size="11">24h</text>
369
- <text x="400" y="395" text-anchor="middle" fill="#E0E0E0" font-size="12" font-weight="bold">Time Since Added (hours)</text>
370
-
371
- <!-- Y-axis labels -->
372
- <text x="85" y="355" text-anchor="end" fill="#B0B0B0" font-size="11">0</text>
373
- <text x="85" y="280" text-anchor="end" fill="#B0B0B0" font-size="11">3</text>
374
- <text x="85" y="205" text-anchor="end" fill="#B0B0B0" font-size="11">6</text>
375
- <text x="85" y="130" text-anchor="end" fill="#B0B0B0" font-size="11">9</text>
376
- <text x="85" y="85" text-anchor="end" fill="#B0B0B0" font-size="11">10</text>
377
- <text x="40" y="220" text-anchor="middle" fill="#E0E0E0" font-size="12" font-weight="bold" transform="rotate(-90 40 220)">Effective Score</text>
378
-
379
- <!-- Decay curves for different importance levels -->
380
- <!-- Importance 10.0 -->
381
- <path d="M 100 80 Q 250 105 400 155 T 700 320" stroke="#4CAF50" stroke-width="3" fill="none"/>
382
- <text x="710" y="320" fill="#4CAF50" font-size="11" font-weight="bold">Imp: 10.0</text>
383
-
384
- <!-- Importance 5.0 -->
385
- <path d="M 100 205 Q 250 230 400 255 T 700 335" stroke="#2196F3" stroke-width="3" fill="none"/>
386
- <text x="710" y="335" fill="#2196F3" font-size="11" font-weight="bold">Imp: 5.0</text>
387
-
388
- <!-- Importance 1.0 -->
389
- <path d="M 100 330 Q 250 340 400 345 T 700 348" stroke="#FF9800" stroke-width="3" fill="none"/>
390
- <text x="710" y="348" fill="#FF9800" font-size="11" font-weight="bold">Imp: 1.0</text>
391
-
392
- <!-- Key insight -->
393
- <rect x="150" y="50" width="500" height="25" fill="rgba(76, 175, 80, 0.1)" stroke="#4CAF50" stroke-width="1" rx="3"/>
394
- <text x="400" y="68" text-anchor="middle" fill="#4CAF50" font-size="12">High-importance memories retain value longer, but recency still matters</text>
395
- </svg>
259
+ ![Balanced Strategy: Importance Decay Over Time](../assets/images/balanced-strategy-decay.svg)
396
260
 
397
261
  !!! info "Related ADR"
398
- See [ADR-006: Context Assembly Strategies](adrs/006-context-assembly.md) for detailed strategy analysis.
262
+ See [ADR-006: Context Assembly Strategies](../architecture/adrs/006-context-assembly.md) for detailed strategy analysis.
399
263
 
400
264
  ### Performance Characteristics
401
265
 
@@ -474,7 +338,7 @@ CREATE INDEX idx_nodes_value_gin ON nodes
474
338
  - Retention policies for data lifecycle
475
339
 
476
340
  !!! info "Related ADR"
477
- See [ADR-001: Use PostgreSQL with TimescaleDB for Storage](adrs/001-postgresql-timescaledb.md) for complete rationale.
341
+ See [ADR-001: Use PostgreSQL with TimescaleDB for Storage](../architecture/adrs/001-postgresql-timescaledb.md) for complete rationale.
478
342
 
479
343
  ### Long-Term Memory Operations
480
344
 
@@ -560,7 +424,7 @@ end
560
424
  ```
561
425
 
562
426
  !!! info "Related ADR"
563
- See [ADR-005: RAG-Based Retrieval with Hybrid Search](adrs/005-rag-retrieval.md) for search strategy details.
427
+ See [ADR-005: RAG-Based Retrieval with Hybrid Search](../architecture/adrs/005-rag-retrieval.md) for search strategy details.
564
428
 
565
429
  ### RAG-Based Retrieval
566
430
 
@@ -831,9 +695,9 @@ LIMIT 20;
831
695
 
832
696
  ## Related Documentation
833
697
 
834
- - [Architecture Index](index.md) - System overview and component summary
835
- - [Architecture Overview](overview.md) - Detailed architecture and data flows
698
+ - [Architecture Index](../architecture/index.md) - System overview and component summary
699
+ - [Architecture Overview](../architecture/overview.md) - Detailed architecture and data flows
836
700
  - [Hive Mind Architecture](hive-mind.md) - Multi-robot shared memory
837
- - [ADR-002: Two-Tier Memory Architecture](adrs/002-two-tier-memory.md)
838
- - [ADR-006: Context Assembly Strategies](adrs/006-context-assembly.md)
839
- - [ADR-007: Working Memory Eviction Strategy](adrs/007-eviction-strategy.md)
701
+ - [ADR-002: Two-Tier Memory Architecture](../architecture/adrs/002-two-tier-memory.md)
702
+ - [ADR-006: Context Assembly Strategies](../architecture/adrs/006-context-assembly.md)
703
+ - [ADR-007: Working Memory Eviction Strategy](../architecture/adrs/007-eviction-strategy.md)
@@ -0,0 +1,85 @@
1
+ # Why "Robots" Instead of "Agents"?
2
+
3
+ > "What's in a name? That which we call a rose
4
+ > By any other name would smell as sweet."
5
+ > — Shakespeare, *Romeo and Juliet*
6
+
7
+ Shakespeare argues names are arbitrary. In software, we respectfully disagree—names shape expectations and understanding. The words we choose frame how we think about systems, what we expect from them, and how we architect their capabilities.
8
+
9
+ HTM uses **robots** rather than the fashionable "agents" deliberately and thoughtfully.
10
+
11
+ ## The Problem with "Agent"
12
+
13
+ The term "agent" carries philosophical baggage it cannot support:
14
+
15
+ - **Semantic overload**: User agents, software agents, real estate agents, secret agents, FBI agents, travel agents. The word means everything and therefore nothing. When you say "AI agent," what mental model does your listener construct?
16
+
17
+ - **False autonomy**: "Agent" implies genuine decision-making, independent action, perhaps even free will. These systems follow instructions. They predict the next token. They don't have *agency* in any meaningful philosophical sense. Calling them agents sets expectations the technology cannot meet.
18
+
19
+ - **The hype cycle problem**: "AI Agent" and "Agentic AI" became buzzwords in 2023-2024, often meaning nothing more than "LLM with a prompt and a while loop." We prefer terminology that will age gracefully rather than become an embarrassing artifact of a particular moment's enthusiasm.
20
+
21
+ - **Implementation reality**: Look under the hood of popular "agent" frameworks. You'll often find a system prompt, a for-loop, and some JSON parsing. Calling that an "agent" is marketing, not engineering.
22
+
23
+ ## The Case for "Robot"
24
+
25
+ "Robot" has heritage, honesty, and heart:
26
+
27
+ - **Rich literary tradition**: The word comes from Karel Čapek's 1920 play *R.U.R.* (Rossum's Universal Robots), derived from Czech *robota*, meaning forced labor or drudgery. Isaac Asimov gave us the Three Laws of Robotics and decades of thoughtful exploration of robot ethics, identity, and purpose. There's a century of serious thinking about what robots are and how they should behave. "Agent" has no comparable intellectual foundation.
28
+
29
+ - **Honest about the relationship**: Robots work for us. They're tireless, reliable, and purpose-built. They don't pretend to have goals independent of their creators. This honesty about the master-worker relationship is healthier than the ambiguity of "agent."
30
+
31
+ - **Cultural resonance**: Robots are endearing. R2-D2. Wall-E. Bender. Data. The Iron Giant. Baymax. We've spent a century telling stories about robots, developing affection for them, and exploring their place alongside humanity. "Agent" has no such cultural weight—it's the language of bureaucracy and espionage.
32
+
33
+ - **Technical precision**: In HTM, each robot has an identity (`robot_id`), a name, and a history of contributions. Robots are registered in a table. They're tracked. They're *things* with identity and persistence. "Agent" suggests ephemerality; "robot" suggests durability.
34
+
35
+ ## Robots in the Hive Mind
36
+
37
+ HTM's architecture reinforces the robot metaphor in a specific way: **all robots share a common long-term memory**.
38
+
39
+ This is the *hive mind* pattern. Individual robots have their own working memory—their own immediate context and focus—but they draw from and contribute to a shared pool of knowledge. Like worker bees serving a hive, each robot is both individual and part of something larger.
40
+
41
+ ```
42
+ ┌─────────────────────────────────────────────────────┐
43
+ │ Shared Long-Term Memory │
44
+ │ (The Hive Mind / Collective) │
45
+ │ │
46
+ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
47
+ │ │ Memory │ │ Memory │ │ Memory │ ... │
48
+ │ └─────────┘ └─────────┘ └─────────┘ │
49
+ └─────────────────────────────────────────────────────┘
50
+ ▲ ▲ ▲
51
+ │ │ │
52
+ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐
53
+ │ Robot A │ │ Robot B │ │ Robot C │
54
+ │ │ │ │ │ │
55
+ │ Working │ │ Working │ │ Working │
56
+ │ Memory │ │ Memory │ │ Memory │
57
+ └─────────┘ └─────────┘ └─────────┘
58
+ ```
59
+
60
+ This architecture maps naturally to the robot metaphor:
61
+
62
+ - **Robots are workers**: They execute tasks, store memories, recall information
63
+ - **Robots are individuals**: Each has its own name, identity, and working context
64
+ - **Robots are collective**: They share knowledge, learn from each other's experiences
65
+ - **Robots are persistent**: They're registered, tracked, and their contributions are attributed
66
+
67
+ "Agent" suggests independence and autonomy. "Robot" suggests collaboration and purpose. HTM's robots work together, building collective intelligence. That's what the terminology should convey.
68
+
69
+ ## Robots Never Forget
70
+
71
+ HTM follows a **never-forget philosophy** (see [ADR-009](../architecture/adrs/009-never-forget.md)). Memories are never truly deleted—only soft-deleted, always recoverable. This aligns with the robot metaphor:
72
+
73
+ A good robot doesn't lose your data. A good robot remembers what you told it, years later if necessary. A good robot is *reliable* in a way that ephemeral "agents" are not.
74
+
75
+ When you tell an HTM robot something important, it stores that information in the collective memory. Other robots can access it. Future robots can learn from it. The knowledge persists, attributed to the robot that first contributed it.
76
+
77
+ This is robot memory done right: durable, shared, and faithful.
78
+
79
+ ## Honest Terminology, Clear Thinking
80
+
81
+ Language shapes thought. When we call these systems "agents," we prime ourselves to expect agency—goals, autonomy, perhaps even consciousness. When we call them "robots," we remind ourselves what they actually are: sophisticated tools, tireless workers, faithful servants of the instructions we give them.
82
+
83
+ HTM helps robots do their job better: remember perfectly, recall intelligently, share knowledge generously, and serve reliably. That's not agency. That's good engineering.
84
+
85
+ These are robots. Let's call them what they are.
@@ -63,12 +63,12 @@ Update your `.envrc` file (already done):
63
63
 
64
64
  ```bash
65
65
  # Database connection - Localhost PostgreSQL
66
- export HTM_DBHOST=localhost
67
- export HTM_DBPORT=5432
68
- export HTM_DBNAME=htm_development
69
- export HTM_DBUSER=${USER}
70
- export HTM_DBPASS=
71
- export HTM_DBURL="postgresql://${HTM_DBUSER}@${HTM_DBHOST}:${HTM_DBPORT}/${HTM_DBNAME}?sslmode=prefer"
66
+ export HTM_DATABASE__HOST=localhost
67
+ export HTM_DATABASE__PORT=5432
68
+ export HTM_DATABASE__NAME=htm_development
69
+ export HTM_DATABASE__USER=${USER}
70
+ export HTM_DATABASE__PASSWORD=
71
+ export HTM_DATABASE__URL="postgresql://${HTM_DATABASE__USER}@${HTM_DATABASE__HOST}:${HTM_DATABASE__PORT}/${HTM_DATABASE__NAME}?sslmode=prefer"
72
72
 
73
73
  # Client-side embedding generation
74
74
  export HTM_EMBEDDINGS_PROVIDER=ollama
@@ -209,7 +209,7 @@ ollama serve
209
209
  **Solution:**
210
210
  ```bash
211
211
  direnv allow
212
- echo $HTM_DBURL # Verify it's set
212
+ echo $HTM_DATABASE__URL # Verify it's set
213
213
  ```
214
214
 
215
215
  ## Switching Back to TimescaleDB Cloud
@@ -218,21 +218,21 @@ To switch back to TimescaleDB Cloud (production), edit `.envrc`:
218
218
 
219
219
  ```bash
220
220
  # Comment out localhost config
221
- # export HTM_DBHOST=localhost
222
- # export HTM_DBPORT=5432
223
- # export HTM_DBNAME=htm_development
224
- # export HTM_DBUSER=${USER}
225
- # export HTM_DBPASS=
226
- # export HTM_DBURL="postgresql://${HTM_DBUSER}@${HTM_DBHOST}:${HTM_DBPORT}/${HTM_DBNAME}?sslmode=prefer"
221
+ # export HTM_DATABASE__HOST=localhost
222
+ # export HTM_DATABASE__PORT=5432
223
+ # export HTM_DATABASE__NAME=htm_development
224
+ # export HTM_DATABASE__USER=${USER}
225
+ # export HTM_DATABASE__PASSWORD=
226
+ # export HTM_DATABASE__URL="postgresql://${HTM_DATABASE__USER}@${HTM_DATABASE__HOST}:${HTM_DATABASE__PORT}/${HTM_DATABASE__NAME}?sslmode=prefer"
227
227
 
228
228
  # Uncomment TimescaleDB Cloud config
229
229
  export HTM_SERVICE_NAME=$TIGER_SERVICE_NAME
230
- export HTM_DBURL=$TIGER_DBURL
231
- export HTM_DBNAME=$TIGER_DBNAME
232
- export HTM_DBUSER=$TIGER_DBUSER
233
- export HTM_DBPASS=$TIGER_DBPASS
234
- export HTM_DBHOST=$TIGER_DBHOST
235
- export HTM_DBPORT=$TIGER_DBPORT
230
+ export HTM_DATABASE__URL=$TIGER_DBURL
231
+ export HTM_DATABASE__NAME=$TIGER_DBNAME
232
+ export HTM_DATABASE__USER=$TIGER_DBUSER
233
+ export HTM_DATABASE__PASSWORD=$TIGER_DBPASS
234
+ export HTM_DATABASE__HOST=$TIGER_DBHOST
235
+ export HTM_DATABASE__PORT=$TIGER_DBPORT
236
236
  ```
237
237
 
238
238
  Then reload:
@@ -63,14 +63,14 @@ Create a `.envrc` file in your application's root:
63
63
 
64
64
  ```bash
65
65
  # .envrc
66
- export HTM_DBURL="postgresql://user:password@host:port/dbname?sslmode=require"
66
+ export HTM_DATABASE__URL="postgresql://user:password@host:port/dbname?sslmode=require"
67
67
 
68
68
  # Or use individual parameters
69
- export HTM_DBHOST="your-host.tsdb.cloud.timescale.com"
70
- export HTM_DBPORT="37807"
71
- export HTM_DBNAME="tsdb"
72
- export HTM_DBUSER="tsdbadmin"
73
- export HTM_DBPASS="your_password"
69
+ export HTM_DATABASE__HOST="your-host.tsdb.cloud.timescale.com"
70
+ export HTM_DATABASE__PORT="37807"
71
+ export HTM_DATABASE__NAME="tsdb"
72
+ export HTM_DATABASE__USER="tsdbadmin"
73
+ export HTM_DATABASE__PASSWORD="your_password"
74
74
 
75
75
  # Embedding configuration
76
76
  export HTM_EMBEDDINGS_PROVIDER=ollama
@@ -93,7 +93,7 @@ direnv allow
93
93
  ### Option 2: Export in Shell
94
94
 
95
95
  ```bash
96
- export HTM_DBURL="postgresql://user:password@host:port/dbname?sslmode=require"
96
+ export HTM_DATABASE__URL="postgresql://user:password@host:port/dbname?sslmode=require"
97
97
  rake htm:db:info
98
98
  ```
99
99
 
@@ -103,7 +103,7 @@ rake htm:db:info
103
103
  # Rakefile
104
104
 
105
105
  # Set environment variables programmatically
106
- ENV['HTM_DBURL'] = "postgresql://user:password@host:port/dbname?sslmode=require"
106
+ ENV['HTM_DATABASE__URL'] = "postgresql://user:password@host:port/dbname?sslmode=require"
107
107
 
108
108
  # Then load tasks
109
109
  require 'htm/tasks'
@@ -122,7 +122,7 @@ require 'htm/tasks'
122
122
 
123
123
  ```bash
124
124
  # .env
125
- HTM_DBURL=postgresql://user:password@host:port/dbname?sslmode=require
125
+ HTM_DATABASE__URL=postgresql://user:password@host:port/dbname?sslmode=require
126
126
  ```
127
127
 
128
128
  ## Real-World Example
@@ -297,13 +297,13 @@ jobs:
297
297
 
298
298
  - name: Setup database
299
299
  env:
300
- HTM_DBURL: postgresql://postgres:postgres@localhost:5432/test
300
+ HTM_DATABASE__URL: postgresql://postgres:postgres@localhost:5432/test
301
301
  run: |
302
302
  bundle exec rake htm:db:setup
303
303
 
304
304
  - name: Run tests
305
305
  env:
306
- HTM_DBURL: postgresql://postgres:postgres@localhost:5432/test
306
+ HTM_DATABASE__URL: postgresql://postgres:postgres@localhost:5432/test
307
307
  run: |
308
308
  bundle exec rake test
309
309
  ```
@@ -317,7 +317,7 @@ services:
317
317
  app:
318
318
  build: .
319
319
  environment:
320
- - HTM_DBURL=postgresql://postgres:postgres@db:5432/myapp
320
+ - HTM_DATABASE__URL=postgresql://postgres:postgres@db:5432/myapp
321
321
  depends_on:
322
322
  - db
323
323
  command: bash -c "rake htm:db:setup && rake app:start"
@@ -347,10 +347,10 @@ rake -T
347
347
  Error: Database configuration not found
348
348
  ```
349
349
 
350
- Solution: Set `HTM_DBURL` environment variable
350
+ Solution: Set `HTM_DATABASE__URL` environment variable
351
351
 
352
352
  ```bash
353
- export HTM_DBURL="postgresql://user:password@host:port/dbname"
353
+ export HTM_DATABASE__URL="postgresql://user:password@host:port/dbname"
354
354
  rake htm:db:info
355
355
  ```
356
356
 
data/examples/README.md CHANGED
@@ -8,12 +8,12 @@ All examples require:
8
8
 
9
9
  1. **PostgreSQL Database** with pgvector extension:
10
10
  ```bash
11
- export HTM_DBURL="postgresql://user@localhost:5432/htm_development"
11
+ export HTM_DATABASE__URL="postgresql://user@localhost:5432/htm_development"
12
12
  ```
13
13
 
14
14
  > **Note**: Database selection now respects `RAILS_ENV`. If `RAILS_ENV` is set,
15
- > HTM extracts the base name from `HTM_DBURL` and appends the environment suffix.
16
- > For example, with `HTM_DBURL=...htm_development` and `RAILS_ENV=test`, HTM
15
+ > HTM extracts the base name from `HTM_DATABASE__URL` and appends the environment suffix.
16
+ > For example, with `HTM_DATABASE__URL=...htm_development` and `HTM_ENV=test`, HTM
17
17
  > connects to `htm_test`. When `RAILS_ENV` is unset (typical for examples),
18
18
  > behavior is unchanged.
19
19
 
@@ -32,6 +32,43 @@ All examples require:
32
32
 
33
33
  ## Standalone Scripts
34
34
 
35
+ ### config_file_example/
36
+
37
+ **Configuration management with source tracing.**
38
+
39
+ Demonstrates how HTM uses `anyway_config` for layered configuration from multiple sources, with source tracing to show where each value originated.
40
+
41
+ ```bash
42
+ cd examples/config_file_example
43
+ ruby show_config.rb
44
+ ```
45
+
46
+ **Features:**
47
+ - Configuration priority order (defaults → XDG → project → local → env vars)
48
+ - Source tracing showing origin of each config value
49
+ - `HTM_CONF` environment variable for custom config file paths
50
+ - Environment-specific configuration (`HTM_ENV`)
51
+ - Generating config templates with `htm_mcp config`
52
+
53
+ **Usage examples:**
54
+ ```bash
55
+ # Basic - loads ./config/htm.local.yml automatically
56
+ ruby show_config.rb
57
+
58
+ # Use custom config file
59
+ HTM_CONF=./custom_config.yml ruby show_config.rb
60
+
61
+ # Override with environment variables
62
+ HTM_EMBEDDING__MODEL=mxbai-embed-large ruby show_config.rb
63
+
64
+ # Different environment
65
+ HTM_ENV=production ruby show_config.rb
66
+ ```
67
+
68
+ See [config_file_example/README.md](config_file_example/README.md) for detailed documentation.
69
+
70
+ ---
71
+
35
72
  ### basic_usage.rb
36
73
 
37
74
  **Getting started with HTM fundamentals.**
@@ -184,7 +221,7 @@ ruby examples/mcp_server.rb
184
221
  "command": "ruby",
185
222
  "args": ["/path/to/htm/examples/mcp_server.rb"],
186
223
  "env": {
187
- "HTM_DBURL": "postgresql://user@localhost:5432/htm_development"
224
+ "HTM_DATABASE__URL": "postgresql://user@localhost:5432/htm_development"
188
225
  }
189
226
  }
190
227
  }
@@ -260,7 +297,7 @@ ollama pull gpt-oss # Or your preferred model
260
297
  ```
261
298
 
262
299
  **Environment Variables:**
263
- - `HTM_DBURL` - PostgreSQL connection (required)
300
+ - `HTM_DATABASE__URL` - PostgreSQL connection (required)
264
301
  - `OLLAMA_URL` - Ollama server URL (default: http://localhost:11434)
265
302
  - `OLLAMA_MODEL` - Model to use (default: gpt-oss:latest)
266
303
  - `HTM_ROBOT_NAME` - Robot name (optional, prompts if not set)
@@ -313,7 +350,7 @@ bundle exec ruby app.rb
313
350
  - Tag tree visualization
314
351
 
315
352
  **Environment Variables:**
316
- - `HTM_DBURL` - PostgreSQL connection (required)
353
+ - `HTM_DATABASE__URL` - PostgreSQL connection (required)
317
354
  - `REDIS_URL` - Redis for Sidekiq (default: redis://localhost:6379/0)
318
355
  - `SESSION_SECRET` - Session encryption key
319
356
 
@@ -405,6 +442,12 @@ examples/
405
442
  ├── custom_llm_configuration.rb # LLM integration patterns
406
443
  ├── file_loader_usage.rb # Document loading
407
444
  ├── timeframe_demo.rb # Time-based filtering
445
+ ├── config_file_example/
446
+ │ ├── show_config.rb # Config source tracing demo
447
+ │ ├── custom_config.yml # Example for HTM_CONF
448
+ │ ├── README.md # Configuration documentation
449
+ │ └── config/
450
+ │ └── htm.local.yml # Auto-loaded local overrides
408
451
  ├── telemetry/
409
452
  │ ├── demo.rb # Live Grafana metrics dashboard
410
453
  │ ├── README.md
@@ -438,6 +481,7 @@ examples/
438
481
  | Use Case | Example |
439
482
  |----------|---------|
440
483
  | Learning HTM basics | `basic_usage.rb` |
484
+ | Configuration management | `config_file_example/` |
441
485
  | Custom LLM integration | `custom_llm_configuration.rb` |
442
486
  | Loading documents/files | `file_loader_usage.rb` |
443
487
  | Time-based queries | `timeframe_demo.rb` |
@@ -4,8 +4,10 @@
4
4
  # Basic usage example for HTM
5
5
  #
6
6
  # Prerequisites:
7
- # 1. Set HTM_DBURL environment variable (see SETUP.md)
8
- # 2. Initialize database schema: rake db_setup
7
+ # 1. Configure database via environment or config file:
8
+ # - HTM_DATABASE__URL="postgresql://user@localhost:5432/htm_development"
9
+ # - Or individual vars: HTM_DATABASE__HOST, HTM_DATABASE__NAME, etc.
10
+ # 2. Initialize database schema: rake htm:db:setup
9
11
  # 3. Install dependencies: bundle install
10
12
 
11
13
  require_relative '../lib/htm'
@@ -13,26 +15,31 @@ require_relative '../lib/htm'
13
15
  puts "HTM Basic Usage Example"
14
16
  puts "=" * 60
15
17
 
16
- # Check environment
17
- unless ENV['HTM_DBURL']
18
- puts "ERROR: HTM_DBURL not set. Please set it:"
19
- puts " export HTM_DBURL=\"postgresql://postgres@localhost:5432/htm_development\""
20
- puts "See SETUP.md for details."
18
+ # Check database configuration using the config system
19
+ unless HTM.config.database_configured?
20
+ puts "ERROR: Database not configured. Set one of:"
21
+ puts " export HTM_DATABASE__URL=\"postgresql://user@localhost:5432/htm_development\""
22
+ puts " Or configure in ~/.config/htm/htm.yml"
23
+ puts "Run 'bin/htm_mcp help' for all configuration options."
21
24
  exit 1
22
25
  end
23
26
 
24
27
  begin
25
- # Configure HTM globally (uses Ollama by default)
28
+ # Configure HTM globally (uses Ollama by default from defaults.yml)
26
29
  puts "\n1. Configuring HTM with Ollama provider..."
27
30
  HTM.configure do |config|
28
- config.embedding_provider = :ollama
29
- config.embedding_model = 'nomic-embed-text:latest' # Ollama models need :tag suffix
30
- config.embedding_dimensions = 768
31
- config.tag_provider = :ollama
32
- config.tag_model = 'gemma3:latest' # Ollama models need :tag suffix
33
- config.reset_to_defaults # Apply settings
31
+ config.embedding.provider = :ollama
32
+ config.embedding.model = 'nomic-embed-text:latest'
33
+ config.embedding.dimensions = 768
34
+ config.tag.provider = :ollama
35
+ config.tag.model = 'gemma3:latest'
36
+ # Use inline job backend for synchronous execution in examples
37
+ # (In production, use :thread or :sidekiq for async processing)
38
+ config.job.backend = :inline
39
+ # Quiet the logs for cleaner output
40
+ config.log_level = :warn
34
41
  end
35
- puts "✓ HTM configured with Ollama provider"
42
+ puts "✓ HTM configured with Ollama provider (inline job backend)"
36
43
 
37
44
  # Initialize HTM for 'Code Helper' robot
38
45
  puts "\n2. Initializing HTM for 'Code Helper' robot..."
@@ -43,7 +50,7 @@ begin
43
50
  puts "✓ HTM initialized"
44
51
  puts " Robot ID: #{htm.robot_id}"
45
52
  puts " Robot Name: #{htm.robot_name}"
46
- puts " Embedding Service: Ollama (#{HTM.configuration.embedding_model})"
53
+ puts " Embedding Service: #{HTM.config.embedding.provider} (#{HTM.config.embedding.model})"
47
54
 
48
55
  # Remember some information
49
56
  puts "\n3. Remembering information..."
@@ -63,15 +70,18 @@ begin
63
70
  )
64
71
  puts "✓ Remembered fact about user preferences (node #{node_id_3})"
65
72
 
66
- # Sleep briefly to allow async embedding/tag jobs to start
67
- sleep 0.5
73
+ # With inline backend, embeddings and tags are generated synchronously
74
+ # No sleep needed - memories are immediately searchable
68
75
 
69
- # Demonstrate recall
70
- puts "\n4. Recalling memories about 'database'..."
76
+ # Demonstrate recall using fulltext search (keyword matching)
77
+ # Note: hybrid search requires fulltext matches first, so search terms
78
+ # must appear in the stored content. Use fulltext for keyword matching.
79
+ puts "\n4. Recalling memories about 'PostgreSQL'..."
71
80
  memories = htm.recall(
72
- "database",
81
+ "PostgreSQL", # This word appears in the stored content
73
82
  timeframe: (Time.now - 3600)..Time.now, # Last hour
74
83
  limit: 5,
84
+ strategy: :fulltext, # Keyword matching (words must appear in content)
75
85
  raw: true # Return full node data (id, content, etc.)
76
86
  )
77
87
  puts "✓ Found #{memories.length} memories"