brainlayer 1.0.0__py3-none-any.whl
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.
- brainlayer/__init__.py +3 -0
- brainlayer/cli/__init__.py +1545 -0
- brainlayer/cli/wizard.py +132 -0
- brainlayer/cli_new.py +151 -0
- brainlayer/client.py +164 -0
- brainlayer/clustering.py +736 -0
- brainlayer/daemon.py +1105 -0
- brainlayer/dashboard/README.md +129 -0
- brainlayer/dashboard/__init__.py +5 -0
- brainlayer/dashboard/app.py +151 -0
- brainlayer/dashboard/search.py +229 -0
- brainlayer/dashboard/views.py +230 -0
- brainlayer/embeddings.py +131 -0
- brainlayer/engine.py +550 -0
- brainlayer/index_new.py +87 -0
- brainlayer/mcp/__init__.py +1558 -0
- brainlayer/migrate.py +205 -0
- brainlayer/paths.py +43 -0
- brainlayer/pipeline/__init__.py +47 -0
- brainlayer/pipeline/analyze_communication.py +508 -0
- brainlayer/pipeline/brain_graph.py +567 -0
- brainlayer/pipeline/chat_tags.py +63 -0
- brainlayer/pipeline/chunk.py +422 -0
- brainlayer/pipeline/classify.py +472 -0
- brainlayer/pipeline/cluster_sampling.py +73 -0
- brainlayer/pipeline/enrichment.py +810 -0
- brainlayer/pipeline/extract.py +66 -0
- brainlayer/pipeline/extract_claude_desktop.py +149 -0
- brainlayer/pipeline/extract_corrections.py +231 -0
- brainlayer/pipeline/extract_markdown.py +195 -0
- brainlayer/pipeline/extract_whatsapp.py +227 -0
- brainlayer/pipeline/git_overlay.py +301 -0
- brainlayer/pipeline/longitudinal_analyzer.py +568 -0
- brainlayer/pipeline/obsidian_export.py +455 -0
- brainlayer/pipeline/operation_grouping.py +486 -0
- brainlayer/pipeline/plan_linking.py +313 -0
- brainlayer/pipeline/sanitize.py +549 -0
- brainlayer/pipeline/semantic_style.py +574 -0
- brainlayer/pipeline/session_enrichment.py +472 -0
- brainlayer/pipeline/style_embed.py +67 -0
- brainlayer/pipeline/style_index.py +139 -0
- brainlayer/pipeline/temporal_chains.py +203 -0
- brainlayer/pipeline/time_batcher.py +248 -0
- brainlayer/pipeline/unified_timeline.py +569 -0
- brainlayer/storage.py +66 -0
- brainlayer/store.py +155 -0
- brainlayer/taxonomy.json +80 -0
- brainlayer/vector_store.py +1891 -0
- brainlayer-1.0.0.dist-info/METADATA +313 -0
- brainlayer-1.0.0.dist-info/RECORD +53 -0
- brainlayer-1.0.0.dist-info/WHEEL +4 -0
- brainlayer-1.0.0.dist-info/entry_points.txt +4 -0
- brainlayer-1.0.0.dist-info/licenses/LICENSE +190 -0
brainlayer/store.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""brainlayer_store — Write-side memory for BrainLayer.
|
|
2
|
+
|
|
3
|
+
Store ideas, mistakes, decisions, learnings, todos, and bookmarks
|
|
4
|
+
into the BrainLayer knowledge base. Items are embedded at write time
|
|
5
|
+
and searchable immediately.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from brainlayer.store import store_memory
|
|
9
|
+
|
|
10
|
+
result = store_memory(
|
|
11
|
+
store=vector_store,
|
|
12
|
+
embed_fn=model.embed_query,
|
|
13
|
+
content="Always use exponential backoff for retries",
|
|
14
|
+
memory_type="learning",
|
|
15
|
+
project="my-project",
|
|
16
|
+
tags=["reliability", "api"],
|
|
17
|
+
)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import json
|
|
21
|
+
import logging
|
|
22
|
+
import uuid
|
|
23
|
+
from datetime import datetime, timezone
|
|
24
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
25
|
+
|
|
26
|
+
from .vector_store import VectorStore, serialize_f32
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
VALID_MEMORY_TYPES = ["idea", "mistake", "decision", "learning", "todo", "bookmark", "note", "journal"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def store_memory(
|
|
34
|
+
store: VectorStore,
|
|
35
|
+
embed_fn: Callable[[str], List[float]],
|
|
36
|
+
content: str,
|
|
37
|
+
memory_type: str,
|
|
38
|
+
project: Optional[str] = None,
|
|
39
|
+
tags: Optional[List[str]] = None,
|
|
40
|
+
importance: Optional[int] = None,
|
|
41
|
+
) -> Dict[str, Any]:
|
|
42
|
+
"""Persistently store a memory into BrainLayer.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
store: VectorStore instance.
|
|
46
|
+
embed_fn: Function that takes text and returns a 1024-dim embedding vector.
|
|
47
|
+
content: The text content to store.
|
|
48
|
+
memory_type: One of VALID_MEMORY_TYPES.
|
|
49
|
+
project: Optional project name to scope the memory.
|
|
50
|
+
tags: Optional list of tags for categorization.
|
|
51
|
+
importance: Optional importance score (1-10, clamped).
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Dict with 'id' (chunk ID) and 'related' (list of similar existing memories).
|
|
55
|
+
|
|
56
|
+
Raises:
|
|
57
|
+
ValueError: If content is empty or memory_type is invalid.
|
|
58
|
+
"""
|
|
59
|
+
# Validate
|
|
60
|
+
if not content or not content.strip():
|
|
61
|
+
raise ValueError("content must be non-empty")
|
|
62
|
+
if memory_type not in VALID_MEMORY_TYPES:
|
|
63
|
+
raise ValueError(f"type must be one of: {', '.join(VALID_MEMORY_TYPES)}")
|
|
64
|
+
|
|
65
|
+
content = content.strip()
|
|
66
|
+
|
|
67
|
+
# Clamp importance
|
|
68
|
+
if importance is not None:
|
|
69
|
+
importance = max(1, min(10, importance))
|
|
70
|
+
|
|
71
|
+
# Generate chunk ID and timestamps
|
|
72
|
+
chunk_id = f"manual-{uuid.uuid4().hex[:16]}"
|
|
73
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
74
|
+
|
|
75
|
+
# Embed at write time
|
|
76
|
+
embedding = embed_fn(content)
|
|
77
|
+
|
|
78
|
+
# Search for related existing memories BEFORE inserting
|
|
79
|
+
related = _find_related(store, embedding, project=project, limit=3)
|
|
80
|
+
|
|
81
|
+
# Insert into chunks table
|
|
82
|
+
cursor = store.conn.cursor()
|
|
83
|
+
cursor.execute(
|
|
84
|
+
"""
|
|
85
|
+
INSERT INTO chunks
|
|
86
|
+
(id, content, metadata, source_file, project, content_type,
|
|
87
|
+
value_type, char_count, source, created_at, enriched_at,
|
|
88
|
+
summary, tags, importance)
|
|
89
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
90
|
+
""",
|
|
91
|
+
(
|
|
92
|
+
chunk_id,
|
|
93
|
+
content,
|
|
94
|
+
json.dumps({"memory_type": memory_type}),
|
|
95
|
+
"brainlayer-store",
|
|
96
|
+
project,
|
|
97
|
+
memory_type, # content_type = memory_type for easy filtering
|
|
98
|
+
"HIGH",
|
|
99
|
+
len(content),
|
|
100
|
+
"manual",
|
|
101
|
+
now,
|
|
102
|
+
now, # enriched_at = now (user-provided content is pre-enriched)
|
|
103
|
+
content[:200], # summary = first 200 chars
|
|
104
|
+
json.dumps(tags) if tags else None,
|
|
105
|
+
float(importance) if importance is not None else None,
|
|
106
|
+
),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Insert embedding into chunk_vectors
|
|
110
|
+
cursor.execute("DELETE FROM chunk_vectors WHERE chunk_id = ?", (chunk_id,))
|
|
111
|
+
cursor.execute(
|
|
112
|
+
"INSERT INTO chunk_vectors (chunk_id, embedding) VALUES (?, ?)",
|
|
113
|
+
(chunk_id, serialize_f32(embedding)),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Also insert into FTS5 for keyword search
|
|
117
|
+
# (The trigger handles this for INSERT INTO chunks, but since we bypass
|
|
118
|
+
# the normal upsert_chunks flow, verify it's there)
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
"id": chunk_id,
|
|
122
|
+
"related": related,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _find_related(
|
|
127
|
+
store: VectorStore,
|
|
128
|
+
embedding: List[float],
|
|
129
|
+
project: Optional[str] = None,
|
|
130
|
+
limit: int = 3,
|
|
131
|
+
) -> List[Dict[str, Any]]:
|
|
132
|
+
"""Find related existing memories by vector similarity."""
|
|
133
|
+
try:
|
|
134
|
+
results = store.search(
|
|
135
|
+
query_embedding=embedding,
|
|
136
|
+
n_results=limit,
|
|
137
|
+
project_filter=project,
|
|
138
|
+
)
|
|
139
|
+
related = []
|
|
140
|
+
for doc, meta in zip(results["documents"][0], results["metadatas"][0]):
|
|
141
|
+
item: Dict[str, Any] = {"content": doc[:300]}
|
|
142
|
+
if meta.get("summary"):
|
|
143
|
+
item["summary"] = meta["summary"]
|
|
144
|
+
if meta.get("project"):
|
|
145
|
+
item["project"] = meta["project"]
|
|
146
|
+
if meta.get("content_type"):
|
|
147
|
+
item["type"] = meta["content_type"]
|
|
148
|
+
if meta.get("created_at"):
|
|
149
|
+
item["date"] = meta["created_at"][:10]
|
|
150
|
+
related.append(item)
|
|
151
|
+
return related
|
|
152
|
+
except Exception as e:
|
|
153
|
+
# Don't let related search failure block the store — intentionally broad
|
|
154
|
+
logger.warning("Related memory search failed: %s", e)
|
|
155
|
+
return []
|
brainlayer/taxonomy.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"description": "Hierarchical topic labels for BrainLayer chunks. 5 categories, ~50 labels.",
|
|
4
|
+
"categories": {
|
|
5
|
+
"tech": {
|
|
6
|
+
"description": "Technical content — code, debugging, architecture",
|
|
7
|
+
"labels": {
|
|
8
|
+
"tech/code-snippet": "Code written or reviewed",
|
|
9
|
+
"tech/debug/error-trace": "Stack traces, error messages, crash logs",
|
|
10
|
+
"tech/debug/investigation": "Debugging discussion, root cause analysis",
|
|
11
|
+
"tech/architecture": "System design, architectural decisions",
|
|
12
|
+
"tech/config": "Configuration files, env vars, settings",
|
|
13
|
+
"tech/testing": "Test code, test strategies, CI/CD",
|
|
14
|
+
"tech/refactor": "Code refactoring, cleanup, migration",
|
|
15
|
+
"tech/performance": "Performance optimization, profiling",
|
|
16
|
+
"tech/security": "Auth, secrets, security concerns",
|
|
17
|
+
"tech/devops": "Deployment, Docker, Railway, infra",
|
|
18
|
+
"tech/database": "SQL, migrations, schema design",
|
|
19
|
+
"tech/api": "API endpoints, HTTP, REST, GraphQL",
|
|
20
|
+
"tech/frontend": "UI components, CSS, React, Next.js",
|
|
21
|
+
"tech/mobile": "React Native, Expo, mobile-specific",
|
|
22
|
+
"tech/ai-ml": "LLM integration, embeddings, RAG, agents"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"pm": {
|
|
26
|
+
"description": "Project management — planning, decisions, requirements",
|
|
27
|
+
"labels": {
|
|
28
|
+
"pm/planning": "Roadmap, sprint planning, task breakdown",
|
|
29
|
+
"pm/decision": "Architecture decisions, tool choices, trade-offs",
|
|
30
|
+
"pm/requirements": "Feature specs, user stories, PRDs",
|
|
31
|
+
"pm/review": "Code review, PR discussion, feedback",
|
|
32
|
+
"pm/retrospective": "What worked, what didn't, lessons learned"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"personal": {
|
|
36
|
+
"description": "Personal/career — job search, learning, communication",
|
|
37
|
+
"labels": {
|
|
38
|
+
"personal/job-search": "Job applications, interviews, outreach",
|
|
39
|
+
"personal/learning": "Tutorials, research, skill development",
|
|
40
|
+
"personal/writing": "Blog posts, documentation, content creation",
|
|
41
|
+
"personal/communication": "Email drafts, message style, social posts",
|
|
42
|
+
"personal/finance": "Expenses, invoices, tax, payments"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"platform": {
|
|
46
|
+
"description": "Platform-specific — which tool/service the content is about",
|
|
47
|
+
"labels": {
|
|
48
|
+
"platform/claude": "Claude Code, Claude API, Anthropic",
|
|
49
|
+
"platform/github": "GitHub issues, PRs, Actions, repos",
|
|
50
|
+
"platform/supabase": "Supabase DB, auth, storage, edge functions",
|
|
51
|
+
"platform/telegram": "Telegram bot, grammy, messaging",
|
|
52
|
+
"platform/convex": "Convex backend, functions, schema",
|
|
53
|
+
"platform/vercel": "Vercel deployment, Next.js hosting",
|
|
54
|
+
"platform/railway": "Railway deployment, services",
|
|
55
|
+
"platform/obsidian": "Obsidian vault, notes, sync",
|
|
56
|
+
"platform/linear": "Linear issues, project management"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"project": {
|
|
60
|
+
"description": "Project-specific — which codebase/product",
|
|
61
|
+
"labels": {
|
|
62
|
+
"project/my-project": "Example project",
|
|
63
|
+
"project/brainlayer": "BrainLayer memory pipeline",
|
|
64
|
+
"project/app-a": "Example application A",
|
|
65
|
+
"project/app-b": "Example application B",
|
|
66
|
+
"project/personal-site": "Personal website, admin dashboard",
|
|
67
|
+
"project/union": "Union platform"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"meta": {
|
|
71
|
+
"description": "Meta labels — content quality, noise, empty",
|
|
72
|
+
"labels": {
|
|
73
|
+
"meta/noise": "Noise, irrelevant, or garbage content",
|
|
74
|
+
"meta/empty": "Empty or near-empty content (nothing useful)",
|
|
75
|
+
"meta/context-only": "Only useful as context for surrounding chunks",
|
|
76
|
+
"meta/duplicate": "Duplicate or near-duplicate of another chunk"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|