htm 0.0.11 → 0.0.15

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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/.dictate.toml +46 -0
  3. data/.envrc +2 -0
  4. data/CHANGELOG.md +85 -2
  5. data/README.md +348 -79
  6. data/Rakefile +14 -2
  7. data/bin/htm_mcp.rb +94 -0
  8. data/config/database.yml +20 -13
  9. data/db/migrate/00003_create_file_sources.rb +5 -0
  10. data/db/migrate/00004_create_nodes.rb +17 -0
  11. data/db/migrate/00005_create_tags.rb +7 -0
  12. data/db/migrate/00006_create_node_tags.rb +2 -0
  13. data/db/migrate/00007_create_robot_nodes.rb +7 -0
  14. data/db/schema.sql +69 -100
  15. data/docs/api/index.md +1 -1
  16. data/docs/api/yard/HTM/Configuration.md +54 -0
  17. data/docs/api/yard/HTM/Database.md +13 -10
  18. data/docs/api/yard/HTM/EmbeddingService.md +5 -1
  19. data/docs/api/yard/HTM/LongTermMemory.md +18 -277
  20. data/docs/api/yard/HTM/PropositionError.md +18 -0
  21. data/docs/api/yard/HTM/PropositionService.md +66 -0
  22. data/docs/api/yard/HTM/QueryCache.md +88 -0
  23. data/docs/api/yard/HTM/RobotGroup.md +481 -0
  24. data/docs/api/yard/HTM/SqlBuilder.md +108 -0
  25. data/docs/api/yard/HTM/TagService.md +4 -0
  26. data/docs/api/yard/HTM/Telemetry/NullInstrument.md +13 -0
  27. data/docs/api/yard/HTM/Telemetry/NullMeter.md +15 -0
  28. data/docs/api/yard/HTM/Telemetry.md +109 -0
  29. data/docs/api/yard/HTM/WorkingMemoryChannel.md +176 -0
  30. data/docs/api/yard/HTM.md +8 -22
  31. data/docs/api/yard/index.csv +102 -25
  32. data/docs/api/yard-reference.md +8 -0
  33. data/docs/architecture/index.md +1 -1
  34. data/docs/assets/images/multi-provider-failover.svg +51 -0
  35. data/docs/assets/images/robot-group-architecture.svg +65 -0
  36. data/docs/database/README.md +3 -3
  37. data/docs/database/public.file_sources.svg +29 -21
  38. data/docs/database/public.node_tags.md +2 -0
  39. data/docs/database/public.node_tags.svg +53 -41
  40. data/docs/database/public.nodes.md +2 -0
  41. data/docs/database/public.nodes.svg +52 -40
  42. data/docs/database/public.robot_nodes.md +2 -0
  43. data/docs/database/public.robot_nodes.svg +30 -22
  44. data/docs/database/public.robots.svg +16 -12
  45. data/docs/database/public.tags.md +3 -0
  46. data/docs/database/public.tags.svg +41 -33
  47. data/docs/database/schema.json +66 -0
  48. data/docs/database/schema.svg +60 -48
  49. data/docs/development/index.md +14 -1
  50. data/docs/development/rake-tasks.md +1068 -0
  51. data/docs/getting-started/index.md +1 -1
  52. data/docs/getting-started/quick-start.md +144 -155
  53. data/docs/guides/adding-memories.md +2 -3
  54. data/docs/guides/context-assembly.md +185 -184
  55. data/docs/guides/getting-started.md +154 -148
  56. data/docs/guides/index.md +8 -1
  57. data/docs/guides/long-term-memory.md +60 -92
  58. data/docs/guides/mcp-server.md +617 -0
  59. data/docs/guides/multi-robot.md +249 -345
  60. data/docs/guides/recalling-memories.md +153 -163
  61. data/docs/guides/robot-groups.md +604 -0
  62. data/docs/guides/search-strategies.md +61 -58
  63. data/docs/guides/working-memory.md +103 -136
  64. data/docs/images/telemetry-architecture.svg +153 -0
  65. data/docs/index.md +30 -26
  66. data/docs/telemetry.md +391 -0
  67. data/examples/README.md +46 -1
  68. data/examples/cli_app/README.md +1 -1
  69. data/examples/cli_app/htm_cli.rb +1 -1
  70. data/examples/robot_groups/robot_worker.rb +1 -2
  71. data/examples/robot_groups/same_process.rb +1 -4
  72. data/examples/sinatra_app/app.rb +1 -1
  73. data/examples/telemetry/README.md +147 -0
  74. data/examples/telemetry/SETUP_README.md +169 -0
  75. data/examples/telemetry/demo.rb +498 -0
  76. data/examples/telemetry/grafana/dashboards/htm-metrics.json +457 -0
  77. data/lib/htm/configuration.rb +261 -70
  78. data/lib/htm/database.rb +46 -22
  79. data/lib/htm/embedding_service.rb +24 -14
  80. data/lib/htm/errors.rb +15 -1
  81. data/lib/htm/jobs/generate_embedding_job.rb +19 -0
  82. data/lib/htm/jobs/generate_propositions_job.rb +103 -0
  83. data/lib/htm/jobs/generate_tags_job.rb +24 -0
  84. data/lib/htm/loaders/markdown_chunker.rb +79 -0
  85. data/lib/htm/loaders/markdown_loader.rb +41 -15
  86. data/lib/htm/long_term_memory/fulltext_search.rb +138 -0
  87. data/lib/htm/long_term_memory/hybrid_search.rb +324 -0
  88. data/lib/htm/long_term_memory/node_operations.rb +209 -0
  89. data/lib/htm/long_term_memory/relevance_scorer.rb +355 -0
  90. data/lib/htm/long_term_memory/robot_operations.rb +34 -0
  91. data/lib/htm/long_term_memory/tag_operations.rb +428 -0
  92. data/lib/htm/long_term_memory/vector_search.rb +109 -0
  93. data/lib/htm/long_term_memory.rb +51 -1153
  94. data/lib/htm/models/node.rb +35 -2
  95. data/lib/htm/models/node_tag.rb +31 -0
  96. data/lib/htm/models/robot_node.rb +31 -0
  97. data/lib/htm/models/tag.rb +44 -0
  98. data/lib/htm/proposition_service.rb +169 -0
  99. data/lib/htm/query_cache.rb +214 -0
  100. data/lib/htm/robot_group.rb +721 -0
  101. data/lib/htm/sql_builder.rb +178 -0
  102. data/lib/htm/tag_service.rb +16 -6
  103. data/lib/htm/tasks.rb +8 -2
  104. data/lib/htm/telemetry.rb +224 -0
  105. data/lib/htm/version.rb +1 -1
  106. data/lib/htm/working_memory_channel.rb +250 -0
  107. data/lib/htm.rb +66 -3
  108. data/lib/tasks/doc.rake +1 -1
  109. data/lib/tasks/htm.rake +259 -13
  110. data/mkdocs.yml +98 -96
  111. metadata +55 -20
  112. data/.aigcm_msg +0 -1
  113. data/.claude/settings.local.json +0 -95
  114. data/CLAUDE.md +0 -603
  115. data/db/migrate/00009_add_working_memory_to_robot_nodes.rb +0 -12
  116. data/examples/cli_app/temp.log +0 -93
  117. data/examples/robot_groups/lib/robot_group.rb +0 -419
  118. data/examples/robot_groups/lib/working_memory_channel.rb +0 -140
  119. data/lib/htm/loaders/paragraph_chunker.rb +0 -112
  120. data/notes/ARCHITECTURE_REVIEW.md +0 -1167
  121. data/notes/IMPLEMENTATION_SUMMARY.md +0 -606
  122. data/notes/MULTI_FRAMEWORK_IMPLEMENTATION.md +0 -451
  123. data/notes/next_steps.md +0 -100
  124. data/notes/plan.md +0 -627
  125. data/notes/tag_ontology_enhancement_ideas.md +0 -222
  126. data/notes/timescaledb_removal_summary.md +0 -200
