htm 0.0.1

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 (155) hide show
  1. checksums.yaml +7 -0
  2. data/.architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md +227 -0
  3. data/.architecture/decisions/adrs/002-two-tier-memory-architecture.md +322 -0
  4. data/.architecture/decisions/adrs/003-ollama-default-embedding-provider.md +339 -0
  5. data/.architecture/decisions/adrs/004-multi-robot-shared-memory-hive-mind.md +374 -0
  6. data/.architecture/decisions/adrs/005-rag-based-retrieval-with-hybrid-search.md +443 -0
  7. data/.architecture/decisions/adrs/006-context-assembly-strategies.md +444 -0
  8. data/.architecture/decisions/adrs/007-working-memory-eviction-strategy.md +461 -0
  9. data/.architecture/decisions/adrs/008-robot-identification-system.md +550 -0
  10. data/.architecture/decisions/adrs/009-never-forget-explicit-deletion-only.md +570 -0
  11. data/.architecture/decisions/adrs/010-redis-working-memory-rejected.md +323 -0
  12. data/.architecture/decisions/adrs/011-database-side-embedding-generation-with-pgai.md +585 -0
  13. data/.architecture/decisions/adrs/012-llm-driven-ontology-topic-extraction.md +583 -0
  14. data/.architecture/decisions/adrs/013-activerecord-orm-and-many-to-many-tagging.md +299 -0
  15. data/.architecture/decisions/adrs/014-client-side-embedding-generation-workflow.md +569 -0
  16. data/.architecture/decisions/adrs/015-hierarchical-tag-ontology-and-llm-extraction.md +701 -0
  17. data/.architecture/decisions/adrs/016-async-embedding-and-tag-generation.md +694 -0
  18. data/.architecture/members.yml +144 -0
  19. data/.architecture/reviews/2025-10-29-llm-configuration-and-async-processing-review.md +1137 -0
  20. data/.architecture/reviews/initial-system-analysis.md +330 -0
  21. data/.envrc +32 -0
  22. data/.irbrc +145 -0
  23. data/CHANGELOG.md +150 -0
  24. data/COMMITS.md +196 -0
  25. data/LICENSE +21 -0
  26. data/README.md +1347 -0
  27. data/Rakefile +51 -0
  28. data/SETUP.md +268 -0
  29. data/config/database.yml +67 -0
  30. data/db/migrate/20250101000001_enable_extensions.rb +14 -0
  31. data/db/migrate/20250101000002_create_robots.rb +14 -0
  32. data/db/migrate/20250101000003_create_nodes.rb +42 -0
  33. data/db/migrate/20250101000005_create_tags.rb +38 -0
  34. data/db/migrate/20250101000007_add_node_vector_indexes.rb +30 -0
  35. data/db/schema.sql +473 -0
  36. data/db/seed_data/README.md +100 -0
  37. data/db/seed_data/presidents.md +136 -0
  38. data/db/seed_data/states.md +151 -0
  39. data/db/seeds.rb +208 -0
  40. data/dbdoc/README.md +173 -0
  41. data/dbdoc/public.node_stats.md +48 -0
  42. data/dbdoc/public.node_stats.svg +41 -0
  43. data/dbdoc/public.node_tags.md +40 -0
  44. data/dbdoc/public.node_tags.svg +112 -0
  45. data/dbdoc/public.nodes.md +54 -0
  46. data/dbdoc/public.nodes.svg +118 -0
  47. data/dbdoc/public.nodes_tags.md +39 -0
  48. data/dbdoc/public.nodes_tags.svg +112 -0
  49. data/dbdoc/public.ontology_structure.md +48 -0
  50. data/dbdoc/public.ontology_structure.svg +38 -0
  51. data/dbdoc/public.operations_log.md +42 -0
  52. data/dbdoc/public.operations_log.svg +130 -0
  53. data/dbdoc/public.relationships.md +39 -0
  54. data/dbdoc/public.relationships.svg +41 -0
  55. data/dbdoc/public.robot_activity.md +46 -0
  56. data/dbdoc/public.robot_activity.svg +35 -0
  57. data/dbdoc/public.robots.md +35 -0
  58. data/dbdoc/public.robots.svg +90 -0
  59. data/dbdoc/public.schema_migrations.md +29 -0
  60. data/dbdoc/public.schema_migrations.svg +26 -0
  61. data/dbdoc/public.tags.md +35 -0
  62. data/dbdoc/public.tags.svg +60 -0
  63. data/dbdoc/public.topic_relationships.md +45 -0
  64. data/dbdoc/public.topic_relationships.svg +32 -0
  65. data/dbdoc/schema.json +1437 -0
  66. data/dbdoc/schema.svg +154 -0
  67. data/docs/api/database.md +806 -0
  68. data/docs/api/embedding-service.md +532 -0
  69. data/docs/api/htm.md +797 -0
  70. data/docs/api/index.md +259 -0
  71. data/docs/api/long-term-memory.md +1096 -0
  72. data/docs/api/working-memory.md +665 -0
  73. data/docs/architecture/adrs/001-postgresql-timescaledb.md +314 -0
  74. data/docs/architecture/adrs/002-two-tier-memory.md +411 -0
  75. data/docs/architecture/adrs/003-ollama-embeddings.md +421 -0
  76. data/docs/architecture/adrs/004-hive-mind.md +437 -0
  77. data/docs/architecture/adrs/005-rag-retrieval.md +531 -0
  78. data/docs/architecture/adrs/006-context-assembly.md +496 -0
  79. data/docs/architecture/adrs/007-eviction-strategy.md +645 -0
  80. data/docs/architecture/adrs/008-robot-identification.md +625 -0
  81. data/docs/architecture/adrs/009-never-forget.md +648 -0
  82. data/docs/architecture/adrs/010-redis-working-memory-rejected.md +323 -0
  83. data/docs/architecture/adrs/011-pgai-integration.md +494 -0
  84. data/docs/architecture/adrs/index.md +215 -0
  85. data/docs/architecture/hive-mind.md +736 -0
  86. data/docs/architecture/index.md +351 -0
  87. data/docs/architecture/overview.md +538 -0
  88. data/docs/architecture/two-tier-memory.md +873 -0
  89. data/docs/assets/css/custom.css +83 -0
  90. data/docs/assets/images/htm-core-components.svg +63 -0
  91. data/docs/assets/images/htm-database-schema.svg +93 -0
  92. data/docs/assets/images/htm-hive-mind-architecture.svg +125 -0
  93. data/docs/assets/images/htm-importance-scoring-framework.svg +83 -0
  94. data/docs/assets/images/htm-layered-architecture.svg +71 -0
  95. data/docs/assets/images/htm-long-term-memory-architecture.svg +115 -0
  96. data/docs/assets/images/htm-working-memory-architecture.svg +120 -0
  97. data/docs/assets/images/htm.jpg +0 -0
  98. data/docs/assets/images/htm_demo.gif +0 -0
  99. data/docs/assets/js/mathjax.js +18 -0
  100. data/docs/assets/videos/htm_video.mp4 +0 -0
  101. data/docs/database_rake_tasks.md +322 -0
  102. data/docs/development/contributing.md +787 -0
  103. data/docs/development/index.md +336 -0
  104. data/docs/development/schema.md +596 -0
  105. data/docs/development/setup.md +719 -0
  106. data/docs/development/testing.md +819 -0
  107. data/docs/guides/adding-memories.md +824 -0
  108. data/docs/guides/context-assembly.md +1009 -0
  109. data/docs/guides/getting-started.md +577 -0
  110. data/docs/guides/index.md +118 -0
  111. data/docs/guides/long-term-memory.md +941 -0
  112. data/docs/guides/multi-robot.md +866 -0
  113. data/docs/guides/recalling-memories.md +927 -0
  114. data/docs/guides/search-strategies.md +953 -0
  115. data/docs/guides/working-memory.md +717 -0
  116. data/docs/index.md +214 -0
  117. data/docs/installation.md +477 -0
  118. data/docs/multi_framework_support.md +519 -0
  119. data/docs/quick-start.md +655 -0
  120. data/docs/setup_local_database.md +302 -0
  121. data/docs/using_rake_tasks_in_your_app.md +383 -0
  122. data/examples/basic_usage.rb +93 -0
  123. data/examples/cli_app/README.md +317 -0
  124. data/examples/cli_app/htm_cli.rb +270 -0
  125. data/examples/custom_llm_configuration.rb +183 -0
  126. data/examples/example_app/Rakefile +71 -0
  127. data/examples/example_app/app.rb +206 -0
  128. data/examples/sinatra_app/Gemfile +21 -0
  129. data/examples/sinatra_app/app.rb +335 -0
  130. data/lib/htm/active_record_config.rb +113 -0
  131. data/lib/htm/configuration.rb +342 -0
  132. data/lib/htm/database.rb +594 -0
  133. data/lib/htm/embedding_service.rb +115 -0
  134. data/lib/htm/errors.rb +34 -0
  135. data/lib/htm/job_adapter.rb +154 -0
  136. data/lib/htm/jobs/generate_embedding_job.rb +65 -0
  137. data/lib/htm/jobs/generate_tags_job.rb +82 -0
  138. data/lib/htm/long_term_memory.rb +965 -0
  139. data/lib/htm/models/node.rb +109 -0
  140. data/lib/htm/models/node_tag.rb +33 -0
  141. data/lib/htm/models/robot.rb +52 -0
  142. data/lib/htm/models/tag.rb +76 -0
  143. data/lib/htm/railtie.rb +76 -0
  144. data/lib/htm/sinatra.rb +157 -0
  145. data/lib/htm/tag_service.rb +135 -0
  146. data/lib/htm/tasks.rb +38 -0
  147. data/lib/htm/version.rb +5 -0
  148. data/lib/htm/working_memory.rb +182 -0
  149. data/lib/htm.rb +400 -0
  150. data/lib/tasks/db.rake +19 -0
  151. data/lib/tasks/htm.rake +147 -0
  152. data/lib/tasks/jobs.rake +312 -0
  153. data/mkdocs.yml +190 -0
  154. data/scripts/install_local_database.sh +309 -0
  155. metadata +341 -0
