htm 0.0.10 → 0.0.14

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.dictate.toml +46 -0
  3. data/.envrc +2 -0
  4. data/CHANGELOG.md +86 -3
  5. data/README.md +86 -7
  6. data/Rakefile +14 -2
  7. data/bin/htm_mcp.rb +621 -0
  8. data/config/database.yml +20 -13
  9. data/db/migrate/00010_add_soft_delete_to_associations.rb +29 -0
  10. data/db/migrate/00011_add_performance_indexes.rb +21 -0
  11. data/db/migrate/00012_add_tags_trigram_index.rb +18 -0
  12. data/db/migrate/00013_enable_lz4_compression.rb +43 -0
  13. data/db/schema.sql +49 -92
  14. data/docs/api/index.md +1 -1
  15. data/docs/api/yard/HTM.md +2 -4
  16. data/docs/architecture/index.md +1 -1
  17. data/docs/development/index.md +1 -1
  18. data/docs/getting-started/index.md +1 -1
  19. data/docs/guides/index.md +1 -1
  20. data/docs/images/telemetry-architecture.svg +153 -0
  21. data/docs/telemetry.md +391 -0
  22. data/examples/README.md +171 -1
  23. data/examples/cli_app/README.md +1 -1
  24. data/examples/cli_app/htm_cli.rb +1 -1
  25. data/examples/mcp_client.rb +529 -0
  26. data/examples/sinatra_app/app.rb +1 -1
  27. data/examples/telemetry/README.md +147 -0
  28. data/examples/telemetry/SETUP_README.md +169 -0
  29. data/examples/telemetry/demo.rb +498 -0
  30. data/examples/telemetry/grafana/dashboards/htm-metrics.json +457 -0
  31. data/lib/htm/configuration.rb +261 -70
  32. data/lib/htm/database.rb +46 -22
  33. data/lib/htm/embedding_service.rb +24 -14
  34. data/lib/htm/errors.rb +15 -1
  35. data/lib/htm/jobs/generate_embedding_job.rb +19 -0
  36. data/lib/htm/jobs/generate_propositions_job.rb +103 -0
  37. data/lib/htm/jobs/generate_tags_job.rb +24 -0
  38. data/lib/htm/loaders/markdown_chunker.rb +79 -0
  39. data/lib/htm/loaders/markdown_loader.rb +41 -15
  40. data/lib/htm/long_term_memory/fulltext_search.rb +138 -0
  41. data/lib/htm/long_term_memory/hybrid_search.rb +324 -0
  42. data/lib/htm/long_term_memory/node_operations.rb +209 -0
  43. data/lib/htm/long_term_memory/relevance_scorer.rb +355 -0
  44. data/lib/htm/long_term_memory/robot_operations.rb +34 -0
  45. data/lib/htm/long_term_memory/tag_operations.rb +428 -0
  46. data/lib/htm/long_term_memory/vector_search.rb +109 -0
  47. data/lib/htm/long_term_memory.rb +51 -1153
  48. data/lib/htm/models/node.rb +35 -2
  49. data/lib/htm/models/node_tag.rb +31 -0
  50. data/lib/htm/models/robot_node.rb +31 -0
  51. data/lib/htm/models/tag.rb +44 -0
  52. data/lib/htm/proposition_service.rb +169 -0
  53. data/lib/htm/query_cache.rb +214 -0
  54. data/lib/htm/sql_builder.rb +178 -0
  55. data/lib/htm/tag_service.rb +16 -6
  56. data/lib/htm/tasks.rb +8 -2
  57. data/lib/htm/telemetry.rb +224 -0
  58. data/lib/htm/version.rb +1 -1
  59. data/lib/htm.rb +64 -3
  60. data/lib/tasks/doc.rake +1 -1
  61. data/lib/tasks/htm.rake +259 -13
  62. data/mkdocs.yml +96 -96
  63. metadata +75 -18
  64. data/.aigcm_msg +0 -1
  65. data/.claude/settings.local.json +0 -92
  66. data/CLAUDE.md +0 -603
  67. data/examples/cli_app/temp.log +0 -93
  68. data/lib/htm/loaders/paragraph_chunker.rb +0 -112
  69. data/notes/ARCHITECTURE_REVIEW.md +0 -1167
  70. data/notes/IMPLEMENTATION_SUMMARY.md +0 -606
  71. data/notes/MULTI_FRAMEWORK_IMPLEMENTATION.md +0 -451
  72. data/notes/next_steps.md +0 -100
  73. data/notes/plan.md +0 -627
  74. data/notes/tag_ontology_enhancement_ideas.md +0 -222
  75. data/notes/timescaledb_removal_summary.md +0 -200