data/docs/index.md CHANGED
@@ -1,12 +1,12 @@
1
1
 
2
2
  <div align="center">
3
- <div style="background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%); border: 4px solid #ff0000; border-radius: 12px; padding: 20px; margin: 20px auto; max-width: 800px; box-shadow: 0 8px 16px rgba(255, 0, 0, 0.3);">
4
- <p style="color: #ffffff; font-size: 24px; font-weight: bold; margin: 0; text-shadow: 2px 2px 4px rgba(0,0,0,0.5);">
5
- ⚠️ WARNING ⚠️
3
+ <div style="background: linear-gradient(135deg, #ffd93d 0%, #f5c800 100%); border: 4px solid #e6b800; border-radius: 12px; padding: 20px; margin: 20px auto; max-width: 800px; box-shadow: 0 8px 16px rgba(230, 184, 0, 0.3);">
4
+ <p style="color: #000000; font-size: 42px; font-weight: bold; margin: 0;">
5
+ 💣 CAUTION 💣
6
6
  </p>
7
- <p style="color: #fff; font-size: 16px; margin: 10px 0 0 0; line-height: 1.6;">
8
- This documentation is AI-generated and may contain <strong>hallucinations</strong>, <strong>inaccuracies</strong>, or <strong>outdated information</strong>.<br/>
9
- Always verify critical details in the source code.
7
+ <p style="color: #000; font-size: 27px; font-weight: bold; margin: 10px 0 0 0; line-height: 1.6;">
8
+ This documentation may contain <strong>inaccuracies</strong>.<br/>
9
+ Verify critical details in the source code and example demos.
10
10
  </p>
