brainiac-cli 0.16.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.
- brain/__init__.py +39 -0
- brain/__main__.py +14 -0
- brain/_assets/AGENTS.md +564 -0
- brain/_assets/overlay/template/brand/brand-guide.md +24 -0
- brain/_assets/overlay/template/keywords/glossary.md +15 -0
- brain/_assets/overlay/template/people/roster.md +14 -0
- brain/_assets/overlay/template/voice/voice-profile.md +34 -0
- brain/_assets/routines/manifest.json +257 -0
- brain/_assets/scripts/brain-brief-mac.plist +59 -0
- brain/_assets/scripts/brain-brief.sh +74 -0
- brain/_assets/scripts/brain-synthesis-mac.plist +48 -0
- brain/_assets/scripts/brain-synthesis.sh +214 -0
- brain/_assets/scripts/install-brief-mac.sh +152 -0
- brain/_assets/scripts/install-brief-windows.ps1 +97 -0
- brain/_assets/scripts/register_tasks.py +386 -0
- brain/_assets/templates/company.md +21 -0
- brain/_assets/templates/concept.md +27 -0
- brain/_assets/templates/daily.md +20 -0
- brain/_assets/templates/decision.md +42 -0
- brain/_assets/templates/meeting.md +33 -0
- brain/_assets/templates/person.md +20 -0
- brain/_assets/templates/project.md +23 -0
- brain/_assets/templates/state-moc.md +40 -0
- brain/_version.py +12 -0
- brain/anchor.py +121 -0
- brain/audit.py +422 -0
- brain/backup.py +210 -0
- brain/brief.py +417 -0
- brain/capture.py +117 -0
- brain/chunk.py +249 -0
- brain/classification.py +134 -0
- brain/cli.py +1906 -0
- brain/config.py +368 -0
- brain/connect.py +362 -0
- brain/context.py +108 -0
- brain/core.py +3018 -0
- brain/doctor.py +1161 -0
- brain/egress.py +148 -0
- brain/embed.py +857 -0
- brain/encryption.py +217 -0
- brain/frontmatter.py +102 -0
- brain/golden_probe.py +678 -0
- brain/graph.py +369 -0
- brain/graphify.py +352 -0
- brain/index.py +1576 -0
- brain/ingest/__init__.py +19 -0
- brain/ingest/handlers/__init__.py +43 -0
- brain/ingest/handlers/base.py +95 -0
- brain/ingest/handlers/docx.py +78 -0
- brain/ingest/handlers/email.py +228 -0
- brain/ingest/handlers/html.py +142 -0
- brain/ingest/handlers/image.py +91 -0
- brain/ingest/handlers/pdf.py +99 -0
- brain/ingest/handlers/pptx.py +69 -0
- brain/ingest/handlers/tables.py +41 -0
- brain/ingest/handlers/text.py +43 -0
- brain/ingest/handlers/xlsx.py +100 -0
- brain/ingest/handlers/zip.py +163 -0
- brain/ingest/pipeline.py +839 -0
- brain/ingest/transcript.py +158 -0
- brain/init.py +870 -0
- brain/maintenance.py +2266 -0
- brain/mcp_adapter.py +217 -0
- brain/multihop.py +232 -0
- brain/notes.py +195 -0
- brain/overlay.py +183 -0
- brain/projection.py +79 -0
- brain/rerank.py +425 -0
- brain/snapshot.py +231 -0
- brain/update.py +743 -0
- brain/vectors.py +225 -0
- brainiac_cli-0.16.0.dist-info/METADATA +306 -0
- brainiac_cli-0.16.0.dist-info/RECORD +77 -0
- brainiac_cli-0.16.0.dist-info/WHEEL +5 -0
- brainiac_cli-0.16.0.dist-info/entry_points.txt +4 -0
- brainiac_cli-0.16.0.dist-info/licenses/LICENSE +202 -0
- brainiac_cli-0.16.0.dist-info/top_level.txt +1 -0
brain/vectors.py
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Dense-vector backend ADAPTER INTERFACE + a fallback backend.
|
|
2
|
+
|
|
3
|
+
CORE-01 hardening (r2-codex): "Define an adapter interface with a fallback
|
|
4
|
+
vector backend BEFORE any retrieval code is written." sqlite-vec is pre-v1
|
|
5
|
+
(breaking changes expected) and may fail to load on a locked Windows install or
|
|
6
|
+
an unbuilt Cowork VM. The retrieval layer therefore depends ONLY on the
|
|
7
|
+
``VectorBackend`` protocol, never on sqlite-vec directly.
|
|
8
|
+
|
|
9
|
+
Two backends ship:
|
|
10
|
+
* ``SqliteVecBackend`` — sqlite-vec ``vec0`` virtual table (fast ANN). Used
|
|
11
|
+
when the extension loads.
|
|
12
|
+
* ``BruteForceBackend`` — vectors stored as BLOBs in a plain table; cosine
|
|
13
|
+
computed in Python. No extension, works with ANY
|
|
14
|
+
sqlite build (including a future SQLCipher build),
|
|
15
|
+
correct everywhere. The guaranteed fallback.
|
|
16
|
+
|
|
17
|
+
``get_backend()`` selects sqlite-vec when available and degrades to brute force
|
|
18
|
+
otherwise — the caller's retrieval code is identical either way.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import math
|
|
23
|
+
import sqlite3
|
|
24
|
+
import struct
|
|
25
|
+
from typing import Protocol, Sequence, runtime_checkable
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def pack_vector(vec: Sequence[float]) -> bytes:
|
|
29
|
+
return struct.pack(f"{len(vec)}f", *vec)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def unpack_vector(blob: bytes) -> list[float]:
|
|
33
|
+
return list(struct.unpack(f"{len(blob) // 4}f", blob))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def cosine(a: Sequence[float], b: Sequence[float]) -> float:
|
|
37
|
+
dot = sum(x * y for x, y in zip(a, b))
|
|
38
|
+
na = math.sqrt(sum(x * x for x in a))
|
|
39
|
+
nb = math.sqrt(sum(y * y for y in b))
|
|
40
|
+
if na == 0.0 or nb == 0.0:
|
|
41
|
+
return 0.0
|
|
42
|
+
return dot / (na * nb)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@runtime_checkable
|
|
46
|
+
class VectorBackend(Protocol):
|
|
47
|
+
"""The only contract the retrieval layer is allowed to depend on."""
|
|
48
|
+
|
|
49
|
+
name: str
|
|
50
|
+
|
|
51
|
+
def setup(self, conn: sqlite3.Connection, dim: int) -> None: ...
|
|
52
|
+
def upsert(self, conn: sqlite3.Connection, rowid: int, vec: Sequence[float]) -> None: ...
|
|
53
|
+
def delete(self, conn: sqlite3.Connection, rowid: int) -> None: ...
|
|
54
|
+
def delete_all(self, conn: sqlite3.Connection) -> None: ...
|
|
55
|
+
def search(
|
|
56
|
+
self, conn: sqlite3.Connection, query: Sequence[float], k: int
|
|
57
|
+
) -> list[tuple[int, float]]:
|
|
58
|
+
"""Return [(rowid, similarity 0..1)] best-first."""
|
|
59
|
+
|
|
60
|
+
def get_vectors(
|
|
61
|
+
self, conn: sqlite3.Connection, rowids: Sequence[int]
|
|
62
|
+
) -> dict[int, list[float]]:
|
|
63
|
+
"""Fetch stored vectors for the given chunk rowids (missing rowids are
|
|
64
|
+
simply absent from the result). Used by retrieval-time diversity /
|
|
65
|
+
near-duplicate suppression, which needs candidate-vs-candidate cosine
|
|
66
|
+
without re-embedding."""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class SqliteVecBackend:
|
|
70
|
+
name = "sqlite-vec"
|
|
71
|
+
|
|
72
|
+
def __init__(self) -> None:
|
|
73
|
+
import sqlite_vec # noqa: F401 (import-time check; raises if absent)
|
|
74
|
+
|
|
75
|
+
self._sqlite_vec = sqlite_vec
|
|
76
|
+
self._dim = 0
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def available() -> bool:
|
|
80
|
+
try:
|
|
81
|
+
import sqlite_vec # noqa: F401
|
|
82
|
+
|
|
83
|
+
return True
|
|
84
|
+
except Exception:
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def loadable() -> bool:
|
|
89
|
+
"""True iff the native ``vec0`` extension actually DLOPENS — not just that
|
|
90
|
+
the Python wrapper imports. A packaged build can ship the ``sqlite_vec``
|
|
91
|
+
Python module but omit the native ``vec0.dylib``/``.so``/``.dll`` (observed
|
|
92
|
+
S10: macOS PyInstaller bundle). ``available()`` (import-only) returns True
|
|
93
|
+
in that case but ``setup()`` then crashes on dlopen — so the ``auto``
|
|
94
|
+
selector probes a real load here and degrades to brute-force on failure."""
|
|
95
|
+
try:
|
|
96
|
+
import sqlite3 as _sq
|
|
97
|
+
|
|
98
|
+
be = SqliteVecBackend()
|
|
99
|
+
con = _sq.connect(":memory:")
|
|
100
|
+
try:
|
|
101
|
+
be.load_into(con)
|
|
102
|
+
return True
|
|
103
|
+
finally:
|
|
104
|
+
con.close()
|
|
105
|
+
except Exception:
|
|
106
|
+
return False
|
|
107
|
+
|
|
108
|
+
def load_into(self, conn: sqlite3.Connection) -> None:
|
|
109
|
+
conn.enable_load_extension(True)
|
|
110
|
+
self._sqlite_vec.load(conn)
|
|
111
|
+
conn.enable_load_extension(False)
|
|
112
|
+
|
|
113
|
+
def setup(self, conn: sqlite3.Connection, dim: int) -> None:
|
|
114
|
+
self._dim = dim
|
|
115
|
+
self.load_into(conn)
|
|
116
|
+
conn.execute("DROP TABLE IF EXISTS vec_index")
|
|
117
|
+
conn.execute(f"CREATE VIRTUAL TABLE vec_index USING vec0(embedding float[{dim}])")
|
|
118
|
+
|
|
119
|
+
def upsert(self, conn: sqlite3.Connection, rowid: int, vec: Sequence[float]) -> None:
|
|
120
|
+
conn.execute("DELETE FROM vec_index WHERE rowid = ?", (rowid,))
|
|
121
|
+
conn.execute(
|
|
122
|
+
"INSERT INTO vec_index(rowid, embedding) VALUES (?, ?)",
|
|
123
|
+
(rowid, pack_vector(vec)),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def delete(self, conn: sqlite3.Connection, rowid: int) -> None:
|
|
127
|
+
conn.execute("DELETE FROM vec_index WHERE rowid = ?", (rowid,))
|
|
128
|
+
|
|
129
|
+
def delete_all(self, conn: sqlite3.Connection) -> None:
|
|
130
|
+
conn.execute("DELETE FROM vec_index")
|
|
131
|
+
|
|
132
|
+
def search(self, conn, query, k):
|
|
133
|
+
# Express k as an ``AND k = ?`` MATCH constraint, NOT a bound ``LIMIT ?``.
|
|
134
|
+
# Newer sqlite (>=~3.41) pushes a parameterised LIMIT into vec0's query
|
|
135
|
+
# planner so ``ORDER BY distance LIMIT ?`` works, but older builds (e.g.
|
|
136
|
+
# the Cowork device VM's bundled sqlite) do not, and vec0 then raises
|
|
137
|
+
# "A LIMIT or 'k = ?' constraint is required on vec0 knn queries". The
|
|
138
|
+
# ``k = ?`` form is sqlite-vec's canonical KNN API and is version-robust.
|
|
139
|
+
rows = conn.execute(
|
|
140
|
+
"SELECT rowid, distance FROM vec_index "
|
|
141
|
+
"WHERE embedding MATCH ? AND k = ? ORDER BY distance",
|
|
142
|
+
(pack_vector(query), k),
|
|
143
|
+
).fetchall()
|
|
144
|
+
# vec0 default metric is L2; convert to a 0..1 similarity for a uniform
|
|
145
|
+
# contract with the brute-force backend.
|
|
146
|
+
return [(int(r[0]), 1.0 / (1.0 + float(r[1]))) for r in rows]
|
|
147
|
+
|
|
148
|
+
def get_vectors(self, conn, rowids):
|
|
149
|
+
if not rowids:
|
|
150
|
+
return {}
|
|
151
|
+
qmarks = ",".join("?" * len(rowids))
|
|
152
|
+
out: dict[int, list[float]] = {}
|
|
153
|
+
for rowid, blob in conn.execute(
|
|
154
|
+
f"SELECT rowid, embedding FROM vec_index WHERE rowid IN ({qmarks})",
|
|
155
|
+
tuple(int(r) for r in rowids),
|
|
156
|
+
):
|
|
157
|
+
out[int(rowid)] = unpack_vector(blob)
|
|
158
|
+
return out
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class BruteForceBackend:
|
|
162
|
+
"""Pure-Python fallback. Stores vectors as BLOBs in a normal table and ranks
|
|
163
|
+
by cosine in Python. Slower at scale but correct and dependency-free; the
|
|
164
|
+
SQLCipher-safe path (no loadable extension required)."""
|
|
165
|
+
|
|
166
|
+
name = "brute-force"
|
|
167
|
+
|
|
168
|
+
def setup(self, conn: sqlite3.Connection, dim: int) -> None:
|
|
169
|
+
conn.execute("DROP TABLE IF EXISTS vec_blob")
|
|
170
|
+
conn.execute(
|
|
171
|
+
"CREATE TABLE vec_blob (rowid INTEGER PRIMARY KEY, embedding BLOB NOT NULL)"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
def upsert(self, conn: sqlite3.Connection, rowid: int, vec: Sequence[float]) -> None:
|
|
175
|
+
conn.execute(
|
|
176
|
+
"INSERT OR REPLACE INTO vec_blob(rowid, embedding) VALUES (?, ?)",
|
|
177
|
+
(rowid, pack_vector(vec)),
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def delete(self, conn: sqlite3.Connection, rowid: int) -> None:
|
|
181
|
+
conn.execute("DELETE FROM vec_blob WHERE rowid = ?", (rowid,))
|
|
182
|
+
|
|
183
|
+
def delete_all(self, conn: sqlite3.Connection) -> None:
|
|
184
|
+
conn.execute("DELETE FROM vec_blob")
|
|
185
|
+
|
|
186
|
+
def search(self, conn, query, k):
|
|
187
|
+
scored = [
|
|
188
|
+
(int(rowid), cosine(query, unpack_vector(blob)))
|
|
189
|
+
for rowid, blob in conn.execute("SELECT rowid, embedding FROM vec_blob")
|
|
190
|
+
]
|
|
191
|
+
scored.sort(key=lambda t: t[1], reverse=True)
|
|
192
|
+
return scored[:k]
|
|
193
|
+
|
|
194
|
+
def get_vectors(self, conn, rowids):
|
|
195
|
+
if not rowids:
|
|
196
|
+
return {}
|
|
197
|
+
qmarks = ",".join("?" * len(rowids))
|
|
198
|
+
out: dict[int, list[float]] = {}
|
|
199
|
+
for rowid, blob in conn.execute(
|
|
200
|
+
f"SELECT rowid, embedding FROM vec_blob WHERE rowid IN ({qmarks})",
|
|
201
|
+
tuple(int(r) for r in rowids),
|
|
202
|
+
):
|
|
203
|
+
out[int(rowid)] = unpack_vector(blob)
|
|
204
|
+
return out
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def get_backend(prefer: str = "auto") -> VectorBackend:
|
|
208
|
+
"""Adapter selection. ``auto`` uses sqlite-vec if loadable, else brute force.
|
|
209
|
+
|
|
210
|
+
``prefer`` may also be ``"sqlite-vec"`` (raises if unavailable) or
|
|
211
|
+
``"brute-force"`` (forces the fallback — used by tests and SQLCipher mode).
|
|
212
|
+
"""
|
|
213
|
+
if prefer == "brute-force":
|
|
214
|
+
return BruteForceBackend()
|
|
215
|
+
if prefer == "sqlite-vec":
|
|
216
|
+
return SqliteVecBackend()
|
|
217
|
+
# auto — probe a REAL extension load (not just the import) so a packaged
|
|
218
|
+
# build that ships the wrapper but omits the native vec0 lib degrades to
|
|
219
|
+
# brute-force instead of crashing at setup() (S10 finding).
|
|
220
|
+
if SqliteVecBackend.available() and SqliteVecBackend.loadable():
|
|
221
|
+
try:
|
|
222
|
+
return SqliteVecBackend()
|
|
223
|
+
except Exception:
|
|
224
|
+
pass
|
|
225
|
+
return BruteForceBackend()
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: brainiac-cli
|
|
3
|
+
Version: 0.16.0
|
|
4
|
+
Summary: Brainiac — local any-LLM second-brain core engine + brain CLI (Markdown truth, derived SQLite index).
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: onnxruntime>=1.17
|
|
10
|
+
Requires-Dist: tokenizers>=0.15
|
|
11
|
+
Requires-Dist: numpy<3,>=1.24
|
|
12
|
+
Requires-Dist: sqlite-vec>=0.1.6
|
|
13
|
+
Requires-Dist: huggingface-hub>=0.20
|
|
14
|
+
Requires-Dist: cryptography>=41
|
|
15
|
+
Requires-Dist: PyYAML>=6
|
|
16
|
+
Requires-Dist: regex>=2023.0.0
|
|
17
|
+
Requires-Dist: keyring>=24; sys_platform == "win32"
|
|
18
|
+
Requires-Dist: pypdf>=4.0
|
|
19
|
+
Requires-Dist: python-docx>=1.1
|
|
20
|
+
Requires-Dist: python-pptx>=0.6.23
|
|
21
|
+
Requires-Dist: openpyxl>=3.1
|
|
22
|
+
Requires-Dist: Pillow>=10
|
|
23
|
+
Provides-Extra: vec
|
|
24
|
+
Requires-Dist: sqlite-vec>=0.1.6; extra == "vec"
|
|
25
|
+
Provides-Extra: audit
|
|
26
|
+
Requires-Dist: cryptography>=41; extra == "audit"
|
|
27
|
+
Provides-Extra: embed
|
|
28
|
+
Requires-Dist: fastembed>=0.3; extra == "embed"
|
|
29
|
+
Provides-Extra: corporate
|
|
30
|
+
Requires-Dist: onnxruntime>=1.17; extra == "corporate"
|
|
31
|
+
Requires-Dist: tokenizers>=0.15; extra == "corporate"
|
|
32
|
+
Requires-Dist: numpy<3,>=1.24; extra == "corporate"
|
|
33
|
+
Requires-Dist: sqlite-vec>=0.1.6; extra == "corporate"
|
|
34
|
+
Requires-Dist: huggingface-hub>=0.20; extra == "corporate"
|
|
35
|
+
Requires-Dist: cryptography>=41; extra == "corporate"
|
|
36
|
+
Requires-Dist: PyYAML>=6; extra == "corporate"
|
|
37
|
+
Provides-Extra: yaml
|
|
38
|
+
Requires-Dist: PyYAML>=6; extra == "yaml"
|
|
39
|
+
Provides-Extra: ingest
|
|
40
|
+
Requires-Dist: pypdf>=4.0; extra == "ingest"
|
|
41
|
+
Requires-Dist: python-docx>=1.1; extra == "ingest"
|
|
42
|
+
Requires-Dist: python-pptx>=0.6.23; extra == "ingest"
|
|
43
|
+
Requires-Dist: openpyxl>=3.1; extra == "ingest"
|
|
44
|
+
Requires-Dist: Pillow>=10; extra == "ingest"
|
|
45
|
+
Provides-Extra: dev
|
|
46
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
47
|
+
Requires-Dist: build>=1; extra == "dev"
|
|
48
|
+
Provides-Extra: eval
|
|
49
|
+
Requires-Dist: ranx>=0.3.20; extra == "eval"
|
|
50
|
+
Requires-Dist: numpy>=1.24; extra == "eval"
|
|
51
|
+
Provides-Extra: quant-tools
|
|
52
|
+
Requires-Dist: onnx>=1.14; extra == "quant-tools"
|
|
53
|
+
Provides-Extra: mcp
|
|
54
|
+
Requires-Dist: mcp>=1.0; extra == "mcp"
|
|
55
|
+
Provides-Extra: index
|
|
56
|
+
Requires-Dist: regex>=2023.0.0; extra == "index"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
# Brainiac
|
|
60
|
+
|
|
61
|
+
A local, any-LLM **second brain**: your notes stay plain Markdown + YAML on
|
|
62
|
+
your own disk, and the `brain` CLI gives any LLM harness (Claude Code, Codex,
|
|
63
|
+
Gemini CLI, Claude Desktop / Cowork, ...) fast, sourced search over them — no
|
|
64
|
+
vendor lock-in, no cloud index, no plugin ecosystem to keep alive.
|
|
65
|
+
|
|
66
|
+
## Why
|
|
67
|
+
|
|
68
|
+
Retrieval-augmented note-taking usually means picking a proprietary app and
|
|
69
|
+
trusting its plugin/embedding pipeline forever. Brainiac inverts that: the
|
|
70
|
+
substrate is just files (`vault/brain/`, `vault/raw/`), the search index is a
|
|
71
|
+
disposable cache you can rebuild any time, and every read goes through a
|
|
72
|
+
deny-by-default classification filter (the **egress gate** — see
|
|
73
|
+
`docs/glossary.md`) before it reaches a model — so you control what an LLM is
|
|
74
|
+
allowed to see, note by note. See `AGENTS.md` for the full conventions and
|
|
75
|
+
security model.
|
|
76
|
+
|
|
77
|
+
## Installing Brainiac for the first time
|
|
78
|
+
|
|
79
|
+
**Installing? → [`docs/install/README.md`](docs/install/README.md) (pick your
|
|
80
|
+
platform: Claude Code, Cowork, Codex, or Gemini CLI).**
|
|
81
|
+
|
|
82
|
+
The single most common path (Claude Code, on your own machine):
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
claude> /plugin marketplace add Autopsias/brainiac
|
|
86
|
+
claude> /plugin install brainiac-manager@brainiac
|
|
87
|
+
claude> /brainiac-install <path-to-your-vault>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Or the one-command way** (PyPI-first, no clone needed):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
curl -fsSL https://raw.githubusercontent.com/Autopsias/brainiac/main/install.sh -o /tmp/brainiac-install.sh
|
|
94
|
+
bash /tmp/brainiac-install.sh
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`install.sh` tries, in order, `uv tool install`, `pipx install`, then
|
|
98
|
+
`pip install --user` — first success wins, and it tells you which one it
|
|
99
|
+
used. Every channel installs `brainiac-cli[mcp]` so `brain-mcp` (the
|
|
100
|
+
optional Claude Desktop bridge) works out of the box. Plain `pip install
|
|
101
|
+
brainiac-cli[mcp]` works too, without the channel-fallback convenience.
|
|
102
|
+
|
|
103
|
+
**Windows (PowerShell)?** Same install, no bash/WSL required:
|
|
104
|
+
|
|
105
|
+
```powershell
|
|
106
|
+
irm https://raw.githubusercontent.com/Autopsias/brainiac/main/install.ps1 -OutFile install.ps1
|
|
107
|
+
.\install.ps1
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Contributing to Brainiac, or no PyPI/network access?** Clone and pass
|
|
111
|
+
`--dev` / `-Dev` — an editable install from the checkout, the pre-PyPI
|
|
112
|
+
behavior:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
git clone https://github.com/Autopsias/brainiac.git && cd brainiac
|
|
116
|
+
./install.sh --dev # macOS/Linux
|
|
117
|
+
# or: .\install.ps1 -Dev # Windows
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The `--dev` path also builds a **lexical-only** index for the checkout's
|
|
121
|
+
bundled sample vault (`BRAIN_EMBEDDER=hash` — no model download, no network
|
|
122
|
+
needed) — try `brain search "arctic-embed vs e5" --json` against it right
|
|
123
|
+
away. The default PyPI-first path has no local sample vault to index — run
|
|
124
|
+
this against your own vault instead (see `docs/install/README.md`):
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
BRAIN_VAULT=<workspace>/vault brain init --full --apply # scaffolds + seeds 3 sample notes AND indexes them
|
|
128
|
+
BRAIN_VAULT=<workspace>/vault brain search "welcome" --json # first search works right away
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Either way, semantic search downloads its embedding model (a few hundred MB)
|
|
132
|
+
lazily on first real use, or run `brain warmup` up front.
|
|
133
|
+
|
|
134
|
+
Then ask your first question:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
brain search "welcome" --json # fresh vault (matches the seeded sample notes)
|
|
138
|
+
brain search "arctic-embed vs e5" --json # --dev checkout's own bundled vault
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Every search hit carries the note's file path and its classification tier,
|
|
142
|
+
and an `egress` block reports how many notes were withheld by the
|
|
143
|
+
classification filter.
|
|
144
|
+
|
|
145
|
+
Two things worth knowing about where files live:
|
|
146
|
+
|
|
147
|
+
- **Your notes** live in the vault (`vault/` by default — plain Markdown, the
|
|
148
|
+
single source of truth).
|
|
149
|
+
- **The search index** lives in your per-user app-data folder
|
|
150
|
+
(`~/Library/Application Support/profile-a-brain` on macOS,
|
|
151
|
+
`%LOCALAPPDATA%\profile-a-brain` on Windows, `~/.local/share/...` on
|
|
152
|
+
Linux). It is a derived cache — deleting it loses nothing; `brain rebuild`
|
|
153
|
+
recreates it from the vault.
|
|
154
|
+
|
|
155
|
+
Per-client walkthroughs (Claude Code vs Codex vs Cowork):
|
|
156
|
+
`docs/install/README.md`. Run `brain --help` any time — the CLI is self-describing and is the one
|
|
157
|
+
source of truth for what's shipped.
|
|
158
|
+
|
|
159
|
+
## Updating an existing install
|
|
160
|
+
|
|
161
|
+
Already installed? Don't re-run the first-time setup — update in place.
|
|
162
|
+
|
|
163
|
+
**Check where you stand (read-only).** In your terminal:
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
brain doctor
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
prints one health + version table across every surface — engine venv, CLI
|
|
170
|
+
plugins, staged Cowork workspaces, marketplace cache, and the Desktop/Cowork
|
|
171
|
+
store — each ✅/⚠️ with the exact command to fix anything stale. It changes
|
|
172
|
+
nothing and exits non-zero when a required surface is behind. (Available from
|
|
173
|
+
v0.10.0 onward.)
|
|
174
|
+
|
|
175
|
+
**Bring everything current.** In Claude Code on the host:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
/brainiac-update
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
now **runs** the update instead of printing a checklist: marketplace refresh →
|
|
182
|
+
downgrade-safe CLI-plugin reinstall → engine venv reinstall → every registered
|
|
183
|
+
Cowork workspace re-staged → a final `brain doctor` verify — then a before→after
|
|
184
|
+
version table and one pass/fail. It handles the reconciliation downgrade
|
|
185
|
+
(installed newer than the marketplace) automatically and never touches your
|
|
186
|
+
notes, audit chain, or runtime state. Prefer the terminal? `brain update` is the
|
|
187
|
+
same flow — add `--dry-run` to preview every decision without mutating anything.
|
|
188
|
+
Full detail: **`docs/install/README.md`** (§ Updating).
|
|
189
|
+
|
|
190
|
+
**Installed under the old names?** Marketplace `profile-a-marketplace` and
|
|
191
|
+
plugins `profile-a-kernel`/`profile-a-extras` were renamed to `brainiac` /
|
|
192
|
+
`brainiac-kernel`/`brainiac-extras` (2026-07-11). `brain doctor` flags a
|
|
193
|
+
stale-name registration under either old name. Recovery (add-new-before-
|
|
194
|
+
remove-old — never the reverse):
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
claude plugin marketplace add Autopsias/brainiac
|
|
198
|
+
claude plugin install brainiac-manager@brainiac
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
then run `/brainiac-update` — it detects the old-name registrations and
|
|
202
|
+
finishes the migration automatically (installs the new-name plugins,
|
|
203
|
+
verifies the lifecycle skills resolve, then removes the old marketplace and
|
|
204
|
+
plugins). See `docs/adr/0006-distribution-naming.md`.
|
|
205
|
+
|
|
206
|
+
## Using it with a new project (second vault, third, ...)
|
|
207
|
+
|
|
208
|
+
The install is **per machine**; vaults are **per project**. You never
|
|
209
|
+
reinstall — you point the same `brain` at a different vault folder, and each
|
|
210
|
+
vault automatically gets its own index and audit chain (no configuration):
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
export BRAIN_VAULT=~/vaults/my-new-project # which vault to use
|
|
214
|
+
brain init --full --apply # once per vault: scaffold + seed + index
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Full detail (per-vault overlay, the scheduled-task gotcha):
|
|
218
|
+
**`docs/install/second-vault.md`**.
|
|
219
|
+
|
|
220
|
+
## For technical & security teams
|
|
221
|
+
|
|
222
|
+
A plain summary of what this repo does and doesn't do, for a corporate
|
|
223
|
+
review:
|
|
224
|
+
|
|
225
|
+
- **All data stays on the local disk.** Notes are plain Markdown; the index
|
|
226
|
+
is a local SQLite file. There is no server, no telemetry, no cloud sync,
|
|
227
|
+
and the project holds **no model API keys** — the only egress is whatever
|
|
228
|
+
LLM client the owner already runs.
|
|
229
|
+
- **Deny-by-default egress gate.** Every read command filters notes by their
|
|
230
|
+
`classification` tier before printing; a note with a missing or unknown
|
|
231
|
+
label is treated as most-restrictive and withheld. Scheme:
|
|
232
|
+
`docs/classification-scheme.md`.
|
|
233
|
+
- **Signed audit chain.** Every committed write is Ed25519-signed and
|
|
234
|
+
hash-chained; the key lives in the OS secret store, fail-closed (no file
|
|
235
|
+
fallback). Rotation runbook and stated limitations: `SECURITY.md`.
|
|
236
|
+
- **Trust split.** Untrusted/sandboxed legs (the Cowork Linux VM) get a
|
|
237
|
+
read-only snapshot and a draft inbox — they can never sign, index, or
|
|
238
|
+
mutate the canonical store. `AGENTS.md` §6.
|
|
239
|
+
- **Dependencies.** The default install pulls a small, auditable set
|
|
240
|
+
(onnxruntime, tokenizers, numpy, sqlite-vec, huggingface-hub,
|
|
241
|
+
cryptography, PyYAML, regex — see `pyproject.toml`, which documents why
|
|
242
|
+
each exists). The code degrades gracefully without any of them, so a
|
|
243
|
+
constrained deployment (Intune, air-gapped) can install with
|
|
244
|
+
`pip install --no-deps .` and re-add only what policy allows; an SBOM
|
|
245
|
+
generator ships at `tools/generate_sbom.py`. Offline model provisioning:
|
|
246
|
+
set `$BRAIN_MODEL_CACHE` to a pre-fetched model dir and no download is
|
|
247
|
+
attempted.
|
|
248
|
+
- **License & provenance.** Apache-2.0. Built clean-room; the AGPL project
|
|
249
|
+
consulted as a design reference was never forked or vendored — log and
|
|
250
|
+
audit gate: `docs/clean-room-log.md`, `tools/code_origin_audit.py`.
|
|
251
|
+
- **Vulnerability reporting:** `SECURITY.md`. Deeper notes:
|
|
252
|
+
`docs/SECURITY_NOTES.md`, `docs/operations/`.
|
|
253
|
+
|
|
254
|
+
## How the AI assistants are wired
|
|
255
|
+
|
|
256
|
+
`AGENTS.md` is the canonical instruction file. `CLAUDE.md` imports it
|
|
257
|
+
verbatim (`@AGENTS.md`) so Claude Code reads the same contract; Codex reads
|
|
258
|
+
`AGENTS.md` natively; Gemini CLI is pointed at it via `.gemini/`. All of them
|
|
259
|
+
call the `brain` CLI through their normal shell — **no MCP required**. The
|
|
260
|
+
one exception is the Claude Desktop **Chat tab** (the only surface that
|
|
261
|
+
can't run a command): for that, `pip install -e ".[mcp]"` adds the optional,
|
|
262
|
+
deletable `brain-mcp` bridge. Full matrix: `docs/harness-wiring.md`.
|
|
263
|
+
|
|
264
|
+
## More
|
|
265
|
+
|
|
266
|
+
- **`AGENTS.md`** — the conventions/schema every harness reads at startup:
|
|
267
|
+
note shape, link style, capture rules, the four agent-facing verbs
|
|
268
|
+
(search/get/recent/draft-capture), and the security posture.
|
|
269
|
+
- **`docs/install/`** — installation, starting at the
|
|
270
|
+
[platform picker](docs/install/README.md) (Claude Code, Cowork — the Claude
|
|
271
|
+
Desktop Linux VM sandbox client — Codex, Gemini CLI) and
|
|
272
|
+
`docs/install/new-owner.md` for the five-minute "what runs where" mental model.
|
|
273
|
+
- **`docs/glossary.md`** — one-line definitions for the jargon used across
|
|
274
|
+
these docs (PARA, MNPI, egress gate, Cowork, host-broker, overlay, ...).
|
|
275
|
+
- **`SECURITY.md`** — vulnerability reporting, supported versions, audit-key
|
|
276
|
+
rotation.
|
|
277
|
+
- **`LICENSE`** — Apache-2.0.
|
|
278
|
+
|
|
279
|
+
## Layout
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
AGENTS.md conventions + frontmatter schema
|
|
283
|
+
src/brain/ the brain CLI + engine (index, search, audit, ...)
|
|
284
|
+
docs/ specs (substrate, classification, install, security notes)
|
|
285
|
+
tools/validate.py conventions validator (stdlib-only; PyYAML optional)
|
|
286
|
+
vault/ the tiny sample vault used in the quickstart above
|
|
287
|
+
raw/ immutable captured sources
|
|
288
|
+
brain/ agent-owned atomic notes + index.md + generated backlinks.md
|
|
289
|
+
.brain/ per-vault runtime (published snapshot, capture inbox) — gitignored
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Validate
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
python3 tools/validate.py vault # exit 0 = conventions clean
|
|
296
|
+
python3 tools/validate.py vault --backlinks # regenerate brain/backlinks.md
|
|
297
|
+
python3 tools/validate.py vault --okf # + optional OKF lint
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Scope note
|
|
301
|
+
|
|
302
|
+
Substrate readiness is not the same as operational cutover. This repo makes
|
|
303
|
+
the substrate *ready* to replace an existing tool (e.g. Obsidian + Smart
|
|
304
|
+
Connections) and emits the cutover hooks (`docs/corpus-migration.md`,
|
|
305
|
+
`docs/dependency-inventory.md`); actually retiring your old setup is a
|
|
306
|
+
separate, owner-specific step. See `AGENTS.md` §7.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
brain/__init__.py,sha256=X1-_-A7-DOJrM53MjcgFvkV6gyTmMcKxq0adY_Ve-pk,1870
|
|
2
|
+
brain/__main__.py,sha256=RnmXo52qFPkq9WQH2i-PTZZdpKYdfkmo9PaQ2Ncvdx4,431
|
|
3
|
+
brain/_version.py,sha256=IVFuOcK8mkureEFjMM6_nu3-Yad3LY6tBzCF3H1u5TQ,621
|
|
4
|
+
brain/anchor.py,sha256=0ThDeoXmI3CDc2oF4qMzPeZh34b5hE0VU6TUOtMIuNI,5148
|
|
5
|
+
brain/audit.py,sha256=HkA2Z2Gw9X4vfV-t-Y7EDsP2-EC6N_yApsbckN5DvKc,16681
|
|
6
|
+
brain/backup.py,sha256=_oWERCSKaSHp-ku0oY1118peXhGs7tzRnQfNiR7nEpQ,8868
|
|
7
|
+
brain/brief.py,sha256=SRkFuw9Ic3sVoqRGsOQM3JZLPlCDeDUJWFvGdCGKbe8,16802
|
|
8
|
+
brain/capture.py,sha256=UWZPSho_4IxxHic9inS5BAY9k2jl5zZGhnNh9P5h5RQ,3997
|
|
9
|
+
brain/chunk.py,sha256=r6iTnx2sF86wyN8i4jx7EYfy-R08Cf2hwbd4Ly0y9jI,10089
|
|
10
|
+
brain/classification.py,sha256=ihR5fwUR76Pud18dYoCqP0X_6YY20q60f7tBvztvfJs,5659
|
|
11
|
+
brain/cli.py,sha256=4EaWYpswVCWKXVpp6CD5_Q5EoE-IqTqp2ChN9S64ISQ,98442
|
|
12
|
+
brain/config.py,sha256=Zk2EmS0aoth8fl1r63iGBSi420qXjYYFpwsad3-91KQ,17646
|
|
13
|
+
brain/connect.py,sha256=WGXEkthfT-G-2IMAwSHVI7_PaYyITeLz_Z18UE8Bf6Q,15471
|
|
14
|
+
brain/context.py,sha256=e25fvfyFzi5JqdIzFMrJwGqVFjygp6M8yRixQVZuvuU,4707
|
|
15
|
+
brain/core.py,sha256=KKf-AKcUBCkIAzQzI6O7V1lvwfSI7O9fptenxpJMo04,159636
|
|
16
|
+
brain/doctor.py,sha256=u94HD2LDDNV2tKWK1y0HZecLU-JRlSiEaGoxKAxA9NA,57560
|
|
17
|
+
brain/egress.py,sha256=EGcxDkdE1OeDxR8bI0G9Tg6mqJPe6CQrOBXOU-NsjO8,7476
|
|
18
|
+
brain/embed.py,sha256=zfQmiAxoCJaF3WYCu5A1PFk2GywdkP09pd24oNkg0zo,38550
|
|
19
|
+
brain/encryption.py,sha256=zRZ9mg4E_kBD_0Y3HDF-4D3sngy2wPaLV9zn3m6PeM4,8968
|
|
20
|
+
brain/frontmatter.py,sha256=3s39Y9hEBTebTZ1fCGVbm9D7KDUtGJsvlhtIQYwEAGY,3624
|
|
21
|
+
brain/golden_probe.py,sha256=M-paNnwMS7nt88IZHKJ6RMfVIrq71EH2iy3MEuKMX5U,32963
|
|
22
|
+
brain/graph.py,sha256=VKNGg3yHV-wg7VSudKlc4dQlfBv6DkGKqzkNhVmO1V4,14807
|
|
23
|
+
brain/graphify.py,sha256=yjxN7w5d6aZlu1Tj93BHMR7KumIPShgtVDEIW4iwiWM,16040
|
|
24
|
+
brain/index.py,sha256=7VnYmgwqxbfoXRRAXl1vnLSPn9yOICfFAwVUqD7NGzk,77479
|
|
25
|
+
brain/init.py,sha256=_8bX4o_QH0jzYJaYdZ2KvzTXapmCvM1l1n6PpCEs4Lw,36393
|
|
26
|
+
brain/maintenance.py,sha256=uR3MCFjE16pOmbl5SaOs_tPrNg4BMASo_2-8Pe0STqk,107955
|
|
27
|
+
brain/mcp_adapter.py,sha256=yDUPVsWm7CroJTH1U_AAzExRavX3dBfxJRmtwYpxfs0,11400
|
|
28
|
+
brain/multihop.py,sha256=SEOYB1fNY3YPyPd9LhOFRva4sV-Ifl16NQn1i9IrEGE,9683
|
|
29
|
+
brain/notes.py,sha256=7otaNlAfamsfkBdfVDMptFHX_E_jd6koIZMNHoT7Y8c,7632
|
|
30
|
+
brain/overlay.py,sha256=9rsuS3STthgshYkcNUPL5bI7w3xJlok_l0LuED279Hk,6966
|
|
31
|
+
brain/projection.py,sha256=XyAZPBAoZ5MQLgCd2jBgNgyTMGjV3HcWGPIoEHLRlfk,2885
|
|
32
|
+
brain/rerank.py,sha256=yyMp80zsguvYM_hztHhEmpy4Tvg4BMVImvVTSZ73PGw,18399
|
|
33
|
+
brain/snapshot.py,sha256=g7BCq2ofzDZYvoiiGx-1gEWS1YbV5YhXFgOu9do3Pi8,8199
|
|
34
|
+
brain/update.py,sha256=FyBfTNZ8-y5f9VrwfnJElN4SCzY0RmNsS4hO0xS5qu4,37039
|
|
35
|
+
brain/vectors.py,sha256=EdBRBI6_rAcbelGU1QOpZEld01wgJGyOlkoeY7lIQ0s,8813
|
|
36
|
+
brain/_assets/AGENTS.md,sha256=MsbBXm_Vdmp-1lr41Tmgvdvgoi0zu60-QVO043DOr4E,33235
|
|
37
|
+
brain/_assets/overlay/template/brand/brand-guide.md,sha256=osiarUtl0BDdy-FkdIKrO4TxYWwyXLopqpjaf-BzW3U,735
|
|
38
|
+
brain/_assets/overlay/template/keywords/glossary.md,sha256=L5pHOlGNDFeUJKy2Gkpr9Pm9yRWPULdGOgZRC8S-vJI,387
|
|
39
|
+
brain/_assets/overlay/template/people/roster.md,sha256=ZO8NOvkqY3vqU9y-KjSQAYw8jICwlgNxMk_6CZLxUUk,377
|
|
40
|
+
brain/_assets/overlay/template/voice/voice-profile.md,sha256=srRWsWz11TEmB4N0qH4upfetlY8HPdGtFwwyOeRzHBI,932
|
|
41
|
+
brain/_assets/routines/manifest.json,sha256=ZfNIFDsokQyUqkcTuajjjN4bg-fUIT9Ied_3eeuwnOk,23599
|
|
42
|
+
brain/_assets/scripts/brain-brief-mac.plist,sha256=yUCCyTbG2ssocvC4NUXNHB_NWjzEbg3Le_mW5VqtNKg,2665
|
|
43
|
+
brain/_assets/scripts/brain-brief.sh,sha256=1fh4o9s9nDqQ9Pu9Xps-pAFfXtKp7OEaS77f51HdBzs,3896
|
|
44
|
+
brain/_assets/scripts/brain-synthesis-mac.plist,sha256=kLA__aADJi6C2YtkUWPJRiL-9r3DyGCPu88w1yp-11I,1715
|
|
45
|
+
brain/_assets/scripts/brain-synthesis.sh,sha256=gpSUJUfCfRiIgRwFGi08pR1THhHp2RVCNwMB9JR4uYs,9886
|
|
46
|
+
brain/_assets/scripts/install-brief-mac.sh,sha256=zw2T_I28nXAknNyX1ep3K3iozN9Fc_DhioWvOT6QDzQ,7048
|
|
47
|
+
brain/_assets/scripts/install-brief-windows.ps1,sha256=VE6SJg64hON8O6K1_7AWey0qa6KDILa9zyj9mZsNQs0,4665
|
|
48
|
+
brain/_assets/scripts/register_tasks.py,sha256=XDWtn6WpBZ7d9RRqpcI-zYxe6c3bb6zc0Qtyb3WSnD8,17838
|
|
49
|
+
brain/_assets/templates/company.md,sha256=ZFjeepGAoFdZlvtmPg19__5C-_pe9HH7oiRnl64yE-k,231
|
|
50
|
+
brain/_assets/templates/concept.md,sha256=852qP9pqhwtOLblwYlkLnhFr9GgpNvaqR7eqptabA0g,438
|
|
51
|
+
brain/_assets/templates/daily.md,sha256=G0t_oUTlPBYS8nQK7_gt1Rb2FaZZPtRIX4fHerBoHrc,217
|
|
52
|
+
brain/_assets/templates/decision.md,sha256=Bkb-dHXTjZ6x_ENVqxdwRIJ8v126SRJ8mCZBNWlQXIw,914
|
|
53
|
+
brain/_assets/templates/meeting.md,sha256=tzLwoihXdUXv3aXoJyNKPifOPT2xXWK5UR-CGCzbh8c,531
|
|
54
|
+
brain/_assets/templates/person.md,sha256=ENbuUsR79EdVebLhyEu4REgCFg1MlmoUqnFR2tHj9bI,228
|
|
55
|
+
brain/_assets/templates/project.md,sha256=gZYTGUqJz_woVZqTWju-E3hkDlv7-2b4aU-SgEEGsr4,241
|
|
56
|
+
brain/_assets/templates/state-moc.md,sha256=ZSusJ73sUpMF6uCYFdUeWw-XvivYiOruAwKRpXpd0J4,1009
|
|
57
|
+
brain/ingest/__init__.py,sha256=YWIwBJXGDwj59BKrJPd-QZvXBYRC6kI0omDC2QT2sCI,918
|
|
58
|
+
brain/ingest/pipeline.py,sha256=tlikO2z4hppJaNGLqRP75b-j-EKcyBkBEOIrvH5H7V8,38009
|
|
59
|
+
brain/ingest/transcript.py,sha256=dtT3rAj0Wm147XGhw5sui5fIFdrtx7aIc13QhnxJKjY,6430
|
|
60
|
+
brain/ingest/handlers/__init__.py,sha256=0iU29LmHTi-glc5tmyunXAHoqVtol1wTC7hxaGhevIw,1321
|
|
61
|
+
brain/ingest/handlers/base.py,sha256=2gFybMPzzx7ixiNh9BsD--4IUQ-GPWi4OtNsFOnaO2c,3619
|
|
62
|
+
brain/ingest/handlers/docx.py,sha256=KiQl-6khxEZsHHNzml2xoqo58owKXGYBqQ534zzR7UU,2983
|
|
63
|
+
brain/ingest/handlers/email.py,sha256=ky3q68Ya5VuaBjvN1QJtzBDqAP-61GRdsw8QZvj5iW0,8291
|
|
64
|
+
brain/ingest/handlers/html.py,sha256=KKwaF_RrgmA9dextJVYqSrpBeRUgLg52XUst_lS5XVM,5022
|
|
65
|
+
brain/ingest/handlers/image.py,sha256=UC7CbyMYpMhoR6b-RLkbrt9Xebr5NlNINi3pbPQHuGI,3373
|
|
66
|
+
brain/ingest/handlers/pdf.py,sha256=b3EJw8XTHatfgZSiUYH9MlhdJ_m5u96lomNy12F0EXY,3655
|
|
67
|
+
brain/ingest/handlers/pptx.py,sha256=eqkI6Gm11hvBqAzOS7OJ_48ioNhjSFFCwgJQFVQHHlc,2328
|
|
68
|
+
brain/ingest/handlers/tables.py,sha256=wKYnBwNkPBLRuABJKzGSEbkEs8MDVl4phUKXg0N7GE4,1563
|
|
69
|
+
brain/ingest/handlers/text.py,sha256=2NUxvphrnIow8X3U1ChFS7IMYbuIKbSS5w_qIceIMX8,1478
|
|
70
|
+
brain/ingest/handlers/xlsx.py,sha256=EoLqKN-DTGmxbYF5F-xX3KvoLkUKNEPYxChJLzWiGoA,4102
|
|
71
|
+
brain/ingest/handlers/zip.py,sha256=aTOO6DR418IGwYonWLdscpEjzB1Ngg63bQy7Admv6Fk,7450
|
|
72
|
+
brainiac_cli-0.16.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
73
|
+
brainiac_cli-0.16.0.dist-info/METADATA,sha256=x4isWPqPZJHa693yZqPWW3Lhd9Vnn-AfWjeFbBFpGR8,13144
|
|
74
|
+
brainiac_cli-0.16.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
75
|
+
brainiac_cli-0.16.0.dist-info/entry_points.txt,sha256=gaRS9IrVXze1IdVJm_BcN7kAXzst2FDou63OEwpsQNU,122
|
|
76
|
+
brainiac_cli-0.16.0.dist-info/top_level.txt,sha256=0pJ5ecu89EDo7ZExlRWAh7IWxf55ZhTYilz2jLXwRSg,6
|
|
77
|
+
brainiac_cli-0.16.0.dist-info/RECORD,,
|