@@ -0,0 +1,824 @@
1
+ # Adding Memories to HTM
2
+
3
+ This guide covers everything you need to know about storing information in HTM effectively.
4
+
5
+ ## Basic Usage
6
+
7
+ The primary method for adding memories is `add_node`:
8
+
9
+ ```ruby
10
+ node_id = htm.add_node(
11
+ key, # Unique identifier
12
+ value, # Content (string)
13
+ type: :fact, # Memory type
14
+ category: nil, # Optional category
15
+ importance: 1.0, # Importance score (0.0-10.0)
16
+ related_to: [], # Array of related node keys
17
+ tags: [] # Array of tags
18
+ )
19
+ ```
20
+
21
+ The method returns the database ID of the created node.
22
+
23
+ ## Memory Types Deep Dive
24
+
25
+ HTM supports six memory types, each optimized for specific use cases.
26
+
27
+ ### :fact - Immutable Facts
28
+
29
+ Facts are unchanging truths about the world, users, or systems.
30
+
31
+ ```ruby
32
+ # User information
33
+ htm.add_node(
34
+ "user_name",
35
+ "The user's name is Alice Thompson",
36
+ type: :fact,
37
+ importance: 9.0,
38
+ tags: ["user", "identity"]
39
+ )
40
+
41
+ # System configuration
42
+ htm.add_node(
43
+ "system_timezone",
44
+ "System timezone is UTC",
45
+ type: :fact,
46
+ importance: 6.0,
47
+ tags: ["system", "config"]
48
+ )
49
+
50
+ # Domain knowledge
51
+ htm.add_node(
52
+ "fact_photosynthesis",
53
+ "Photosynthesis converts light energy into chemical energy in plants",
54
+ type: :fact,
55
+ importance: 7.0,
56
+ tags: ["biology", "science"]
57
+ )
58
+ ```
59
+
60
+ !!! tip "When to Use :fact"
61
+ - User profile information (name, email, preferences)
62
+ - System configuration that rarely changes
63
+ - Scientific facts or domain knowledge
64
+ - Historical events
65
+ - API endpoints and credentials
66
+
67
+ ### :context - Conversation State
68
+
69
+ Context captures the current state of conversations or sessions.
70
+
71
+ ```ruby
72
+ # Current conversation topic
73
+ htm.add_node(
74
+ "context_#{session_id}_001",
75
+ "User is asking about database performance optimization",
76
+ type: :context,
77
+ importance: 6.0,
78
+ tags: ["conversation", "current"]
79
+ )
80
+
81
+ # Conversation mood
82
+ htm.add_node(
83
+ "context_mood",
84
+ "User seems frustrated with slow query times",
85
+ type: :context,
86
+ importance: 7.0,
87
+ tags: ["conversation", "sentiment"]
88
+ )
89
+
90
+ # Current task
91
+ htm.add_node(
92
+ "context_task",
93
+ "Helping user optimize their PostgreSQL queries",
94
+ type: :context,
95
+ importance: 8.0,
96
+ tags: ["task", "active"]
97
+ )
98
+ ```
99
+
100
+ !!! tip "When to Use :context"
101
+ - Current conversation topics
102
+ - Session state
103
+ - Temporary workflow status
104
+ - User's current goals or questions
105
+ - Conversation sentiment or mood
106
+
107
+ !!! note
108
+ Context memories are typically lower importance (4-6) since they become outdated quickly. They'll naturally get evicted from working memory as new context arrives.
109
+
110
+ ### :code - Code Snippets and Patterns
111
+
112
+ Store code examples, patterns, and technical solutions.
113
+
114
+ ```ruby
115
+ # Function example
116
+ htm.add_node(
117
+ "code_date_parser",
118
+ <<~CODE,
119
+ def parse_date(date_string)
120
+ Date.parse(date_string)
121
+ rescue ArgumentError
122
+ nil
123
+ end
124
+ CODE
125
+ type: :code,
126
+ importance: 6.0,
127
+ tags: ["ruby", "date", "parsing"]
128
+ )
129
+
130
+ # SQL query pattern
131
+ htm.add_node(
132
+ "code_user_query",
133
+ <<~SQL,
134
+ SELECT u.id, u.name, COUNT(o.id) as order_count
135
+ FROM users u
136
+ LEFT JOIN orders o ON u.id = o.user_id
137
+ GROUP BY u.id, u.name
138
+ HAVING COUNT(o.id) > 10
139
+ SQL
140
+ type: :code,
141
+ category: "sql",
142
+ importance: 7.0,
143
+ tags: ["sql", "aggregation", "joins"]
144
+ )
145
+
146
+ # Configuration example
147
+ htm.add_node(
148
+ "code_redis_config",
149
+ <<~YAML,
150
+ redis:
151
+ host: localhost
152
+ port: 6379
153
+ pool_size: 5
154
+ timeout: 2
155
+ YAML
156
+ type: :code,
157
+ category: "config",
158
+ importance: 5.0,
159
+ tags: ["redis", "configuration", "yaml"]
160
+ )
161
+ ```
162
+
163
+ !!! tip "When to Use :code"
164
+ - Reusable code snippets
165
+ - Configuration examples
166
+ - SQL queries and patterns
167
+ - API request/response examples
168
+ - Algorithm implementations
169
+ - Regular expressions
170
+
171
+ ### :preference - User Preferences
172
+
173
+ Store user preferences and settings.
174
+
175
+ ```ruby
176
+ # Communication style
177
+ htm.add_node(
178
+ "pref_communication",
179
+ "User prefers concise answers with bullet points",
180
+ type: :preference,
181
+ importance: 8.0,
182
+ tags: ["user", "communication", "style"]
183
+ )
184
+
185
+ # Technical preferences
186
+ htm.add_node(
187
+ "pref_language",
188
+ "User prefers Ruby over Python for scripting tasks",
189
+ type: :preference,
190
+ importance: 7.0,
191
+ tags: ["user", "programming", "language"]
192
+ )
193
+
194
+ # UI preferences
195
+ htm.add_node(
196
+ "pref_theme",
197
+ "User uses dark theme in their IDE",
198
+ type: :preference,
199
+ importance: 4.0,
200
+ tags: ["user", "ui", "theme"]
201
+ )
202
+
203
+ # Work preferences
204
+ htm.add_node(
205
+ "pref_working_hours",
206
+ "User typically codes in the morning, prefers design work in afternoon",
207
+ type: :preference,
208
+ importance: 5.0,
209
+ tags: ["user", "schedule", "productivity"]
210
+ )
211
+ ```
212
+
213
+ !!! tip "When to Use :preference"
214
+ - Communication style preferences
215
+ - Technical tool preferences
216
+ - UI/UX preferences
217
+ - Work habits and patterns
218
+ - Learning style preferences
219
+
220
+ ### :decision - Architectural Decisions
221
+
222
+ Track important decisions with rationale.
223
+
224
+ ```ruby
225
+ # Technology choice
226
+ htm.add_node(
227
+ "decision_database",
228
+ <<~DECISION,
229
+ Decision: Use PostgreSQL with TimescaleDB for HTM storage
230
+
231
+ Rationale:
232
+ - Excellent time-series optimization
233
+ - Native vector search with pgvector
234
+ - Strong consistency guarantees
235
+ - Mature ecosystem
236
+
237
+ Alternatives considered:
238
+ - MongoDB (rejected: eventual consistency issues)
239
+ - Redis (rejected: limited persistence)
240
+ DECISION
241
+ type: :decision,
242
+ category: "architecture",
243
+ importance: 9.5,
244
+ tags: ["architecture", "database", "timescaledb"]
245
+ )
246
+
247
+ # Design pattern choice
248
+ htm.add_node(
249
+ "decision_memory_architecture",
250
+ <<~DECISION,
251
+ Decision: Implement two-tier memory (working + long-term)
252
+
253
+ Rationale:
254
+ - Working memory provides fast access
255
+ - Long-term memory ensures durability
256
+ - Mirrors human memory architecture
257
+ - Allows token-limited LLM context
258
+
259
+ Trade-offs:
260
+ - Added complexity in synchronization
261
+ - Eviction strategy needs tuning
262
+ DECISION
263
+ type: :decision,
264
+ category: "architecture",
265
+ importance: 10.0,
266
+ tags: ["architecture", "memory", "design-pattern"]
267
+ )
268
+
269
+ # Process decision
270
+ htm.add_node(
271
+ "decision_testing",
272
+ "Decided to use Minitest over RSpec for simplicity and speed",
273
+ type: :decision,
274
+ category: "process",
275
+ importance: 6.0,
276
+ tags: ["testing", "tools"]
277
+ )
278
+ ```
279
+
280
+ !!! tip "When to Use :decision"
281
+ - Technology selections
282
+ - Architecture patterns
283
+ - API design choices
284
+ - Process decisions
285
+ - Trade-off analysis results
286
+
287
+ !!! note "Decision Template"
288
+ Include: what was decided, why, alternatives considered, and trade-offs. This context helps future decision-making.
289
+
290
+ ### :question - Unresolved Questions
291
+
292
+ Track questions that need answering.
293
+
294
+ ```ruby
295
+ # Technical question
296
+ htm.add_node(
297
+ "question_caching",
298
+ "Should we implement Redis caching for frequently accessed memories?",
299
+ type: :question,
300
+ importance: 7.0,
301
+ tags: ["performance", "caching", "open"]
302
+ )
303
+
304
+ # Design question
305
+ htm.add_node(
306
+ "question_auth",
307
+ "How should we handle authentication for multi-robot scenarios?",
308
+ type: :question,
309
+ importance: 8.0,
310
+ tags: ["security", "architecture", "open"]
311
+ )
312
+
313
+ # Research question
314
+ htm.add_node(
315
+ "question_embeddings",
316
+ "Would fine-tuning embeddings on our domain improve recall accuracy?",
317
+ type: :question,
318
+ importance: 6.0,
319
+ tags: ["embeddings", "research", "open"]
320
+ )
321
+ ```
322
+
323
+ !!! tip "When to Use :question"
324
+ - Open technical questions
325
+ - Design uncertainties
326
+ - Research topics to investigate
327
+ - Feature requests to evaluate
328
+ - Performance questions
329
+
330
+ !!! tip "Closing Questions"
331
+ When a question is answered, add a related decision node and mark the question as resolved by updating its tags.
332
+
333
+ ## Importance Scoring Guidelines
334
+
335
+ The importance score (0.0-10.0) determines memory retention and eviction priority.
336
+
337
+ ![Importance Scoring Framework](../assets/images/htm-importance-scoring-framework.svg)
338
+
339
+ ### Scoring Framework
340
+
341
+ ```ruby
342
+ # Critical (9.0-10.0): Must never lose
343
+ htm.add_node("api_key", "Production API key: ...", importance: 10.0)
344
+ htm.add_node("decision_architecture", "Core architecture decision", importance: 9.5)
345
+
346
+ # High (7.0-8.9): Very important, high retention
347
+ htm.add_node("user_identity", "User's name and email", importance: 8.0)
348
+ htm.add_node("major_decision", "Chose Rails for web framework", importance: 7.5)
349
+
350
+ # Medium (4.0-6.9): Moderately important
351
+ htm.add_node("code_snippet", "Useful utility function", importance: 6.0)
352
+ htm.add_node("context_current", "Current conversation topic", importance: 5.0)
353
+ htm.add_node("preference_minor", "Prefers tabs over spaces", importance: 4.0)
354
+
355
+ # Low (1.0-3.9): Nice to have, can evict
356
+ htm.add_node("temp_note", "Check logs later", importance: 3.0)
357
+ htm.add_node("minor_context", "Mentioned weather briefly", importance: 2.0)
358
+ htm.add_node("throwaway", "Temporary calculation result", importance: 1.0)
359
+ ```
360
+
361
+ ### Importance by Type
362
+
363
+ Typical importance ranges for each type:
364
+
365
+ | Type | Typical Range | Example |
366
+ |------|---------------|---------|
367
+ | `:fact` | 7.0-10.0 | User identity, system facts |
368
+ | `:decision` | 7.0-10.0 | Architecture, major choices |
369
+ | `:preference` | 4.0-8.0 | User preferences |
370
+ | `:code` | 4.0-7.0 | Code snippets, examples |
371
+ | `:context` | 3.0-6.0 | Conversation state |
372
+ | `:question` | 5.0-8.0 | Open questions |
373
+
374
+ !!! warning "Importance Affects Eviction"
375
+ When working memory is full, HTM evicts memories with lower importance first. Set importance thoughtfully based on long-term value.
376
+
377
+ ## Adding Relationships
378
+
379
+ Link related memories to build a knowledge graph:
380
+
381
+ ```ruby
382
+ # Add a decision
383
+ htm.add_node(
384
+ "decision_database",
385
+ "Use PostgreSQL for data storage",
386
+ type: :decision,
387
+ importance: 9.0
388
+ )
389
+
390
+ # Add related implementation code
391
+ htm.add_node(
392
+ "code_db_connection",
393
+ "PG.connect(ENV['DATABASE_URL'])",
394
+ type: :code,
395
+ importance: 6.0,
396
+ related_to: ["decision_database"]
397
+ )
398
+
399
+ # Add related configuration
400
+ htm.add_node(
401
+ "fact_db_config",
402
+ "Database uses connection pool of size 5",
403
+ type: :fact,
404
+ importance: 7.0,
405
+ related_to: ["decision_database", "code_db_connection"]
406
+ )
407
+ ```
408
+
409
+ !!! tip "Relationship Patterns"
410
+ - Link implementation code to decisions
411
+ - Connect questions to related facts
412
+ - Link preferences to user facts
413
+ - Connect related decisions (e.g., database choice → ORM choice)
414
+
415
+ ## Categorization with Tags
416
+
417
+ Tags enable flexible organization and retrieval:
418
+
419
+ ```ruby
420
+ # Use multiple tags for rich categorization
421
+ htm.add_node(
422
+ "decision_api_design",
423
+ "RESTful API with JSON responses",
424
+ type: :decision,
425
+ importance: 8.0,
426
+ tags: [
427
+ "api", # Domain
428
+ "rest", # Approach
429
+ "architecture", # Category
430
+ "backend", # Layer
431
+ "json", # Format
432
+ "http" # Protocol
433
+ ]
434
+ )
435
+ ```
436
+
437
+ ### Tag Naming Conventions
438
+
439
+ ```ruby
440
+ # Good: Consistent, lowercase, descriptive
441
+ tags: ["user", "authentication", "security", "oauth"]
442
+
443
+ # Avoid: Inconsistent casing, vague terms
444
+ tags: ["User", "auth", "stuff", "misc"]
445
+ ```
446
+
447
+ ### Common Tag Patterns
448
+
449
+ ```ruby
450
+ # Domain tags
451
+ tags: ["database", "api", "ui", "auth", "billing"]
452
+
453
+ # Layer tags
454
+ tags: ["frontend", "backend", "infrastructure", "data"]
455
+
456
+ # Status tags
457
+ tags: ["active", "deprecated", "experimental", "stable"]
458
+
459
+ # Priority tags
460
+ tags: ["critical", "high-priority", "low-priority"]
461
+
462
+ # Project tags
463
+ tags: ["project-alpha", "project-beta"]
464
+ ```
465
+
466
+ ## Advanced Patterns
467
+
468
+ ### Timestamped Entries
469
+
470
+ Create time-series logs:
471
+
472
+ ```ruby
473
+ def log_event(event_type, description)
474
+ timestamp = Time.now.to_i
475
+
476
+ htm.add_node(
477
+ "event_#{event_type}_#{timestamp}",
478
+ "#{event_type.upcase}: #{description}",
479
+ type: :context,
480
+ importance: 5.0,
481
+ tags: ["event", event_type, "log"]
482
+ )
483
+ end
484
+
485
+ log_event("error", "Database connection timeout")
486
+ log_event("performance", "Query took 3.2 seconds")
487
+ ```
488
+
489
+ ### Versioned Information
490
+
491
+ Track changes over time:
492
+
493
+ ```ruby
494
+ def update_fact(base_key, new_value, version)
495
+ # Add versioned node
496
+ htm.add_node(
497
+ "#{base_key}_v#{version}",
498
+ new_value,
499
+ type: :fact,
500
+ importance: 8.0,
501
+ tags: ["versioned", "v#{version}"],
502
+ related_to: version > 1 ? ["#{base_key}_v#{version-1}"] : []
503
+ )
504
+ end
505
+
506
+ update_fact("user_email", "alice@example.com", 1)
507
+ update_fact("user_email", "alice@newdomain.com", 2)
508
+ ```
509
+
510
+ ### Compound Memories
511
+
512
+ Store structured information:
513
+
514
+ ```ruby
515
+ # User profile as compound memory
516
+ user_profile = {
517
+ name: "Alice Thompson",
518
+ email: "alice@example.com",
519
+ role: "Senior Engineer",
520
+ joined: "2023-01-15"
521
+ }.map { |k, v| "#{k}: #{v}" }.join("\n")
522
+
523
+ htm.add_node(
524
+ "user_profile_001",
525
+ user_profile,
526
+ type: :fact,
527
+ importance: 9.0,
528
+ tags: ["user", "profile", "complete"]
529
+ )
530
+ ```
531
+
532
+ ### Conditional Importance
533
+
534
+ Adjust importance based on context:
535
+
536
+ ```ruby
537
+ def add_memory_with_context(key, value, type, base_importance, current_project)
538
+ # Boost importance for current project
539
+ importance = base_importance
540
+ importance += 2.0 if tags.include?(current_project)
541
+ importance = [importance, 10.0].min # Cap at 10.0
542
+
543
+ htm.add_node(
544
+ key,
545
+ value,
546
+ type: type,
547
+ importance: importance,
548
+ tags: [current_project, type.to_s]
549
+ )
550
+ end
551
+ ```
552
+
553
+ ## Best Practices
554
+
555
+ ### 1. Use Descriptive Keys
556
+
557
+ ```ruby
558
+ # Good: Descriptive and namespaced
559
+ "user_profile_alice_001"
560
+ "decision_database_selection"
561
+ "code_authentication_jwt"
562
+
563
+ # Bad: Vague or collision-prone
564
+ "profile"
565
+ "dec1"
566
+ "code"
567
+ ```
568
+
569
+ ### 2. Be Consistent with Categories
570
+
571
+ ```ruby
572
+ # Define standard categories
573
+ CATEGORIES = {
574
+ architecture: "architecture",
575
+ security: "security",
576
+ performance: "performance",
577
+ ui: "user-interface"
578
+ }
579
+
580
+ htm.add_node(
581
+ key, value,
582
+ category: CATEGORIES[:architecture]
583
+ )
584
+ ```
585
+
586
+ ### 3. Include Context in Values
587
+
588
+ ```ruby
589
+ # Good: Self-contained
590
+ htm.add_node(
591
+ "decision_001",
592
+ "Decided to use Redis for session storage because it provides fast access and automatic expiration",
593
+ type: :decision
594
+ )
595
+
596
+ # Bad: Requires external context
597
+ htm.add_node(
598
+ "decision_001",
599
+ "Use Redis", # Why? For what?
600
+ type: :decision
601
+ )
602
+ ```
603
+
604
+ ### 4. Tag Generously
605
+
606
+ ```ruby
607
+ # Good: Rich tags for multiple retrieval paths
608
+ htm.add_node(
609
+ "code_api_auth",
610
+ "...",
611
+ tags: ["api", "authentication", "security", "jwt", "middleware", "ruby"]
612
+ )
613
+
614
+ # Suboptimal: Minimal tags
615
+ htm.add_node(
616
+ "code_api_auth",
617
+ "...",
618
+ tags: ["code"]
619
+ )
620
+ ```
621
+
622
+ ### 5. Use Relationships to Build Context
623
+
624
+ ```ruby
625
+ # Create a narrative with relationships
626
+ decision_id = htm.add_node("decision_api", "Use GraphQL", type: :decision)
627
+
628
+ htm.add_node(
629
+ "question_api",
630
+ "How to handle file uploads in GraphQL?",
631
+ type: :question,
632
+ related_to: ["decision_api"]
633
+ )
634
+
635
+ htm.add_node(
636
+ "code_upload",
637
+ "GraphQL upload implementation",
638
+ type: :code,
639
+ related_to: ["decision_api", "question_api"]
640
+ )
641
+ ```
642
+
643
+ ## Common Pitfalls
644
+
645
+ ### Pitfall 1: Duplicate Keys
646
+
647
+ ```ruby
648
+ # This will fail - keys must be unique
649
+ htm.add_node("user_001", "Alice")
650
+ htm.add_node("user_001", "Bob") # Error: key already exists
651
+ ```
652
+
653
+ **Solution**: Use unique keys with timestamps or UUIDs:
654
+
655
+ ```ruby
656
+ require 'securerandom'
657
+
658
+ htm.add_node("user_#{SecureRandom.hex(4)}", "Alice")
659
+ htm.add_node("user_#{SecureRandom.hex(4)}", "Bob")
660
+ ```
661
+
662
+ ### Pitfall 2: Too-High Importance
663
+
664
+ ```ruby
665
+ # Don't make everything critical
666
+ htm.add_node("note", "Random thought", importance: 10.0) # Too high!
667
+ ```
668
+
669
+ **Solution**: Reserve high importance (9-10) for truly critical data.
670
+
671
+ ### Pitfall 3: Missing Context
672
+
673
+ ```ruby
674
+ # Bad: No context
675
+ htm.add_node("decision", "Chose option A", type: :decision)
676
+
677
+ # Good: Include rationale
678
+ htm.add_node(
679
+ "decision_auth",
680
+ "Chose OAuth 2.0 for authentication because it provides better security and is industry standard",
681
+ type: :decision
682
+ )
683
+ ```
684
+
685
+ ### Pitfall 4: No Tags
686
+
687
+ ```ruby
688
+ # Harder to find later
689
+ htm.add_node("code_001", "def foo...", type: :code)
690
+
691
+ # Better: Tags enable multiple retrieval paths
692
+ htm.add_node(
693
+ "code_001",
694
+ "def foo...",
695
+ type: :code,
696
+ tags: ["ruby", "functions", "utilities"]
697
+ )
698
+ ```
699
+
700
+ ## Performance Considerations
701
+
702
+ ### Batch Operations
703
+
704
+ When adding many memories, consider transaction efficiency:
705
+
706
+ ```ruby
707
+ # Instead of many individual adds
708
+ memories = [
709
+ {key: "fact_001", value: "...", type: :fact},
710
+ {key: "fact_002", value: "...", type: :fact},
711
+ # ... many more
712
+ ]
713
+
714
+ # Add them efficiently
715
+ memories.each do |m|
716
+ htm.add_node(m[:key], m[:value], type: m[:type], importance: m[:importance])
717
+ end
718
+ ```
719
+
720
+ !!! note
721
+ Each `add_node` call generates embeddings via Ollama. For large batches, this can take time. Consider adding in the background or showing progress.
722
+
723
+ ### Embedding Generation
724
+
725
+ Embedding generation has a cost:
726
+
727
+ ```ruby
728
+ # Short text: Fast (~50ms)
729
+ htm.add_node("fact", "User name is Alice", ...)
730
+
731
+ # Long text: Slower (~500ms)
732
+ htm.add_node("code", "..." * 1000, ...) # 1000 chars
733
+ ```
734
+
735
+ !!! tip
736
+ For very long content (>1000 tokens), consider splitting into multiple nodes or summarizing.
737
+
738
+ ## Next Steps
739
+
740
+ Now that you know how to add memories effectively, learn about:
741
+
742
+ - [**Recalling Memories**](recalling-memories.md) - Search and retrieve memories
743
+ - [**Search Strategies**](search-strategies.md) - Optimize retrieval with different strategies
744
+ - [**Context Assembly**](context-assembly.md) - Use memories with your LLM
745
+
746
+ ## Complete Example
747
+
748
+ ```ruby
749
+ require 'htm'
750
+
751
+ htm = HTM.new(robot_name: "Memory Demo")
752
+
753
+ # Add a fact with rich metadata
754
+ htm.add_node(
755
+ "user_profile",
756
+ "Alice Thompson is a senior software engineer specializing in distributed systems",
757
+ type: :fact,
758
+ category: "user",
759
+ importance: 9.0,
760
+ tags: ["user", "profile", "engineering"]
761
+ )
762
+
763
+ # Add a related preference
764
+ htm.add_node(
765
+ "user_pref_tools",
766
+ "Alice prefers Vim for editing and tmux for terminal management",
767
+ type: :preference,
768
+ importance: 7.0,
769
+ tags: ["user", "tools", "preferences"],
770
+ related_to: ["user_profile"]
771
+ )
772
+
773
+ # Add a decision with context
774
+ htm.add_node(
775
+ "decision_messaging",
776
+ <<~DECISION,
777
+ Decision: Use RabbitMQ for async job processing
778
+
779
+ Rationale:
780
+ - Need reliable message delivery
781
+ - Support for multiple consumer patterns
782
+ - Excellent Ruby client library
783
+
784
+ Alternatives:
785
+ - Redis (simpler but less reliable)
786
+ - Kafka (overkill for our scale)
787
+ DECISION
788
+ type: :decision,
789
+ category: "architecture",
790
+ importance: 8.5,
791
+ tags: ["architecture", "messaging", "rabbitmq", "async"]
792
+ )
793
+
794
+ # Add implementation code
795
+ htm.add_node(
796
+ "code_rabbitmq_setup",
797
+ <<~RUBY,
798
+ require 'bunny'
799
+
800
+ connection = Bunny.new(ENV['RABBITMQ_URL'])
801
+ connection.start
802
+
803
+ channel = connection.create_channel
804
+ queue = channel.queue('jobs', durable: true)
805
+ RUBY
806
+ type: :code,
807
+ importance: 6.0,
808
+ tags: ["ruby", "rabbitmq", "setup", "code"],
809
+ related_to: ["decision_messaging"]
810
+ )
811
+
812
+ # Add an open question
813
+ htm.add_node(
814
+ "question_scaling",
815
+ "Should we implement message partitioning for better scaling?",
816
+ type: :question,
817
+ importance: 7.0,
818
+ tags: ["rabbitmq", "scaling", "performance", "open"],
819
+ related_to: ["decision_messaging"]
820
+ )
821
+
822
+ puts "Added 5 memories with relationships and rich metadata"
823
+ puts "Stats: #{htm.memory_stats[:total_nodes]} total nodes"
824
+ ```