11
11
  </div>
12
12
 
@@ -63,14 +63,14 @@ HTM enables multiple AI robots to share a collective memory:
63
63
  - Cross-robot context awareness and conversation continuity
64
64
  - Query conversation timelines across multiple robots
65
65
 
66
- ### Knowledge Graph
66
+ ### Pseudo Knowledge Graph
67
67
 
68
- Build rich relationship networks between memories:
68
+ Build rich relationship networks between memories using a hierarchical taxonomy:
69
69
 
70
70
  - Link related memories together
71
- - Tag-based categorization
71
+ - Tag-based categorization with up to four levels of abstraction
72
72
  - Importance scoring for prioritization
73
- - Navigate memory relationships programmatically
73
+ - Navigate memory relationship abstractions
74
74
 
75
75
  ## Quick Example
76
76
 
@@ -79,33 +79,36 @@ Here's how simple it is to get started with HTM:
79
79
  ```ruby
80
80
  require 'htm'
81
81
 
82
+ # Configure HTM globally (optional - uses Ollama by default)
83
+ HTM.configure do |config|
84
+ config.embedding_provider = :ollama
85
+ config.embedding_model = 'nomic-embed-text:latest'
86
+ config.tag_provider = :ollama
87
+ config.tag_model = 'gemma3:latest'
88
+ end
89
+
82
90
  # Initialize HTM for your robot
83
91
  htm = HTM.new(
84
- robot_name: "Code Helper",
85
- working_memory_size: 128_000, # 128k tokens
86
- embedding_service: :ollama, # Use Ollama for embeddings
87
- embedding_model: 'gpt-oss' # Default embedding model
92
+ robot_name: "Chat Assistant",
93
+ working_memory_size: 128_000 # 128k tokens
88
94
  )
89
95
 
90
- # Add memories (embeddings generated automatically)
91
- htm.add_node(
92
- "decision_001",
96
+ # Remember information (embeddings generated automatically in background)
97
+ node_id = htm.remember(
93
98
  "We decided to use PostgreSQL for HTM storage",
94
- type: :decision,
95
- category: "architecture",
96
- importance: 9.0,
97
- tags: ["database", "architecture"]
99
+ tags: ["database:postgresql", "architecture"],
100
+ metadata: { category: "architecture", priority: "high" }
98
101
  )
99
102
 
100
103
  # Recall memories from the past
101
104
  memories = htm.recall(
105
+ "database decisions", # Topic (first positional argument)
102
106
  timeframe: "last week",
103
- topic: "database decisions",
104
107
  strategy: :hybrid
105
108
  )
106
109
 
107
- # Create context for your LLM
108
- context = htm.create_context(
110
+ # Create context for your LLM from working memory
111
+ context = htm.working_memory.assemble_context(
109
112
  strategy: :balanced,
110
113
  max_tokens: 50_000
111
114
  )
@@ -117,8 +120,9 @@ response = llm.chat(
117
120
  user: "What database did we decide to use?"
118
121
  )
119
122
 
120
- # Explicit deletion only when needed
121
- htm.forget("old_decision", confirm: :confirmed)
123
+ # Explicit deletion only when needed (soft delete by default)
124
+ htm.forget(node_id) # Soft delete (recoverable)
125
+ htm.forget(node_id, soft: false, confirm: :confirmed) # Permanent delete
122
126
  ```
123
127
 