data/CLAUDE.md DELETED
@@ -1,603 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## Project Overview
6
-
7
- HTM (Hierarchical Temporary Memory) is a Ruby gem that provides intelligent memory management for LLM-based applications (robots). It implements a two-tier memory architecture:
8
-
9
- - **Long-term Memory**: Durable PostgreSQL storage with vector embeddings for semantic search
10
- - **Working Memory**: Token-limited in-memory context for immediate LLM use
11
-
12
- Key capabilities include RAG-based retrieval, temporal filtering, multi-robot "hive mind" shared memory, and flexible hierarchical tagging for organization.
13
-
14
- ## Development Commands
15
-
16
- ### Setup
17
- ```bash
18
- # Set database connection URL (required before any database operations)
19
- export HTM_DBURL="postgresql://postgres@localhost:5432/htm_development"
20
-
21
- # Install dependencies
22
- bundle install
23
-
24
- # Initialize database schema (run once)
25
- rake db_setup
26
- # OR
27
- ruby -r ./lib/htm -e "HTM::Database.setup"
28
-
29
- # Verify database connection
30
- rake db_test
31
- # OR
32
- ruby test_connection.rb
33
- ```
34
-
35
- ### Testing
36
- ```bash
37
- # Run all tests (Minitest)
38
- rake test
39
-
40
- # Run specific test file
41
- ruby test/htm_test.rb
42
- ruby test/embedding_service_test.rb
43
- ruby test/integration_test.rb
44
- ```
45
-
46
- ### Examples
47
- ```bash
48
- # Run basic usage example
49
- rake example
50
- # OR
51
- ruby examples/basic_usage.rb
52
- ```
53
-
54
- ### Gem Tasks
55
- ```bash
56
- # Build gem
57
- rake build
58
-
59
- # Install gem locally
60
- rake install
61
-
62
- # Release gem (requires proper credentials)
63
- rake release
64
- ```
65
-
66
- ### Utilities
67
- ```bash
68
- # Show code statistics
69
- rake stats
70
-
71
- # Show database table record counts and statistics
72
- rake htm:db:stats
73
-
74
- # Rebuild all embeddings (clears and regenerates via LLM)
75
- rake htm:db:rebuild:embeddings
76
-
77
- # Enable PostgreSQL extensions (if needed)
78
- ruby enable_extensions.rb
79
- ```
80
-
81
- ## Architecture
82
-
83
- ### Core Components
84
-
85
- **HTM** (`lib/htm.rb`): Main API class that coordinates all components. Handles robot registration, memory operations (add, recall, retrieve, forget), context assembly, and hive mind queries.
86
-
87
- **HTM::Database** (`lib/htm/database.rb`): Database schema setup and configuration. Parses connection URLs from `HTM_DBURL` environment variable, verifies extensions (pgvector, pg_trgm), and runs schema migrations using ActiveRecord.
88
-
89
- **HTM::LongTermMemory** (`lib/htm/long_term_memory.rb`): PostgreSQL-backed permanent storage with ActiveRecord models. Manages nodes table with many-to-many tagging system, vector search (pgvector), full-text search (PostgreSQL tsvector), and hybrid search capabilities.
90
-
91
- **HTM::WorkingMemory** (`lib/htm/working_memory.rb`): In-memory token-limited cache. Tracks active nodes with LRU eviction, manages token budgets, and assembles context strings with multiple strategies (recent, important, balanced).
92
-
93
- **HTM::EmbeddingService** (`lib/htm/embedding_service.rb`): Vector embedding validation and processing service. Wraps the configured embedding generator (via RubyLLM), validates responses, handles dimension padding/truncation. Called by `GenerateEmbeddingJob` background job. See ADR-016 for async workflow.
94
-
95
- **HTM::TagService** (`lib/htm/tag_service.rb`): Hierarchical tag validation and processing service. Wraps the configured tag extractor (via RubyLLM chat), validates tag format, enforces depth limits. Called by `GenerateTagsJob` background job. Parallel architecture to EmbeddingService. See ADR-016.
96
-
97
- **HTM::Configuration** (`lib/htm/configuration.rb`): Multi-provider LLM configuration via RubyLLM. Supports OpenAI, Anthropic, Gemini, Azure, Ollama (default), HuggingFace, OpenRouter, Bedrock, and DeepSeek. Manages API keys, model selection, and timeouts.
98
-
99
- **HTM::Models::FileSource** (`lib/htm/models/file_source.rb`): Tracks source files loaded into memory. Stores file path, mtime for re-sync detection, YAML frontmatter metadata, and links to chunked nodes via `source_id` foreign key.
100
-
101
- **HTM::Loaders::MarkdownLoader** (`lib/htm/loaders/markdown_loader.rb`): Loads markdown files into long-term memory. Extracts YAML frontmatter, chunks text by paragraph, tracks source file for re-sync, and handles duplicate detection via content hash.
102
-
103
- **HTM::Loaders::ParagraphChunker** (`lib/htm/loaders/paragraph_chunker.rb`): Splits text into paragraph-based chunks. Preserves fenced code blocks (``` and ~~~), splits by blank lines, and merges very short fragments.
104
-
105
- ### Database Schema
106
-
107
- Located in `db/schema.sql`:
108
-
109
- - **robots**: Registry of all LLM agents using the HTM system with metadata
110
- - **nodes**: Primary memory storage with vector embeddings (up to 2000 dimensions), full-text search, fuzzy matching, JSONB metadata, and soft delete support (`deleted_at` column)
111
- - **tags**: Hierarchical tag system using colon-separated namespaces (e.g., `database:postgresql:extensions`)
112
- - **nodes_tags**: Join table implementing many-to-many relationship between nodes and tags
113
- - **file_sources**: Source file metadata for loaded documents (path, mtime, frontmatter, sync status)
114
-
115
- **Nodes table key columns:**
116
- - `content`: The memory content (text)
117
- - `embedding`: Vector embedding for semantic search (up to 2000 dimensions)
118
- - `metadata`: JSONB column for arbitrary key-value data with GIN index
119
- - `content_hash`: SHA-256 hash for deduplication
120
- - `deleted_at`: Soft delete timestamp (null = active)
121
-
122
- The schema uses PostgreSQL 17 with pgvector and pg_trgm extensions. ActiveRecord models are available:
123
- - `HTM::Models::Robot`
124
- - `HTM::Models::Node`
125
- - `HTM::Models::Tag`
126
- - `HTM::Models::NodeTag`
127
- - `HTM::Models::FileSource`
128
-
129
- ### Memory Types
130
-
131
- - `:fact` - Immutable facts about the user or system
132
- - `:context` - Conversational context and state
133
- - `:code` - Code snippets, patterns, and implementations
134
- - `:preference` - User preferences and settings
135
- - `:decision` - Architectural and design decisions
136
- - `:question` - Unresolved questions or uncertainties
137
-
138
- ### Search Strategies
139
-
140
- - **Vector search** (`:vector`): Semantic similarity using pgvector with cosine distance on embeddings
141
- - **Full-text search** (`:fulltext`): Keyword matching using PostgreSQL's tsvector with trigram fuzzy matching
142
- - **Hybrid search** (`:hybrid`): Combines vector and full-text with weighted scoring
143
-
144
- ### Context Assembly Strategies
145
-
146
- - **Recent** (`:recent`): Prioritizes newest memories
147
- - **Important** (`:important`): Prioritizes high importance scores
148
- - **Balanced** (`:balanced`): Importance × recency weighted combination
149
-
150
- ## Dependencies
151
-
152
- ### Runtime
153
- - `pg` - PostgreSQL client library
154
- - `pgvector` - Vector similarity search support
155
- - `connection_pool` - Database connection pooling
156
- - `tiktoken_ruby` - Token counting for context management
157
- - `ruby_llm` - Multi-provider LLM client (OpenAI, Anthropic, Gemini, Azure, Ollama, HuggingFace, OpenRouter, Bedrock, DeepSeek)
158
-
159
- ### Development
160
- - `rake` - Task automation
161
- - `minitest` - Testing framework
162
- - `minitest-reporters` - Enhanced test output
163
- - `debug_me` - Debugging utilities (preferred over puts)
164
-
165
- ## Environment Variables
166
-
167
- ### Database
168
- - `HTM_DBURL` - Full PostgreSQL connection URL (preferred)
169
- - `HTM_SERVICE_NAME` - Service identifier
170
- - `HTM_DBNAME` - Database name
171
- - `HTM_DBUSER` - Database username
172
- - `HTM_DBPASS` - Database password
173
- - `HTM_DBPORT` - Database port
174
- - `HTM_DBHOST` - Database host
175
-
176
- ### LLM Providers (via RubyLLM)
177
- - `OPENAI_API_KEY` - OpenAI API key
178
- - `OPENAI_ORGANIZATION` - OpenAI organization ID (optional)
179
- - `ANTHROPIC_API_KEY` - Anthropic API key
180
- - `GEMINI_API_KEY` - Google Gemini API key
181
- - `AZURE_OPENAI_API_KEY` - Azure OpenAI API key
182
- - `AZURE_OPENAI_ENDPOINT` - Azure OpenAI endpoint URL
183
- - `OLLAMA_URL` - Ollama server URL (default: http://localhost:11434)
184
- - `HUGGINGFACE_API_KEY` - HuggingFace Inference API key
185
- - `OPENROUTER_API_KEY` - OpenRouter API key
186
- - `AWS_ACCESS_KEY_ID` - AWS Bedrock access key
187
- - `AWS_SECRET_ACCESS_KEY` - AWS Bedrock secret key
188
- - `AWS_REGION` - AWS region (default: us-east-1)
189
- - `DEEPSEEK_API_KEY` - DeepSeek API key
190
-
191
- ## External Services
192
-
193
- ### LLM Providers (via RubyLLM)
194
-
195
- HTM uses RubyLLM for multi-provider LLM support. Configure your preferred provider:
196
-
197
- ```ruby
198
- # OpenAI (cloud)
199
- HTM.configure do |config|
200
- config.embedding_provider = :openai
201
- config.embedding_model = 'text-embedding-3-small'
202
- config.tag_provider = :openai
203
- config.tag_model = 'gpt-4o-mini'
204
- end
205
-
206
- # Anthropic (cloud)
207
- HTM.configure do |config|
208
- config.tag_provider = :anthropic
209
- config.tag_model = 'claude-3-haiku-20240307'
210
- end
211
-
212
- # Ollama (local - default)
213
- HTM.configure do |config|
214
- config.embedding_provider = :ollama
215
- config.embedding_model = 'nomic-embed-text'
216
- config.tag_provider = :ollama
217
- config.tag_model = 'llama3'
218
- end
219
- ```
220
-
221
- ### Ollama (default local provider)
222
-
223
- ```bash
224
- # Install Ollama
225
- curl https://ollama.ai/install.sh | sh
226
-
227
- # Pull embedding model
228
- ollama pull nomic-embed-text
229
-
230
- # Pull chat model for tag extraction
231
- ollama pull llama3
232
-
233
- # Verify Ollama is running
234
- curl http://localhost:11434/api/version
235
- ```
236
-
237
- ### PostgreSQL Database
238
- The project uses a local PostgreSQL instance with:
239
- - PostgreSQL 14+ (17.x recommended)
240
- - pgvector extension for vector similarity search
241
- - pg_trgm extension for fuzzy text matching
242
- - ActiveRecord for ORM and migrations
243
-
244
- **Quick setup on macOS:**
245
- ```bash
246
- brew install postgresql@17
247
- brew services start postgresql@17
248
- createdb htm_development
249
- psql htm_development -c "CREATE EXTENSION IF NOT EXISTS vector; CREATE EXTENSION IF NOT EXISTS pg_trgm;"
250
- ```
251
-
252
- ## Testing Philosophy
253
-
254
- - All tests use Minitest framework with spec reporter
255
- - Test files located in `test/` directory
256
- - Integration tests require database connection (use test database if available)
257
- - Mock Ollama embeddings in tests to avoid external dependencies
258
-
259
- ## Code Style
260
-
261
- - Use `debug_me` gem for debugging, not `puts`
262
- - Frozen string literals in all files
263
- - Methods should be testable in isolation
264
- - Use 2-space indentation
265
- - Follow Ruby style guide conventions
266
-
267
- ## Common Development Tasks
268
-
269
- ### Adding a New Memory Type
270
- 1. Create ActiveRecord migration in `db/migrate/` if new columns needed
271
- 2. Add type to documentation in `lib/htm.rb` and `CLAUDE.md`
272
- 3. Consider adding specialized methods in `HTM` class
273
- 4. Add tests for the new type
274
- 5. Run `bundle exec rake htm:db:migrate` and `bundle exec rake htm:db:schema:dump`
275
-
276
- ### Using a Different LLM Provider
277
- HTM uses RubyLLM which supports multiple providers out of the box. To use a different provider:
278
-
279
- 1. Set the appropriate API key environment variable (e.g., `OPENAI_API_KEY`)
280
- 2. Configure HTM with your preferred provider and model:
281
- ```ruby
282
- HTM.configure do |config|
283
- config.embedding_provider = :openai # or :anthropic, :gemini, :azure, etc.
284
- config.embedding_model = 'text-embedding-3-small'
285
- config.tag_provider = :openai
286
- config.tag_model = 'gpt-4o-mini'
287
- end
288
- ```
289
- 3. Supported providers: `:openai`, `:anthropic`, `:gemini`, `:azure`, `:ollama`, `:huggingface`, `:openrouter`, `:bedrock`, `:deepseek`
290
-
291
- ### Modifying Database Schema
292
- 1. Create new ActiveRecord migration in `db/migrate/` with timestamp prefix
293
- 2. Use ActiveRecord DSL for table/column changes (create_table, add_column, add_index, etc.)
294
- 3. Update affected ActiveRecord models in `lib/htm/models/`
295
- 4. Update affected classes (`LongTermMemory`, `Database`)
296
- 5. Run `bundle exec rake htm:db:migrate` to apply changes
297
- 6. Run `bundle exec rake htm:db:schema:dump` to update `db/schema.sql`
298
- 7. Update documentation in `docs/development/schema.md` and `CLAUDE.md`
299
- 8. Update tests
300
-
301
- ### Async Background Processing (ADR-016)
302
-
303
- HTM uses **async-job** for background processing with two parallel jobs per node:
304
-
305
- **Node Creation Flow**:
306
- 1. **Save node immediately** (~15ms) - Fast user response
307
- 2. **Enqueue `GenerateEmbeddingJob`** - Adds embedding asynchronously
308
- 3. **Enqueue `GenerateTagsJob`** - Extracts and adds tags asynchronously
309
-
310
- **Eventual Consistency**:
311
- - Node available immediately for basic retrieval
312
- - Embedding added within ~100ms (enables vector search)
313
- - Tags added within ~1 second (enables hierarchical navigation)
314
- - Full-text search works immediately (no dependencies)
315
-
316
- **Current workflow**:
317
- ```ruby
318
- # 1. Create node (fast response)
319
- node = htm.add_message("PostgreSQL supports vector search via pgvector")
320
- # Returns immediately (~15ms)
321
-
322
- # 2. Background jobs run in parallel (user doesn't wait)
323
- # - GenerateEmbeddingJob: Uses EmbeddingService to generate embedding
324
- # - GenerateTagsJob: Uses TagService to extract tags from content
325
-
326
- # 3. Node eventually enriched (~1 second)
327
- # - node.embedding populated (enables vector search)
328
- # - tags created and associated (enables tag navigation)
329
- ```
330
-
331
- ### Working with Embeddings
332
- 1. **Async generation**: `GenerateEmbeddingJob` runs after node creation
333
- 2. **Multi-provider support** (via RubyLLM):
334
- - Ollama (default): `nomic-embed-text` (768-dim)
335
- - OpenAI: `text-embedding-3-small` (1536-dim)
336
- - Gemini: `text-embedding-004` (768-dim)
337
- - Azure, HuggingFace, OpenRouter, Bedrock, DeepSeek also supported
338
- 3. **Dimensions**: Stored in `embedding_dimension` column, max 2000 dimensions (padded automatically)
339
- 4. **Error handling**: Failures logged, node remains without embedding
340
- 5. **Search behavior**: Vector search excludes nodes without embeddings
341
-
342
- ### Working with Metadata
343
-
344
- Nodes have a `metadata` JSONB column for flexible key-value storage:
345
-
346
- **Storing metadata:**
347
- ```ruby
348
- # Store with metadata
349
- htm.remember("User prefers dark mode", metadata: { category: "preference", priority: "high" })
350
-
351
- # Combine with tags
352
- htm.remember(
353
- "API rate limit is 1000 req/min",
354
- tags: ["api:rate-limiting"],
355
- metadata: { environment: "production", version: 2 }
356
- )
357
- ```
358
-
359
- **Querying by metadata:**
360
- ```ruby
361
- # Filter by metadata in recall
362
- htm.recall("settings", metadata: { priority: "high" })
363
- htm.recall("API config", metadata: { environment: "production", version: 2 })
364
-
365
- # Combine with other filters
366
- htm.recall("database", timeframe: "last month", strategy: :hybrid, metadata: { reviewed: true })
367
- ```
368
-
369
- **Metadata features:**
370
- - Stored as JSONB with GIN index for efficient queries
371
- - Uses PostgreSQL `@>` containment operator (node must contain all specified keys)
372
- - Supports any JSON type: strings, numbers, booleans, arrays, objects
373
- - Validation ensures keys are strings or symbols
374
-
375
- ### Working with Tags
376
- 1. **Async extraction**: `GenerateTagsJob` uses LLM to extract hierarchical tags
377
- 2. **Multi-provider support**: Uses RubyLLM chat (same providers as embeddings)
378
- 3. **Hierarchical format**: Colon separators (e.g., `ai:llm:embeddings`)
379
- 4. **Ontology context**: Uses existing tags to maintain consistency
380
- 5. **Query by prefix**: `WHERE tags.name LIKE 'database:%'` finds all database tags
381
- 6. **Error handling**: Failures logged, node remains without tags
382
-
383
- **Manual tag operations** (if needed):
384
- ```ruby
385
- ltm.add_tag(node_id: node.id, tag: 'database:postgresql') # Manual tag
386
- tags = ltm.node_topics(node.id) # Returns array of tag names
387
- related = ltm.topic_relationships(min_shared_nodes: 2) # Co-occurrence
388
- ```
389
-
390
- **Tag hierarchy visualization**:
391
- ```ruby
392
- # Text tree (directory-style)
393
- puts HTM::Models::Tag.all.tree_string
394
-
395
- # Mermaid flowchart format
396
- puts HTM::Models::Tag.all.tree_mermaid # Top-down
397
- puts HTM::Models::Tag.all.tree_mermaid(direction: 'LR') # Left-to-right
398
-
399
- # SVG visualization (dark theme, transparent background)
400
- File.write('tags.svg', HTM::Models::Tag.all.tree_svg)
401
- File.write('tags.svg', HTM::Models::Tag.all.tree_svg(title: 'My Tags'))
402
- ```
403
-
404
- **Rake tasks for tag management**:
405
- ```bash
406
- rake htm:tags:tree # Display text tree (all tags)
407
- rake 'htm:tags:tree[database]' # Display tags with prefix 'database'
408
- rake htm:tags:mermaid # Export to tags.md (Mermaid format)
409
- rake 'htm:tags:mermaid[ai]' # Export tags with prefix 'ai' to tags.md
410
- rake htm:tags:svg # Export to tags.svg
411
- rake 'htm:tags:svg[web]' # Export tags with prefix 'web' to tags.svg
412
- rake htm:tags:export # Export all formats (tags.txt, tags.md, tags.svg)
413
- rake 'htm:tags:export[database]' # Export filtered tags to all formats
414
- rake htm:tags:rebuild # Rebuild all tags (clears and regenerates via LLM)
415
- ```
416
-
417
- ### Soft Delete and Memory Recovery
418
-
419
- HTM uses soft delete by default when forgetting memories, allowing recovery of accidentally deleted nodes.
420
-
421
- **Soft delete (default - recoverable)**:
422
- ```ruby
423
- htm.forget(node_id) # Soft delete (sets deleted_at timestamp)
424
- htm.forget(node_id, soft: true) # Explicit soft delete
425
- ```
426
-
427
- **Restore soft-deleted nodes**:
428
- ```ruby
429
- htm.restore(node_id) # Clears deleted_at, node visible again
430
- ```
431
-
432
- **Permanent delete (requires confirmation)**:
433
- ```ruby
434
- htm.forget(node_id, soft: false, confirm: :confirmed) # Permanently removes from database
435
- ```
436
-
437
- **Purge old soft-deleted nodes**:
438
- ```ruby
439
- htm.purge_deleted(older_than: 30.days.ago, confirm: :confirmed)
440
- htm.purge_deleted(older_than: Time.new(2024, 1, 1), confirm: :confirmed)
441
- ```
442
-
443
- **Query soft-deleted nodes directly**:
444
- ```ruby
445
- HTM::Models::Node.deleted # All soft-deleted nodes
446
- HTM::Models::Node.with_deleted # All nodes including deleted
447
- HTM::Models::Node.deleted_before(30.days.ago) # Deleted before a date
448
-
449
- node = HTM::Models::Node.with_deleted.find(id)
450
- node.deleted? # Check if soft-deleted
451
- node.restore! # Restore a specific node
452
- node.soft_delete! # Soft delete a specific node
453
- ```
454
-
455
- ### Loading Files into Memory
456
-
457
- HTM can load text-based files (currently markdown) into long-term memory with automatic chunking, source tracking, and re-sync support.
458
-
459
- **Load a single file**:
460
- ```ruby
461
- htm = HTM.new(robot_name: "Document Loader")
462
-
463
- # Load a markdown file - chunks by paragraph, extracts frontmatter
464
- result = htm.load_file("docs/guide.md")
465
- # => { file_source_id: 1, chunks_created: 5, chunks_updated: 0, chunks_deleted: 0 }
466
-
467
- # Force re-sync even if file hasn't changed
468
- result = htm.load_file("docs/guide.md", force: true)
469
- ```
470
-
471
- **Load a directory**:
472
- ```ruby
473
- # Load all markdown files in a directory (recursive)
474
- results = htm.load_directory("docs/")
475
- # => [{ file_path: "docs/guide.md", ... }, { file_path: "docs/api.md", ... }]
476
-
477
- # Custom glob pattern
478
- results = htm.load_directory("content/", pattern: "**/*.md")
479
- ```
480
-
481
- **Query nodes from a file**:
482
- ```ruby
483
- # Get all nodes loaded from a specific file
484
- nodes = htm.nodes_from_file("docs/guide.md")
485
- # => [#<HTM::Models::Node>, #<HTM::Models::Node>, ...]
486
- ```
487
-
488
- **Unload a file**:
489
- ```ruby
490
- # Soft delete all nodes from a file and remove file source
491
- htm.unload_file("docs/guide.md")
492
- ```
493
-
494
- **Re-sync behavior**:
495
- - Files are tracked by path with mtime-based change detection
496
- - If file hasn't changed, `load_file` returns early (unless `force: true`)
497
- - Changed files are re-synced: new chunks created, unchanged chunks kept, removed chunks soft-deleted
498
- - YAML frontmatter is extracted and stored as metadata on the file source
499
-
500
- **Chunking strategy**:
501
- - Text is split by paragraph (blank lines)
502
- - Fenced code blocks (``` and ~~~) are preserved as single chunks
503
- - Very short fragments (<10 chars) are merged with neighbors
504
- - Each chunk becomes a node with `source_id` linking back to the file
505
-
506
- **FileSource model**:
507
- ```ruby
508
- source = HTM::Models::FileSource.find_by(file_path: "docs/guide.md")
509
- source.needs_sync? # Check if file changed since last load
510
- source.chunks # Get all nodes from this file (ordered by position)
511
- source.frontmatter # Get parsed YAML frontmatter hash
512
- source.frontmatter_tags # Get tags from frontmatter (if present)
513
- ```
514
-
515
- **Rake tasks for file loading**:
516
- ```bash
517
- rake 'htm:files:load[docs/guide.md]' # Load a single file
518
- rake 'htm:files:load_dir[docs/]' # Load all markdown files from directory
519
- rake 'htm:files:load_dir[docs/,**/*.md]' # Load with custom glob pattern
520
- rake htm:files:list # List all loaded file sources
521
- rake 'htm:files:info[docs/guide.md]' # Show details for a loaded file
522
- rake 'htm:files:unload[docs/guide.md]' # Unload a file from memory
523
- rake htm:files:sync # Sync all loaded files (reload changed)
524
- rake htm:files:stats # Show file loading statistics
525
-
526
- # Use FORCE=true to reload even if file hasn't changed
527
- FORCE=true rake 'htm:files:load[docs/guide.md]'
528
- ```
529
-
530
- ## Architecture Framework
531
-
532
- HTM uses the [ai-software-architect](https://github.com/codenamev/ai-software-architect) framework for managing architectural decisions and reviews.
533
-
534
- ### Architecture Directory Structure
535
- ```
536
- .architecture/
537
- ├── decisions/adrs/ # Architectural Decision Records
538
- ├── reviews/ # Architecture review documents
539
- ├── recalibration/ # Implementation plans from reviews
540
- ├── comparisons/ # Version comparisons
541
- ├── docs/ # Architecture documentation
542
- ├── templates/ # Document templates
543
- └── members.yml # Review team roster
544
- ```
545
-
546
- ### Working with Architecture
547
-
548
- **View existing ADRs**: Browse `.architecture/decisions/adrs/` for documented architectural decisions.
549
-
550
- **Create new ADR**: Use natural language with Claude Code:
551
- ```
552
- Create an ADR for [topic]
553
- ```
554
-
555
- **Start architecture review**: For version, feature, or component reviews:
556
- ```
557
- Start architecture review for version X.Y.Z
558
- Start architecture review for [feature name]
559
- Review architecture for [component description]
560
- ```
561
-
562
- **Consult specialists**: Invoke specific review perspectives:
563
- ```
564
- Ask Security Architect to review this API design
565
- Ask Performance Specialist to review the caching strategy
566
- Ask AI Engineer to review the RAG implementation
567
- ```
568
-
569
- **View system analysis**: Comprehensive system overview available at `.architecture/reviews/initial-system-analysis.md`.
570
-
571
- ### Review Team
572
-
573
- The architecture review team (defined in `.architecture/members.yml`) includes:
574
- - **Systems Architect**: Distributed systems, scalability, system decomposition
575
- - **Domain Expert**: Domain-driven design, business logic, semantic modeling
576
- - **Security Specialist**: Threat modeling, vulnerability assessment, data protection
577
- - **Maintainability Expert**: Code quality, technical debt, long-term evolution
578
- - **Performance Specialist**: Optimization, profiling, resource utilization
579
- - **AI Engineer**: LLM integration, RAG systems, embedding strategies
580
- - **Ruby Expert**: Ruby idioms, gem development, testing
581
- - **Database Architect**: PostgreSQL, ActiveRecord, pgvector optimization, schema design
582
-
583
- ## Important Notes
584
-
585
- - The gem is under active development; see `htm_teamwork.md` for roadmap
586
- - Database connection requires `HTM_DBURL` environment variable or config/database.yml
587
- - **Async Processing** (ADR-016): Nodes saved immediately (~15ms), embeddings and tags added via background jobs
588
- - **Background Jobs**: Uses `async-job` gem with `GenerateEmbeddingJob` and `GenerateTagsJob`
589
- - **Multi-provider LLM support**: OpenAI, Anthropic, Gemini, Azure, Ollama (default), HuggingFace, OpenRouter, Bedrock, DeepSeek via RubyLLM
590
- - Database uses PostgreSQL 17 with pgvector and pg_trgm extensions
591
- - ActiveRecord models provide ORM layer: Robot, Node, Tag, NodeTag (ADR-013)
592
- - **TagService**: LLM-based hierarchical tag extraction (parallel architecture to EmbeddingService)
593
- - All robots share global memory (hive mind architecture)
594
- - **Soft Delete**: `forget()` performs soft delete by default (recoverable via `restore()`); permanent delete requires `soft: false, confirm: :confirmed`
595
- - Working memory eviction moves nodes to long-term storage, never deletes them
596
- - **Metadata**: Nodes have a JSONB `metadata` column for flexible key-value storage; filter with `recall(..., metadata: {...})`
597
- - **Tag Visualization**: Export tag hierarchy as text tree, Mermaid flowchart, or SVG (dark theme)
598
- - Token counting uses Tiktoken with GPT-3.5-turbo encoding
599
- - Architecture decisions are documented in ADRs (see `.architecture/decisions/adrs/`)
600
- - **Key ADRs**: 001 (PostgreSQL), 013 (ActiveRecord+Tags), **016 (Async Jobs)** [supersedes 014, 015]
601
- - **File Loading**: Load markdown files into memory with `load_file()`, `load_directory()`, `unload_file()` methods
602
- - backward-compatibility is not necessary.
603
- - backward compatibility is never a consideration