A fast agentic-memory engine:
- uses Go for speed of execution
- uses SQLite + sqlite-vec for vector similarity search
- opinionated procedural memory: uses PDDL (Plan Domain Definition Language) for event sequences
- a semantic-graph augmented for temporal-validity, contradictions tracking, fallacies-identification, sources-evaluation
- very configurable to adapt to data sources types, but no scope creep into OCR, ingestion pipelines, etc...
Classic Karpathy Memory layers:
- Episodic Interaction-log and other information source chuncks, using sqlite-vec for semantic search on embeddings.
- Semantic Entities & Relationships graph with added timeline info, contradictions, fallacies, sources...
- Procedural Not just skills markdown... Also invokes PDDL routers: 1-Native STRIPS BFS, 2-delegation (eg. Fast-Downward) of a semantic graph extract into a PDDL domain to resolve timeline questions, bypassing LLM's planning-logic weaknesses.
- Avoid Bloat: No multi-layered data-extraction pipeline, no nested async generators, no runtime schema generation
- Consolidate Storage: Single SQLite file with
PRAGMA journal_mode = WALfor concurrent reads - Caveat-Qualified Graph: Semantic relationships carry explicit conditions/constraints/exceptions
- Explicit Contradictions: Conflicts are tracked as first-class relationships
- Temporal Bounds: Semantic relationships include validity date-time information
- Vector Search: sqlite-vec distance functions for episodic-memory retrieval
gllam
├── cmd/gllam/
│ └── main.go # CLI Local daemon entry point
├── pkg/
│ ├── engine
│ │ ├── engine.go # SQLite connection, WAL, schema init
│ │ ├── semantic.go # Node/link CRUD, contradiction management
│ │ ├── procedural.go # Workflow recipes, helpfulness scoring
│ │ ├── episodic.go # Session summaries, temporal windows
│ │ └── router.go # Intent classifier & context assembler
│ ├── memory/
│ │ └── types.go # All Go type definitions
│ └── schema/
│ └── schema.sql # Complete SQLite DDL
├── go.mod
└── go.sumgo mod init github.com/laurentalsina/gllam
go get github.com/mattn/go-sqlite3
go get github.com/asg017/sqlite-vec-go-bindings/cgosqlite-vec CGO bindings:
sudo dnf install sqlite-devel # Fedora/RedHat
sudo apt-get install libsqlite3-dev # Ubuntu/Debian
curl -sL https://www.sqlite.org/2024/sqlite-amalgamation-3470200.zip -o /tmp/sqlite.zip
unzip -qo /tmp/sqlite.zip -d /tmp
export CGO_CFLAGS="-I/tmp/sqlite-amalgamation-3470200"
Then build with CGO enabled:
CGO_ENABLED=1 go build ./...
source an env file that contains something like:
export EMBEDDINGS_SERVER="http://127.0.0.1:8800"
export DATABASE_PATH="/home/laurent/Projects/gllam/bench/gllam_data.db"
export OPENROUTER_API_KEY=sk-or-v1-4222222222222222222222222222222222222222222
export STRONG_TEXT_SERVER="https://openrouter.ai/api/v1"
export STRONG_LLM_MODEL="google/gemini-3.7-flash"
export FAST_TEXT_SERVER="http://100.96.179.23:8888"
export FAST_LLM_MODEL="local-server"llama-server -m your-embedding-model.gguf --port 8080
go run ./cmd/gllam -seed
go run ./cmd/gllam --recall "how to deploy caddy" --entity "caddy"
go run ./cmd/gllam --embeddings-server http://localhost:8080 --recall "web server" --entity "caddy"
go run ./cmd/gllam --embeddings-server http://localhost:8080
See the shell-scripts in subfolders of ./bench/
a personal-assistant log focus: remember conversations content and infer answer from it see https://arxiv.org/html/2608.02613v1 for the memarena "personal-memory" paper
more diverse corpus of simulated conversation, with notes, large mash of content see https://arxiv.org/abs/2510.27246 also a conversation corpus
GLLAM gets about 70% on both in its current state, which compares well with state of the art.
An open-source engine, that's really "open-core", selling customized ingestion pipelines to customers.
- On BEAM: Cognee does not publish a score breakdown by category on this benchmark, only scores across corpus scales & setups: 100K Scale (Standard): 79% using one-shot retrieval and custom prompts per question type. 100K Scale (Optimized): "80%+" using a question-type routing, dynamically tuning retrieval params. 10M Scale (Best Run): 67% under their best routing configuration.
- On Memarena: Cognee's not tested on this, or it's not published.
- On HotPotQA (Multi-Hop Reasoning): Claims 90% accuracy for graph-enhanced queries
- On DeepEval Framework (Retrieval Quality Metrics): Claims 84% to 92% correctness.
## Usage as a Library
import (
"context"
"log"
"time"
"github.com/laurentalsina/gllam/pkg/engine"
"github.com/laurentalsina/gllam/pkg/memory"
)
// Initialize with llama.cpp embedder
embedder := engine.NewLlamaEmbedder("http://localhost:8080")
gllam, err := engine.NewGllamEngine("./data.db", embedder)
if err != nil { log.Fatal(err) }
defer gllam.Close()
if err := gllam.InitSchema(); err != nil { log.Fatal(err) }
// Store a semantic node
gllam.UpsertNode(ctx, memory.SemanticNode{ID: "caddy", Name: "Caddy", Type: "service"})
// Generate and store embedding for the node
if err := gllam.StoreNodeEmbedding(ctx, "caddy"); err != nil {
log.Fatal(err)
}
// Store a caveat-qualified link
gllam.AddEdge(ctx, memory.SemanticLink{
SourceID: "caddy", TargetID: "tailscale",
Relationship: "binds_to",
Caveats: "Must use Tailscale FQDN",
ValidFrom: time.Now().Unix(),
})
// Route a user prompt and assemble context
ctxResult, err := gllam.RouteAndAssemble(ctx, "how to deploy caddy", []string{"caddy"})
if err != nil { log.Fatal(err) }
// Format for LLM consumption
prompt := engine.FormatSystemPrompt(ctxResult)
fmt.Print(prompt)
// Semantic similarity search
results, err := gllam.SearchSimilarNodes(ctx, "web server", 5)
if err != nil { log.Fatal(err) }
for _, r := range results {
fmt.Printf("Node: %s (distance: %.4f)\n", r.NodeID, r.Distance)
}
## Database Schema
| Table | Go Type | Purpose |
|-------|---------|---------|
| `semantic_nodes` | `memory.SemanticNode` | Entities (services, IPs, configs...), includes `context_prompt` |
| `semantic_links` | `memory.SemanticLink` | Caveat-qualified, temporally bounded relationships |
| `procedural_knowledge` | `memory.ProceduralKnowledge` | Reusable workflow recipes |
| `episodic_summaries` | `memory.EpisodicSummary` | Session summaries with timestamps |
| `semantic_embeddings` | *vec0 virtual table* | Embedding vectors for similarity search (sqlite-vec) |
### SQLite Configuration
Enforced at connection time:
```sql
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA foreign_keys = ON;
PRAGMA busy_timeout = 5000;
Connection architecture: dual-handle design for true read concurrency:
- Write handle:
SetMaxOpenConns(1)— serializes all mutations through a single connection - Read handle: opened with
mode=roDSN flag,SetMaxOpenConns(8)— concurrent read-only queries never contend with the writer
WAL-mode readers don't block each other, and the read-only file descriptor is completely independent of the writer.
| Method | Description |
|---|---|
NewGllamEngine(dbPath, embedder) |
Open dual-handle SQLite connection with sqlite-vec and embedder |
InitSchema() |
Execute schema.sql DDL |
Close() |
Close both database handles |
DB() |
Return write handle for direct SQL access |
DBRO() |
Return read-only handle for concurrent queries |
| Method | Description |
|---|---|
StoreNodeEmbedding(ctx, nodeID) |
Generate and store embedding for a node |
SearchSimilarNodes(ctx, query, limit) |
Find nodes similar to query text |
NewLlamaEmbedder(baseURL) |
Create embedder for llama.cpp server |
| Method | Description |
|---|---|
UpsertNode(ctx, node) |
Insert or update a node (including its context_prompt) |
AddEdge(ctx, link) |
Insert link; auto-creates contradiction nodes/edges on conflict |
InvalidateObsoleteEdge(ctx, ...) |
Set valid_until for temporal expiration |
| Method | Description |
|---|---|
UpsertProceduralKnowledge(ctx, pk) |
Insert/update recipe (version auto-increments) |
MarkProcedureHelpful(ctx, taskType, helpful) |
Toggle golden-standard flag |
RetrieveProcedure(ctx, taskType) |
Fetch recipe + increment times_applied |
GetTopProcedures(ctx, limit) |
Ordered by helpfulness then usage |
| Method | Description |
|---|---|
SaveEpisodicSummary(ctx, summary) |
Store session summary |
GetRecentEpisodes(ctx, limit) |
Top N by created_at DESC |
GetEpisodesInWindow(ctx, start, end) |
Temporal range query |
| Method | Description |
|---|---|
RouteAndAssemble(ctx, prompt, entities) |
Classify intent, retrieve relevant data |
FormatSystemPrompt(ctx) |
Format compiled context as Markdown |
sqlite-vec is registered globally via sqlite_vec.Auto() and provides SIMD-optimized vector operations. Use directly in SQL queries:
-- Create a vector virtual table
CREATE VIRTUAL TABLE semantic_embeddings USING vec0(
node_id INTEGER PRIMARY KEY,
embedding float[1536]
);
-- Insert embeddings
INSERT INTO semantic_embeddings(node_id, embedding)
VALUES (?, vec_f32(?));
-- Similarity search (lower distance = more similar)
SELECT node_id, distance
FROM semantic_embeddings
WHERE embedding MATCH vec_f32(?)
ORDER BY distance
LIMIT 10;Contradictions that remain stored will be of a temporal nature, eg. only version x of some software supports feature y.
When AddEdge() detects an existing active link with the same source_id and a mutually exclusive relationship (e.g. has_state, located_in) but a different target_id:
- It compares the
trust_weight(integer in[10, 1000]) of both origin sources (OriginSourceID). - If a highly trusted source (e.g.
Jira ResolvedorMerged Pull Request,$W = 900$ ) conflicts with a low-trust source (e.g.Email Draft,$W = 100$ ), the low-trust claim is automatically expired (valid_until = now) and superseded with aresolves_conflictedge. - This completely bypasses the need for manual user grilling or unresolved contradiction nodes!
- If trust weights are equal, GLLAM falls back to creating an explicit
NodeTypeContradictionnode for planner or user resolution (or auto-resolves by recency ifAllowUserGrilling = false).
-
Document Type Base (
$W_{\text{doc_type}}$ ): Jira Resolved / Merged PR (800), Approved Architecture Doc (700), Jira Open / Slack / Incident Log (600), Email Thread / Support Ticket (400), Draft / Scratchpad (200). -
Source Identity (
$W_{\text{source}}$ ): Person / source handle adjustments fromSourceReliabilityHeuristics(e.g. Alice+150, Carol+200, Dave-150), falling back to roles (System CI/CD+150, Tech Lead+100, Verified Eng+50). -
Internal Semantic Coherence (
$\Delta W_{\text{coherence}}$ ): Shannon character entropy & non-lexical noise check (+50 boost for valid prose, -250 penalty for DoS / gibberish). -
Temporal Freshness (
$\Delta W_{\text{temporal_freshness}}$ ): < 30 days old (+50), > 6 months old (-50), > 1 year old (-150).
GLLAM provides a dedicated JSON configuration system (config/agentic_memory_prompts.json & pkg/config/agentic_memory.go) to define system prompts, repository directives, and source trust heuristics without re-compiling code:
{
"allow_user_grilling": true,
"ingestion_steering_directives": {
"confluence": { "track_revision_history": true, "max_revision_depth": 10, "compact_author_epochs": true },
"jira": { "track_comment_history": true, "track_status_transitions": true, "compact_author_epochs": true },
"git": { "track_branch_merges": true, "track_revision_history": true, "compact_author_epochs": true }
},
"custom_document_type_rules": {
"notion_workspace": {
"type_name": "notion_workspace",
"baseline_trust_weight": 600,
"ingestion_strategy": { "track_revision_history": true, "compact_author_epochs": true }
}
},
"repository_context_directives": {
"jira": {
"repository_type": "jira",
"extraction_prompt": "Extract Jira issue key, status transitions, resolution, priority, and epic linkage into entity context profiles.",
"context_template": "Jira Issue: {{key}}\nType: {{type}}\nStatus: {{status}}\nResolution: {{resolution}}"
}
},
"trust_weight_prompt": "EVALUATION RULESET FOR SOURCE TRUST WEIGHTING (W in [10, 1000])...",
"source_reliability_prompt": "INDIVIDUAL SOURCE RELIABILITY HEURISTICS...",
"source_reliability_heuristics": {
"alice": 150,
"carol_lead": 200,
"dave_drafts": -150
}
}// Load custom agentic memory prompts
err := gllam.LoadSystemPromptsConfig("./config/agentic_memory_prompts.json")
// Register dynamic custom document type
gllam.RegisterCustomDocumentTypeRule(config.CustomDocumentTypeRule{
TypeName: "notion_workspace",
BaselineTrustWeight: 650,
IngestionStrategy: config.IngestionStrategy{TrackRevisionHistory: true, CompactAuthorEpochs: true},
})
// Register documentation repository context directive
gllam.RegisterRepositoryContextDirective(config.RepositoryContextDirective{
RepositoryType: "sharepoint",
ExtractionPrompt: "Extract SharePoint site URL, document library, and version label into entity context profiles.",
ContextTemplate: "SharePoint Doc: {{doc_name}}\nLibrary: {{library}}\nSite: {{site}}",
})
// Attribute comment inside Jira container directly to individual source node
sourceID, trustWeight, err := gllam.AttributeContainerEntryToSource(ctx, "jira", "alice", "Alice Smith", "Comment 1: DB is PostgreSQL 15.", time.Now().Unix())To prevent a flat semantic graph from devolving into an unsearchable hairball across 15,000+ Jira issues and 10,000+ Confluence pages, GLLAM features an Autonomous Ontological Layer:
-
Materialized Path SQLite Indexing:
- Nodes store hierarchical paths in
taxonomy_path TEXT DEFAULT '/'(e.g./Engineering/Infrastructure/Databases/Relational/Postgres) and booleanis_category INTEGER DEFAULT 0. - Enables instantaneous hierarchical filtering via
taxonomy_path LIKE '/Engineering/Infrastructure/Databases/%'.
- Nodes store hierarchical paths in
-
Asynchronous Batch Categorization (
ProcessUncategorizedBatch):- Decoupled from bulk ingestion pipeline; pulls orphaned nodes (
taxonomy_path = '/') and categorizes them into category nodes (NodeTypeCategory = "category") with explicitis_alinks.
- Decoupled from bulk ingestion pipeline; pulls orphaned nodes (
-
Cyclic Path Prevention (
DetectTaxonomyCycles&WouldCreateTaxonomyCycle):- Uses Kahn's Topological Sort Algorithm to detect and prevent circular parent-child relationships (e.g.
/Infrastructure/Storage$\rightarrow$ /Storage/Databases$\rightarrow$ /Infrastructure/Storage).
- Uses Kahn's Topological Sort Algorithm to detect and prevent circular parent-child relationships (e.g.
-
Self-Healing Bounded Taxonomy Consolidation (
ConsolidateTaxonomyBranch):- Merges redundant categories (e.g.
/Engineering/DBsinto/Engineering/Infrastructure/Databases) using chunked 500-row write transactions and 10ms yield pauses to eliminate SQLite write lock stalls during bulk path rewrites.
- Merges redundant categories (e.g.
-
Procedural Domain Binding (
GetProceduresByTaxonomyPrefix):- Supercharges procedural knowledge retrieval by isolating operational recipes bound to target taxonomy sub-trees.
// Instantaneous hierarchical filtering
nodes, err := gllam.GetNodesByTaxonomyPrefix(ctx, "/Engineering/Infrastructure/Databases")
// Asynchronous batch classification of orphaned nodes
processedCount, err := gllam.ProcessUncategorizedBatch(ctx, 50)
// Detect circular taxonomy paths across is_a/subclass_of edges
hasCycle, cyclicNodes, err := gllam.DetectTaxonomyCycles(ctx)
// Self-healing taxonomy branch consolidation
err := gllam.ConsolidateTaxonomyBranch(ctx, "/Engineering/DBs", "/Engineering/Infrastructure/Databases")
// Domain-isolated procedural recipe retrieval
recipes, err := gllam.GetProceduresByTaxonomyPrefix(ctx, "/Engineering/Infrastructure/Databases")High-scale memory systems require a periodic offline Memory Maintenance Cycle (EnterMemorySleepCycle) to prevent memory degradation and measure graph consistency:
-
Maintenance Compaction & Cleaning:
- Runs Hub Node Caveat Compaction (
BatchCompactHubCaveats) to condense historical caveats while preserving all expired temporal links forever in SQLite for bi-temporal lineage and historical RAG queries. - Runs autonomous self-healing taxonomy branch discovery (
DiscoverTaxonomyMergeCandidates&ConsolidateTaxonomyBranch) during sleep cycles to discover and merge redundant or synonym category paths without deleting category nodes. - Processes uncategorized entity nodes (
ProcessUncategorizedBatch).
- Runs Hub Node Caveat Compaction (
-
Synthetic Random Trace Tests & Memory Exercise (
SimulateRandomTraceTests):- Generates synthetic question/answer trace scenarios across randomly sampled entity pairs.
- Exercises multi-hop graph retrieval (
FindMultiHopPath). - Measures quantitative metrics via
CalculateTraceClarityandCalculateTaxonomyPathOverlap:-
Memory Clarity Score (
$\text{Clarity} \in [0.0, 1.0]$ ): Calculated from multi-hop distance decay ($\frac{1.0}{1.0 + 0.1 \times (\text{hops} - 1)}$ ), link caveats, contradiction penalties (resolves_conflict,subverts_claim), or materialized taxonomy path segment overlap coefficients. -
Memory Consistency Score (
$\text{Consistency} \in [0.0, 1.0]$ ): Ratio of consistent simulated answers across sampled trace pairs.
-
Memory Clarity Score (
// Trigger offline memory maintenance cycle with 10 synthetic random trace tests
report, err := gllam.EnterMemorySleepCycle(ctx, 10)
fmt.Printf("Compacted Revisions: %d\n", report.CompactedRevisionsCount)
fmt.Printf("Memory Clarity Score: %.2f\n", report.MemoryClarityScore)
fmt.Printf("Memory Consistency Score: %.2f\n", report.MemoryConsistencyScore)GLLAM allows steering how documents, version histories, and multi-author transcripts are ingested via AgenticMemorySystemPrompts:
- Targeted Per-Content-Type Prompts (
IngestionSteeringPrompts): Provides tailored extraction prompts for specific document types ("jira","confluence","git","slack","pull_request"). This prevents prompt token bloat and avoids diluting LLM instruction compliance with rules for unrelated document types. - Global Fallback Prompt (
IngestionSteeringPrompt): Serves as a global fallback prompt when ingesting custom document types without a specific prompt. - Ingestion Strategies (
IngestionSteeringDirectives&DetermineDocumentIngestionStrategy): Configures boolean flags for tracking revision histories, comment threads, status transitions, and author epoch compaction.
// Retrieve targeted ingestion steering prompt for Jira issues (falls back to global if unconfigured)
jiraPrompt := gllam.SystemPrompts.GetIngestionSteeringPrompt("jira")
// Determine ingestion strategy flags for Confluence pages
confStrategy := gllam.DetermineDocumentIngestionStrategy("confluence")To prevent WAL file swelling and checkpoint stalls (SQLITE_BUSY) during high-frequency bulk ingestion (e.g. 15,000+ Jira issues and 10,000+ Confluence pages), GLLAM implements explicit WAL checkpointing and strict read-only handle isolation:
- Dedicated Connection Pragmas:
- Write Handle (
db):MaxOpenConns = 1,PRAGMA journal_mode = WAL,PRAGMA wal_autocheckpoint = 1000,PRAGMA busy_timeout = 5000. - Read Handle (
dbRO):MaxOpenConns = 8,PRAGMA query_only = ON;,PRAGMA busy_timeout = 5000;. Read operations cannot lock the writer or attempt invalid mutations.
- Write Handle (
- Explicit WAL Checkpoint API (
CheckpointWAL):- Executes explicit
PRAGMA wal_checkpoint(RESTART)orPRAGMA wal_checkpoint(TRUNCATE)flushes.
- Executes explicit
- Background Checkpoint Manager (
StartWALCheckpointManager):- Asynchronous background goroutine that manages WAL size during idle ingestion windows.
// Launch background WAL Checkpoint Manager running every 5 seconds
gllam.StartWALCheckpointManager(ctx, 5*time.Second)
// Manually trigger a WAL restart or truncation checkpoint
logPages, checkpointedPages, err := gllam.CheckpointWAL(ctx, "RESTART")Swapping or upgrading the local embedding model midway through ingesting a dataset makes stored vector embeddings in sqlite-vec mathematically incompatible with new embeddings, degrading Reciprocal Rank Fusion (RetrieveHybridNeedle). GLLAM prevents vector space drift through automated version metadata tracking and background re-indexing:
- Model Version Metadata: Tracks
embedding_model_versioninsystem_metadata. - Drift Detection (
CheckEmbeddingModelVersion): Compares stored model version with activeembedder.ModelVersion(). - Automated Re-Embedding (
ReembedAllSemanticNodes): Background worker re-computes vector embeddings across allsemantic_nodesand updatessemantic_embeddingsvirtual table.
// Check for vector space drift on engine initialization
drift, prevModel, activeModel, err := gllam.CheckEmbeddingModelVersion(ctx)
if drift {
log.Printf("Vector space drift detected (%s -> %s). Re-embedding nodes...", prevModel, activeModel)
reembeddedCount, err := gllam.ReembedAllSemanticNodes(ctx)
}Core enterprise hub entities (e.g. "Auth Service" or "Production Database") accumulate hundreds of caveats across years of Jira tickets, causing context window bloat and confusing LLM reasoning. GLLAM implements salience windowing and node caveat compaction:
-
Caveat Ranking: Orders caveats by Active Validity (
valid_until IS NULL), Source Trust Weight ($W_{\text{trust}}$ ), and Recency. -
Inline Windowing (
maxInline): Retains Top-K (default 5) active high-trust caveats inline. -
Historical Epoch Compaction (
CompactNodeCaveats): Synthesizes older/lower-trust caveats into a node-levelcaveat_summarystring stored onsemantic_nodes.
// Compact caveats for a hub entity node, retaining Top 5 inline caveats
summaryText, retainedCount, prunedCount, err := gllam.CompactNodeCaveats(ctx, "node-auth-service", 5)
// Run batch compaction across all hub entities with > 10 caveats
compactedHubs, err := gllam.BatchCompactHubCaveats(ctx, 10, 5)When scaling past 100,000 extracted semantic_nodes, executing embedding model calls and updating virtual vector tables (sqlite-vec vec0) inside the primary write transaction drastically increases commit latency. GLLAM decouples relational graph insertion from vector virtual table creation:
- Sub-Millisecond Relational Commit:
UpsertNodecommits relational graph entities to SQLite immediately. - Background Unembedded Queue (
ProcessUnembeddedNodeBatch): Queries nodes wherev.node_id IS NULL. - Embedding Worker Pool (
StartEmbeddingWorkerPool): Launches background worker goroutines that generate embeddings and populatesemantic_embeddingsasynchronously.
// Launch background embedding worker pool (2 workers polling every 2 seconds)
gllam.StartEmbeddingWorkerPool(ctx, 2, 2*time.Second)
// Manually process a batch of unindexed vector embeddings
indexedCount, err := gllam.ProcessUnembeddedNodeBatch(ctx, 50)In enterprise datasets with circular component dependencies (e.g. Service A Spec B Rule C Service A), upstream state invalidation risks entering infinite recursive loops. GLLAM implements active stack cycle prevention:
- Active Call Stack Tracking (
activeStack): Tracks nodes in the current recursion branch. IfactiveStack[currentNodeID] == true, branch recursion terminates with a diagnostic log. - Adaptive Propagation Depth: Allows deep dependency propagation (default 10 hops) without getting trapped in circular graph loops.
// Trigger cascading cross-cutting invalidation across downstream dependencies
err := gllam.InvalidateDependentCrossCuttingLinks(ctx, "service-a", "2000")GLLAM treats logical fallacies in user or agent input as first-class cognitive nodes (NodeTypeFallacy) to prevent deceptive or flawed premises from corrupting automated reasoning.
Fallacies are classified across 6 major categories (referencing the Wikipedia List of Fallacies):
| Fallacy Key | Plain English Meaning & Example | Engine Impact |
|---|---|---|
post_hoc (Post Hoc Ergo Propter Hoc) |
"After this, therefore because of this" — Blindly assuming Event A caused Event B simply because B occurred after A (e.g. "We deployed Caddy, then the server rebooted, so Caddy crashed the server"). | Downgrades causes link to a weak happened_before temporal observation. |
cum_hoc (Cum Hoc Ergo Propter Hoc) |
"With this, therefore because of this" — Confusing correlation with causation (e.g. "CPU usage rose whenever user logins increased"). | Prevents inserting hard depends_on dependencies without explicit proof. |
false_dilemma |
"False Dichotomy" — Forcing a fake binary choice when middle options exist (e.g. "Either we delete the database or the migration fails"). | Prevents promoting either choice to a global or must_follow_rule constraint. |
begging_question (Circularity) |
Premise assumes the unproven conclusion (e.g. "Postgres is reliable because Postgres never fails"). | Disables cyclic PDDL action preconditions. |
equivocation |
Using an ambiguous term in two different senses within the same premise (e.g. using "service" to mean both systemd service and cloud API). | Triggers DisambiguateEntityForSource to split ambiguous nodes. |
ad_hominem |
Attacking the person or agent issuing the claim rather than addressing the claim's substance. | Preserves the underlying claim, flags source attack edge. |
straw_man |
Misrepresenting a rule or claim to make it easy to refute or override. | Prevents overriding established rules without matching rationale. |
red_herring |
Introducing an irrelevant topic to distract from an active contradiction. | Suppresses multi-hop graph expansion for that sub-graph during retrieval. |
GLLAM includes modular benchmark scripts located in ./bench/:
For MemoryArena
- https://huggingface.co/datasets/zthsecondantigravity/memarena-l
./bench/run_d7_qa_extract_semantics.sh: Extracts semantic nodes & links into SQLite (supports--resumefor automatic checkpointing across interruptions)../bench/run_d7_qa_audit.sh: Generates model-tagged extraction snapshots (extraction_snapshot_<model_slug>.json) and compares node/link distributions against previous runs../bench/run_d7_qa_eval.sh: Evaluatesd7_qaquestions againstgllam_data.db, persisting PDDL domain files to./bench/pddl_domains/and results tod7_qa_results_<model_slug>.jsonl../bench/run_d7_qa_grade_results.sh: Runs strict LLM correctness judge, printingPASS/FAILmetrics and generating markdown failure diagnostic reports (d7_qa_failures_<model_slug>.md)../bench/run_d7_qa_all.sh: Executes the full 4-stage pipeline sequentially.
cmd/extract_semantics maintains an extracted_sessions checkpoint table in SQLite:
- Default Resume (
--resume): Automatically skips sessions that have already been extracted in prior runs. - Clean Purge (
--clean): Wipes existing nodes, links, and checkpoints to restart extraction from scratch.
# Resume extraction from checkpoint:
go run ./cmd/extract_semantics/main.go --db ./bench/gllam_data.db --prefix sess_ --concurrency 10
# Clean purge & restart:
go run ./cmd/extract_semantics/main.go --db ./bench/gllam_data.db --prefix sess_ --cleanGLLAM supports both local LLM endpoints (e.g. llama.cpp, vLLM) and cloud APIs like OpenRouter:
export CGO_ENABLED=1
export CGO_CFLAGS="-I/home/laurent/vllm/.venv/lib/python3.13/site-packages/_rocm_sdk_devel/lib/rocm_sysdeps/include"
./bench/run_d7_qa_all.sh http://100.96.179.19:8888export OPENROUTER_API_KEY="sk-or-v1-your-api-key-here"
export LLM_MODEL="qwen/qwen-plus" # or "qwen/qwen-2.5-vl-72b-instruct" or "deepseek/deepseek-chat"
export CGO_ENABLED=1
export CGO_CFLAGS="-I/home/laurent/vllm/.venv/lib/python3.13/site-packages/_rocm_sdk_devel/lib/rocm_sysdeps/include"
./bench/run_d7_qa_all.shGLLAM uses a pluggable embedder interface for generating vector embeddings:
type Embedder interface {
Embed(ctx context.Context, text string) ([]float32, error)
}The LlamaEmbedder connects to a running embeddings server (e.g., llama-server):
# Start embeddings server with an embedding model
llama-server -m nomic-embed-text.gguf --port 8080embedder := engine.NewLlamaEmbedder("http://localhost:8080")
gllam, err := engine.NewGllamEngine("./data.db", embedder)Behavior:
- Hard fail if server is unreachable (no fallback)
- 30-second timeout per request
- Embeddings generated on-demand via
StoreNodeEmbedding()orSearchSimilarNodes()
Implement the Embedder interface for other sources:
type MyEmbedder struct { /* ... */ }
func (m *MyEmbedder) Embed(ctx context.Context, text string) ([]float32, error) {
// Your embedding logic
return vector, nil
}When running the full GLLAM locally, it requires an LLM, an embedding model, and the Fast Downward solver.
Start the models, for example:
cd ~/your_llm_servers_folder/
./serve_Ornith-1.0.sh
./serve_qwen3.6_embeddings.shRequires the Fast Downward C++ binary:
cd ~/Projects
git clone https://github.com/aibasel/downward.git
cd downward
./build.py(GLLAM's FastDownwardPlanner defaults to executing ~/Projects/downward/fast-downward.py)
(C) Laurent Alsina Blackmore 2026 - All rights reserved