124
128
  ## Use Cases
data/docs/telemetry.md ADDED
@@ -0,0 +1,391 @@
1
+ # Telemetry (OpenTelemetry Metrics)
2
+
3
+ HTM includes optional OpenTelemetry-based metrics for production observability. This document provides detailed configuration and usage information.
4
+
5
+ ## Overview
6
+
7
+ HTM uses [OpenTelemetry](https://opentelemetry.io/) for metrics collection, the industry-standard observability framework. This provides:
8
+
9
+ - **Universal compatibility**: Works with 50+ observability backends
10
+ - **Zero vendor lock-in**: Emit standard OTLP, route anywhere
11
+ - **Zero overhead when disabled**: Null object pattern ensures no performance impact
12
+
13
+ ## Quick Start
14
+
15
+ ### 1. Install Dependencies
16
+
17
+ Add the OpenTelemetry gems to your Gemfile:
18
+
19
+ ```ruby
20
+ gem 'opentelemetry-sdk'
21
+ gem 'opentelemetry-metrics-sdk'
22
+ gem 'opentelemetry-exporter-otlp' # For OTLP export
23
+ ```
24
+
25
+ ### 2. Enable Telemetry
26
+
27
+ ```ruby
28
+ HTM.configure do |config|
29
+ config.telemetry_enabled = true
30
+ end
31
+ ```
32
+
33
+ Or via environment variable:
34
+
35
+ ```bash
36
+ export HTM_TELEMETRY_ENABLED="true"
37
+ ```
38
+
39
+ ### 3. Configure Destination
40
+
41
+ Set standard OpenTelemetry environment variables:
42
+
43
+ ```bash
44
+ export OTEL_METRICS_EXPORTER="otlp"
45
+ export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
46
+ ```
47
+
48
+ ## Configuration Options
49
+
50
+ ### HTM Configuration
51
+
52
+ | Option | Type | Default | Description |
53
+ |--------|------|---------|-------------|
54
+ | `telemetry_enabled` | Boolean | `false` | Enable/disable telemetry |
55
+
56
+ ```ruby
57
+ HTM.configure do |config|
58
+ config.telemetry_enabled = true
59
+ end
60
+ ```
61
+
62
+ ### Environment Variables
63
+
64
+ #### HTM-specific
65
+
66
+ | Variable | Default | Description |
67
+ |----------|---------|-------------|
68
+ | `HTM_TELEMETRY_ENABLED` | `false` | Enable telemetry (`true`/`false`) |
69
+
70
+ #### OpenTelemetry Standard
71
+
72
+ These are standard OpenTelemetry environment variables (not HTM-specific):
73
+
74
+ | Variable | Example | Description |
75
+ |----------|---------|-------------|
76
+ | `OTEL_SERVICE_NAME` | `htm` | Service name in telemetry data |
77
+ | `OTEL_METRICS_EXPORTER` | `otlp` | Metrics exporter type |
78
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4318` | OTLP collector endpoint |
79
+ | `OTEL_EXPORTER_OTLP_HEADERS` | `Authorization=Bearer token` | Headers for OTLP requests |
80
+
81
+ ## Available Metrics
82
+
83
+ ### htm.jobs (Counter)
84
+
85
+ Counts job executions by type and outcome.
86
+
87
+ **Attributes:**
88
+ - `job`: Job type (`embedding`, `tags`)
89
+ - `status`: Outcome (`success`, `error`, `circuit_open`)
90
+
91
+ **Example queries (PromQL):**
92
+ ```promql
93
+ # Jobs per minute by type
94
+ rate(htm_jobs_total[1m])
95
+
96
+ # Error rate for embedding jobs
97
+ rate(htm_jobs_total{job="embedding",status="error"}[5m])
98
+ / rate(htm_jobs_total{job="embedding"}[5m])
99
+ ```
100
+
101
+ ### htm.embedding.latency (Histogram)
102
+
103
+ Measures embedding generation time in milliseconds.
104
+
105
+ **Attributes:**
106
+ - `provider`: LLM provider (`ollama`, `openai`, etc.)
107
+ - `status`: Outcome (`success`, `error`)
108
+
109
+ **Example queries (PromQL):**
110
+ ```promql
111
+ # p95 embedding latency
112
+ histogram_quantile(0.95, rate(htm_embedding_latency_bucket[5m]))
113
+
114
+ # Average latency by provider
115
+ rate(htm_embedding_latency_sum[5m]) / rate(htm_embedding_latency_count[5m])
116
+ ```
117
+
118
+ ### htm.tag.latency (Histogram)
119
+
120
+ Measures tag extraction time in milliseconds.
121
+
122
+ **Attributes:**
123
+ - `provider`: LLM provider (`ollama`, `openai`, etc.)
124
+ - `status`: Outcome (`success`, `error`)
125
+
126
+ **Example queries (PromQL):**
127
+ ```promql
128
+ # p99 tag extraction latency
129
+ histogram_quantile(0.99, rate(htm_tag_latency_bucket[5m]))
130
+ ```
131
+
132
+ ### htm.search.latency (Histogram)
133
+
134
+ Measures search operation time in milliseconds.
135
+
136
+ **Attributes:**
137
+ - `strategy`: Search strategy (`vector`, `fulltext`, `hybrid`)
138
+
139
+ **Example queries (PromQL):**
140
+ ```promql
141
+ # Search latency by strategy
142
+ histogram_quantile(0.95, rate(htm_search_latency_bucket[5m])) by (strategy)
143
+
144
+ # Hybrid search avg latency
145
+ rate(htm_search_latency_sum{strategy="hybrid"}[5m])
146
+ / rate(htm_search_latency_count{strategy="hybrid"}[5m])
147
+ ```
148
+
149
+ ### htm.cache.operations (Counter)
150
+
151
+ Counts cache hits and misses.
152
+
153
+ **Attributes:**
154
+ - `operation`: Operation type (`hit`, `miss`)
155
+
156
+ **Example queries (PromQL):**
157
+ ```promql
158
+ # Cache hit rate
159
+ rate(htm_cache_operations_total{operation="hit"}[5m])
160
+ / (rate(htm_cache_operations_total{operation="hit"}[5m])
161
+ + rate(htm_cache_operations_total{operation="miss"}[5m]))
162
+ ```
163
+
164
+ ## Compatible Backends
165
+
166
+ HTM metrics work with any OTLP-compatible platform:
167
+
168
+ ### Open Source / Self-Hosted
169
+
170
+ | Platform | OTLP Support | Notes |
171
+ |----------|--------------|-------|
172
+ | **Jaeger** | Native (v1.35+) | Distributed tracing with metrics |
173
+ | **Prometheus** | Via receiver | Popular metrics platform |
174
+ | **Grafana Tempo** | Native | Traces with metrics correlation |
175
+ | **Grafana Mimir** | Native | Scalable Prometheus-compatible |
176
+ | **SigNoz** | Native | Full-stack observability |
177
+ | **Uptrace** | Native | Open source APM |
178
+
179
+ ### Commercial / SaaS
180
+
181
+ | Platform | OTLP Support | Notes |
182
+ |----------|--------------|-------|
183
+ | **Datadog** | Native | Full-stack observability |
184
+ | **New Relic** | Native | APM and infrastructure |
185
+ | **Honeycomb** | Native (preferred) | High-cardinality observability |
186
+ | **Splunk APM** | Native | Enterprise observability |
187
+ | **Dynatrace** | Native | AI-powered monitoring |
188
+ | **AWS X-Ray** | Via ADOT | AWS native tracing |
189
+ | **Google Cloud Trace** | Native | GCP native tracing |
190
+ | **Azure Monitor** | Native | Azure native monitoring |
191
+ | **Grafana Cloud** | Native | Managed Grafana stack |
192
+
193
+ ## Setup Examples
194
+
195
+ ### Jaeger (Local Development)
196
+
197
+ ```bash
198
+ # Start Jaeger with OTLP support
199
+ docker run -d --name jaeger \
200
+ -p 4318:4318 \
201
+ -p 16686:16686 \
202
+ jaegertracing/all-in-one:latest
203
+
204
+ # Configure HTM
205
+ export HTM_TELEMETRY_ENABLED="true"
206
+ export OTEL_METRICS_EXPORTER="otlp"
207
+ export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
208
+ ```
209
+
210
+ ### Prometheus (via OpenTelemetry Collector)
211
+
212
+ ```yaml
213
+ # otel-collector-config.yaml
214
+ receivers:
215
+ otlp:
216
+ protocols:
217
+ grpc:
218
+ http:
219
+
220
+ exporters:
221
+ prometheus:
222
+ endpoint: "0.0.0.0:8889"
223
+
224
+ service:
225
+ pipelines:
226
+ metrics:
227
+ receivers: [otlp]
228
+ exporters: [prometheus]
229
+ ```
230
+
231
+ ```bash
232
+ docker run -d \
233
+ -p 4317:4317 \
234
+ -p 4318:4318 \
235
+ -p 8889:8889 \
236
+ -v $(pwd)/otel-collector-config.yaml:/etc/otel-collector-config.yaml \
237
+ otel/opentelemetry-collector:latest \
238
+ --config=/etc/otel-collector-config.yaml
239
+ ```
240
+
241
+ ### Datadog
242
+
243
+ ```bash
244
+ export HTM_TELEMETRY_ENABLED="true"
245
+ export OTEL_METRICS_EXPORTER="otlp"
246
+ export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp.datadoghq.com"
247
+ export OTEL_EXPORTER_OTLP_HEADERS="DD-API-KEY=your-api-key"
248
+ ```
249
+
250
+ ### Honeycomb
251
+
252
+ ```bash
253
+ export HTM_TELEMETRY_ENABLED="true"
254
+ export OTEL_METRICS_EXPORTER="otlp"
255
+ export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.honeycomb.io"
256
+ export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key"
257
+ ```
258
+
259
+ ### New Relic
260
+
261
+ ```bash
262
+ export HTM_TELEMETRY_ENABLED="true"
263
+ export OTEL_METRICS_EXPORTER="otlp"
264
+ export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp.nr-data.net"
265
+ export OTEL_EXPORTER_OTLP_HEADERS="api-key=your-license-key"
266
+ ```
267
+
268
+ ## Architecture
269
+
270
+ ### Null Object Pattern
271
+
272
+ HTM uses a null object pattern for telemetry. When disabled:
273
+
274
+ ```ruby
275
+ # This code runs identically whether telemetry is enabled or not
276
+ HTM::Telemetry.job_counter.add(1, attributes: { 'job' => 'embedding' })
277
+ ```
278
+
279
+ When telemetry is disabled or the SDK is not installed:
280
+ - `HTM::Telemetry.meter` returns a `NullMeter`
281
+ - All instruments return `NullInstrument` instances
282
+ - All operations (`add`, `record`) are no-ops returning `nil`
283
+ - Zero memory allocation, zero CPU overhead
284
+
285
+ ### Code Flow
286
+
287
+ ![HTM Telemetry Architecture](images/telemetry-architecture.svg)
288
+
289
+ ### Instrumentation Points
290
+
291
+ HTM instruments these key operations:
292
+
293
+ | Component | Metrics Recorded |
294
+ |-----------|-----------------|
295
+ | `GenerateEmbeddingJob` | `htm.jobs`, `htm.embedding.latency` |
296
+ | `GenerateTagsJob` | `htm.jobs`, `htm.tag.latency` |
297
+ | `VectorSearch#search` | `htm.search.latency` (strategy: vector) |
298
+ | `FulltextSearch#search_fulltext` | `htm.search.latency` (strategy: fulltext) |
299
+ | `HybridSearch#search_hybrid` | `htm.search.latency` (strategy: hybrid) |
300
+ | `QueryCache#fetch` | `htm.cache.operations` |
301
+
302
+ ## Testing
303
+
304
+ When writing tests, reset telemetry state between tests:
305
+
306
+ ```ruby
307
+ def setup
308
+ HTM::Telemetry.reset!
309
+ HTM.configuration.telemetry_enabled = false
310
+ end
311
+
312
+ def teardown
313
+ HTM::Telemetry.reset!
314
+ end
315
+ ```
316
+
317
+ ### Verifying Metrics in Tests
318
+
319
+ ```ruby
320
+ def test_records_embedding_latency
321
+ # Create a mock histogram
322
+ recorded = []
323
+ mock_histogram = Object.new
324
+ mock_histogram.define_singleton_method(:record) do |value, **kwargs|
325
+ recorded << { value: value, attributes: kwargs[:attributes] }
326
+ end
327
+
328
+ # Inject mock (requires test helper)
329
+ HTM::Telemetry.instance_variable_set(:@embedding_latency, mock_histogram)
330
+
331
+ # Run operation
332
+ HTM::Jobs::GenerateEmbeddingJob.perform(node_id: node.id)
333
+
334
+ # Verify
335
+ assert recorded.any? { |r| r[:attributes]['status'] == 'success' }
336
+ end
337
+ ```
338
+
339
+ ## Troubleshooting
340
+
341
+ ### Metrics Not Appearing
342
+
343
+ 1. **Check telemetry is enabled:**
344
+ ```ruby
345
+ puts HTM.configuration.telemetry_enabled # Should be true
346
+ puts HTM::Telemetry.enabled? # Should be true
347
+ ```
348
+
349
+ 2. **Check SDK is installed:**
350
+ ```ruby
351
+ puts HTM::Telemetry.sdk_available? # Should be true
352
+ ```
353
+
354
+ 3. **Check environment variables:**
355
+ ```bash
356
+ echo $OTEL_METRICS_EXPORTER
357
+ echo $OTEL_EXPORTER_OTLP_ENDPOINT
358
+ ```
359
+
360
+ 4. **Check collector is running:**
361
+ ```bash
362
+ curl http://localhost:4318/v1/metrics # Should not 404
363
+ ```
364
+
365
+ ### High Cardinality Issues
366
+
367
+ Avoid high-cardinality attributes in metrics. HTM uses low-cardinality attributes by design:
368
+
369
+ - `job`: 2-3 values (embedding, tags, propositions)
370
+ - `status`: 3 values (success, error, circuit_open)
371
+ - `provider`: ~10 values (ollama, openai, etc.)
372
+ - `strategy`: 3 values (vector, fulltext, hybrid)
373
+ - `operation`: 2 values (hit, miss)
374
+
375
+ ### Performance Concerns
376
+
377
+ With telemetry disabled (default), there is zero overhead:
378
+ - No gem loading
379
+ - No object allocation
380
+ - No method calls beyond the null check
381
+
382
+ With telemetry enabled, overhead is minimal:
383
+ - ~1-5μs per metric recording
384
+ - Memory for histogram buckets (~1KB per histogram)
385
+
386
+ ## References
387
+
388
+ - [OpenTelemetry Ruby SDK](https://github.com/open-telemetry/opentelemetry-ruby)
389
+ - [OpenTelemetry Metrics SDK](https://github.com/open-telemetry/opentelemetry-ruby/tree/main/metrics_sdk)
390
+ - [OpenTelemetry Specification](https://opentelemetry.io/docs/specs/otel/)
391
+ - [OTLP Protocol](https://opentelemetry.io/docs/specs/otlp/)
data/examples/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # HTM Examples
2
2
 
3
- This directory contains example applications demonstrating various ways to use the HTM (Hierarchical Temporary Memory) gem.
3
+ This directory contains example applications demonstrating various ways to use the HTM (Hierarchical Temporal Memory) gem.
4
4
 
5
5
  ## Prerequisites
6
6
 
@@ -11,6 +11,12 @@ All examples require:
11
11
  export HTM_DBURL="postgresql://user@localhost:5432/htm_development"
12
12
  ```
13
13
 
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
17
+ > connects to `htm_test`. When `RAILS_ENV` is unset (typical for examples),
18
+ > behavior is unchanged.
19
+
14
20
  2. **Ollama** (recommended for local LLM):
15
21
  ```bash
16
22
  ollama pull nomic-embed-text # For embeddings
@@ -107,6 +113,39 @@ ruby examples/timeframe_demo.rb
107
113
 
108
114
  ---
109
115
 
116
+ ### telemetry/
117
+
118
+ **Live Grafana dashboard for HTM metrics.**
119
+
120
+ A complete telemetry demo using Homebrew-installed Prometheus and Grafana to visualize HTM metrics in real-time graphs.
121
+
122
+ ```bash
123
+ cd examples/telemetry
124
+ ruby demo.rb
125
+ ```
126
+
127
+ The demo automatically:
128
+ - Checks/installs Prometheus and Grafana via Homebrew
129
+ - Starts both services if not running
130
+ - Configures Prometheus to scrape the demo's metrics
131
+ - Cleans up previous demo data
132
+ - Opens Grafana in your browser
133
+
134
+ **Features:**
135
+ - Live updating dashboard with job counts, latencies, cache hit rates
136
+ - Pre-built Grafana dashboard JSON
137
+ - No Docker required - uses native macOS services
138
+
139
+ **Dependencies:**
140
+ ```bash
141
+ brew install prometheus grafana
142
+ gem install prometheus-client webrick
143
+ ```
144
+
145
+ See [telemetry/README.md](telemetry/README.md) for detailed setup instructions.
146
+
147
+ ---
148
+
110
149
  ### mcp_server.rb & mcp_client.rb
111
150
 
112
151
  **Model Context Protocol (MCP) integration for AI assistants.**
@@ -366,6 +405,11 @@ examples/
366
405
  ├── custom_llm_configuration.rb # LLM integration patterns
367
406
  ├── file_loader_usage.rb # Document loading
368
407
  ├── timeframe_demo.rb # Time-based filtering
408
+ ├── telemetry/
409
+ │ ├── demo.rb # Live Grafana metrics dashboard
410
+ │ ├── README.md
411
+ │ ├── SETUP_README.md
412
+ │ └── grafana/dashboards/htm-metrics.json
369
413
  ├── mcp_server.rb # MCP server exposing HTM tools
370
414
  ├── mcp_client.rb # MCP client with chat interface
371
415
  ├── example_app/
@@ -397,6 +441,7 @@ examples/
397
441
  | Custom LLM integration | `custom_llm_configuration.rb` |
398
442
  | Loading documents/files | `file_loader_usage.rb` |
399
443
  | Time-based queries | `timeframe_demo.rb` |
444
+ | Production observability | `telemetry/` |
400
445
  | MCP server for AI assistants | `mcp_server.rb` |
401
446
  | MCP client with chat interface | `mcp_client.rb` |
402
447
  | Web application | `sinatra_app/` |
@@ -111,7 +111,7 @@ This means:
111
111
  $ ruby htm_cli.rb
112
112
 
113
113
  ============================================================
114
- HTM CLI - Hierarchical Temporary Memory Assistant
114
+ HTM CLI - Hierarchical Temporal Memory Assistant
115
115
  ============================================================
116
116
 
117
117
  Job Backend: inline (synchronous execution)
@@ -67,7 +67,7 @@ class HTMCli
67
67
  def run
68
68
  puts
69
69
  puts "=" * 60
70
- puts "HTM CLI - Hierarchical Temporary Memory Assistant"
70
+ puts "HTM CLI - Hierarchical Temporal Memory Assistant"
71
71
  puts "=" * 60
72
72
  puts
73
73
  puts "Job Backend: #{HTM.configuration.job_backend} (synchronous execution)"
@@ -20,7 +20,6 @@
20
20
  require 'logger'
21
21
  require 'json'
22
22
  require_relative '../../lib/htm'
23
- require_relative 'lib/working_memory_channel'
24
23
 
25
24
  robot_name = ARGV[0]
26
25
  group_name = ARGV[1]
@@ -53,7 +52,7 @@ htm = HTM.new(robot_name: robot_name, working_memory_size: 8000)
53
52
  db_config = HTM::Database.default_config
54
53
 
55
54
  # Setup channel for cross-process notifications
56
- channel = WorkingMemoryChannel.new(group_name, db_config)
55
+ channel = HTM::WorkingMemoryChannel.new(group_name, db_config)
57
56
 
58
57
  # Track notifications received
59
58
  notifications_count = 0
@@ -26,9 +26,6 @@
26
26
  require_relative '../../lib/htm'
27
27
  require 'json'
28
28
 
29
- require_relative 'lib/working_memory_channel'
30
- require_relative 'lib/robot_group'
31
-
32
29
  # =============================================================================
33
30
  # Demo Script
34
31
  # =============================================================================
@@ -59,7 +56,7 @@ begin
59
56
  # ---------------------------------------------------------------------------
60
57
  puts "\n2. Creating robot group with primary + standby..."
61
58
 
62
- group = RobotGroup.new(
59
+ group = HTM::RobotGroup.new(
63
60
  name: 'customer-support-ha',
64
61
  active: ['support-primary'],
65
62
  passive: ['support-standby'],
@@ -281,7 +281,7 @@ __END__
281
281
  </head>
282
282
  <body>
283
283
  <h1>HTM Sinatra Example</h1>
284
- <p>Hierarchical Temporary Memory with tag-enhanced hybrid search and Sidekiq background jobs</p>
284
+ <p>Hierarchical Temporal Memory with tag-enhanced hybrid search and Sidekiq background jobs</p>
285
285
 
286
286
  <div class="section">
287
287
  <h2>Remember Information</h2>