-
released this
2026-06-09 21:54:06 +02:00 | 301 commits to main since this releaseFix
Documentation-only fix. Two type-definition comments incorrectly stated SQ4 vector quantization required a paid native provider. Brainy ships a pure-JS SQ4 implementation (`distanceSQ4Js` in `src/utils/vectorQuantization.ts`); the native SIMD acceleration is a drop-in via `setSQ4DistanceImplementation`, not a hard requirement.
Corrected in `src/coreTypes.ts:472` and `src/types/brainy.types.ts:1123`.
No behaviour change. Caught during an upstream open-core-boundary audit.
Tests
1468 / 1468 unit suite passing. No code paths changed.
See RELEASES.md for the full entry.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
released this
2026-06-09 19:36:29 +02:00 | 303 commits to main since this releaseFix
A same-key rename race in
FileSystemStorage.saveBinaryBlobcausedbrain.flush()to throwENOENTand broke downstream jobs (GCS backups, snapshot exports) for any consumer that triggers concurrent flush + compaction.[job-queue] gcs-backup: failed — ENOENT: no such file or directory, rename '/data/brainy-data/.../_column_index/owner/DELETED.bin.tmp' -> '/data/brainy-data/.../_column_index/owner/DELETED.bin'Root cause:
saveBinaryBlobused a bare${filePath}.tmpsuffix. Two concurrent same-key calls computed the same temp path; bothwriteFiled, the firstrenamesucceeded, the secondrenamefired against a missing temp and threw.Fix: unique per-writer temp suffix (matches the pattern at every other atomic-write site in the same file) + defensive ENOENT swallow on rename + temp cleanup on any other failure.
Audit
One bug site, scoped audit confirms no other similar patterns:
FileSystemStorage— six sibling atomic-write sites already used unique suffixes. OnlysaveBinaryBlobwas the outlier. All clean now.OPFSStorage— WritableStream (no tmp+rename).- Object-store adapters (GCS / R2 / Azure / S3) —
PUTis atomic. MemoryStorage/HistoricalStorageAdapter— not affected.- COW / versioning / HNSW / aggregation / snapshot — all delegate to storage adapters; they get the fix automatically.
Beneficiaries beyond the reported bug
HNSW connection persistence (
hnswIndex.ts:252) also writes viasaveBinaryBloband was structurally susceptible to the same race. No production reports of HNSW failures (probably because the HNSW write path is more naturally serialized by the index lock), but the fix removes the latent issue.Tests
- New
tests/integration/savebinaryblob-concurrent-rename.test.ts(4 tests) - 1468 / 1468 unit suite passing
See RELEASES.md for the full entry.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
released this
2026-06-09 19:04:45 +02:00 | 305 commits to main since this releaseHighlights
Per-entity optimistic concurrency, the read-then-CAS lock pattern, and idempotent-bootstrap singleton inserts.
entity._rev: number— monotonic per-entity counter, auto-bumped on everyupdate(). Surfaced onget()/find()/search(). Pre-7.31.0 entities read as_rev: 1.update({ ifRev: N })— CAS check. ThrowsRevisionConflictErrorcarrying{ id, expected, actual }if the persisted_revno longer matches.add({ ifAbsent: true })+addMany({ items, ifAbsent: true })— by-ID idempotent insert. Returns the existingidif present, no throw, no overwrite.RevisionConflictErrorexported from the public API.
The full optimistic-concurrency guide walks through the lock pattern, read-modify-write retry, idempotent bootstrap, and how
_revinteracts with branches, snapshots, and VFS file versioning.Why this scope (and why no
brain.transaction())A public transaction wrapper was on the table but was cut. The internal
TransactionManagerexposes rawOperationclasses that take aStorageAdapterconstructor arg; a clean high-level facade in 7.31.0 was either (a) "delegate tobrain.add()/update()/relate()" which each commit their own internal transaction before the closure returns (looks atomic, isn't), or (b) threadtx?through every internal write site (~2 days + regression surface). The SDK-scheduler use case driving this is the read-then-CAS lock pattern, fully solved by_rev+ifRev. Multi-write atomicity lands in 8.0's Datomic-stylebrain.transact()where it's atomic by construction.Cortex compatibility
Zero changes required.
_revis a single integer field updated alongside every other metadata field; Cortex never sees the per-entity counter.Tests
- New
tests/integration/rev-and-ifabsent.test.ts(18 tests) - 1468 / 1468 unit suite passing
See RELEASES.md for the full entry.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
released this
2026-06-08 21:54:32 +02:00 | 307 commits to main since this releaseHighlights
- Recalibrate
find({ limit })cap formula from 100 KB/result to 25 KB/result (matches observed entity footprint). Typical caps ~4× more generous;maxQueryLimit/reservedQueryMemoryoverrides unchanged. - Two-tier enforcement: silent pass below cap, one-time warning per call site in the soft tier (
cap < limit ≤ 2× cap), throw in the hard tier (> 2× cap). - Improved error / warning messages name the three escape valves (
maxQueryLimit,reservedQueryMemory, pagination), include caller stack frame, link to new docs. - New public guide:
docs/guides/find-limits.md. findCallerLocation()extracted tosrc/utils/callerLocation.tsand shared with the 7.30.1 subtype enforcement.
Cortex compatibility
Zero changes required. All work is JS-side validation that runs before any storage / Cortex call.
Tests
- New
tests/integration/find-limits.test.ts(9 tests) - Recalibrated
tests/unit/utils/memoryLimits.test.ts(4 tests) - 1468 / 1468 unit suite passing
See RELEASES.md for the full entry.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Recalibrate
-
v7.30.1 — internal subtype consistency + brain.audit() diagnostic + improved enforcement errors Stable
released this
2026-06-08 20:32:11 +02:00 | 309 commits to main since this releaseAffected products: anyone running a brain where a platform layer (SDK, framework wrapper)
has registeredbrain.requireSubtype()rules on common NounTypes, AND anyone preparing for
the upcoming Brainy 8.0 default-on strict mode. Additive; drop-in from 7.30.0. No behavior
change for consumers not using strict-mode enforcement.Why
Production incident 2026-06-08: a consumer using SDK 3.20.0 (which registers
requireSubtype()rules onNounType.{Event, Collection, Message, Contract, Media, Document})
saw their booking flow start returning 500s becausebrain.add({ type: NounType.Event, ... })
calls in their codebase lackedsubtype. An audit of Brainy's OWN source revealed 14 HIGH-risk
internal write paths that also omit subtype — VFS move/copy/symlink edges, aggregation
materializer, neural extraction, importers, integrations (Sheets/OData), MCP client, CLI.
Any consumer runningrequireSubtype()rules on those NounTypes was one step away from breaking
Brainy's own infrastructure paths, not just their own code. 7.30.1 closes both gaps before
8.0 ships and makes strict mode the default.New —
brain.audit()diagnosticFind entities and relationships missing a
subtypevalue, grouped by type. The companion to
migrateField()(and to 8.0'sfillSubtypes()): answers "what would break if I enabled
strict subtype enforcement?".const report = await brain.audit() // { // entitiesWithoutSubtype: { event: 24, document: 3 }, // relationshipsWithoutSubtype: { relatedTo: 1402 }, // total: 1429, // scanned: 8400, // recommendation: 'Found 1429 entries without subtype. Migrate via `brain.migrateField()` // (7.x) — or wait for `brain.fillSubtypes()` (8.0) which closes the same // gap with caller-supplied rules.' // }VFS infrastructure entities are excluded by default (they bypass enforcement via
metadata.isVFSEntitymarkers). Pass{ includeVFS: true }to surface them.New — Improved enforcement error messages
The error fired when subtype enforcement rejects a write now includes:
- The caller's source location — extracted from the JavaScript stack so you see your own
call site, not a Brainy internal frame. Eliminates the "grep your repo forbrain.add" step. - Specific guidance — points at the registered vocabulary when one exists; mentions
brain-wide strict mode and theexceptescape valve when not; otherwise the
brain.requireSubtype()registration recipe. - A documentation link —
https://soulcraft.com/docs/guides/subtypes-and-facets#strict-mode
for the canonical migration recipe.
Before:
add(): NounType.Event requires subtype but got undefined. Register vocabulary via brain.requireSubtype().After:
add(): NounType.event requires subtype but got undefined. at BookingDraftService.getOrCreateByToken (/app/src/booking/draft.ts:42:23) Pass one of: booking, session, milestone. Migration recipe: https://soulcraft.com/docs/guides/subtypes-and-facets#strict-modeInternal subtype labels — Brainy's own infrastructure paths
Every internal Brainy write path now sets a stable, queryable
subtype. Consumers don't need
to do anything for these — they're documented here so you can query Brainy-managed data:Code path NounType / VerbType Subtype label VFS root directory /Collection'vfs-root'VFS subdirectories Collection'vfs-directory'VFS files mime-driven (e.g. Document/Code/Image)'vfs-file'VFS symlinks File'vfs-symlink'(NEW — distinct from'vfs-file')VFS Contains edges (create + move/copy/symlink/batch) Contains'vfs-contains'Aggregation materialized output Measurement'materialized-aggregate'Import-source provenance entity Document'import-source'Importer-extracted entities extractor-driven type 'imported'Importer placeholder targets Thing'import-placeholder'Neural extraction extractor-driven type 'extracted'GoogleSheets API entity writes request-driven 'imported-from-sheets'OData API entity writes request-driven 'imported-from-odata'MCP message storage Message'mcp-message'brainy addCLI defaultuser-supplied type 'cli-add'brainy relateCLI defaultuser-supplied verb 'cli-relate'Query examples:
// Every VFS-managed file in your brain await brain.find({ subtype: 'vfs-file' }) // Document breakdown — distinguishes import-source from extracted/imported/user content brain.counts.bySubtype(NounType.Document) // → { 'import-source': 12, 'imported': 847, 'extracted': 34, 'vfs-file': 102, ... }Caller-supplied
defaultSubtypeon importers and extractionImporter + extraction paths now accept a caller-supplied
defaultSubtypeconfig so consumers
can tag a whole batch with their own provenance label instead of the Brainy default:// SmartImportOrchestrator / ImportCoordinator / NeuralImport all accept this await brain.importer.import(file, { defaultSubtype: 'customer-upload-2026q2', // your batch label // ... })Precedence: extractor-set subtype (highest) → caller's
defaultSubtype→ Brainy default
('imported'for importers,'extracted'for extractors).CLI
--subtypeflagbrainy addandbrainy relategain a--subtype <value>(-s) flag for use with
strict-mode brains:brainy add "Avery Brooks — runs the AI lab" --type person --subtype employee brainy relate alice manages bob --subtype directWhen the flag isn't supplied, the CLI uses
'cli-add'/'cli-relate'as defaults so
ad-hoc CLI usage still works against strict-mode brains.Cortex compatibility
No Cortex changes required for 7.30.1. Every change is JS-side: internal subtype labels are
arbitrary strings stored transparently by Cortex;brain.audit()runs purely on JS via existing
storage.getNouns()/getVerbs()pagination; the CLI is JS-only; error messages fire in
Brainy before any native call.For Cortex 3.0 (forward-looking, not blocking):
- Native
audit()proxy. For billion-scale brains,audit()walks every entity (O(N)).
A native implementation reading from a "null-subtype" bitmap in the column store would be
O(buckets). Listed as the 6th open question in the
Brainy 8.0 spec doc. - Strict-mode parity test. Cortex should mirror Brainy's new
tests/integration/strict-mode-self-test.test.tsagainst their native paths to catch any
latent bug where native writes bypass JS validation. - Reserved-label awareness (optional). Brainy's internal labels (
'vfs-*',
'materialized-aggregate','imported','extracted','mcp-message','cli-*') become
a documented part of the 8.0 contract; useful for telemetry that surfaces "X% of entities are
Brainy-managed infrastructure".
Docs
Updated
docs/guides/subtypes-and-facets.mdwith a new "Strict mode in practice" section
covering the SDK_CORE_VOCABULARY pattern, a 4-step migration recipe, the Brainy-internal label
reference table, and an 8.0 forward-look.docs/api/README.mddocumentsbrain.audit()and
adds a strict-mode tip to theadd()/relate()reference entries.Tests
- New
tests/integration/strict-mode-self-test.test.ts(13 tests): creates a brain under
the exact SDK_CORE_VOCABULARY shape Venue hit + brain-wide strict mode, then exercises every
internal Brainy path (VFS root/mkdir/writeFile/cp/mv/ln, aggregation engine, audit
diagnostic, error-message UX). Zero rejections expected. - Existing 7.30.0 + 7.29.0 integration suites unchanged: 26/26 + 30/30.
- Unit suite unchanged: 1468/1468.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- The caller's source location — extracted from the JavaScript stack so you see your own
-
released this
2026-06-05 20:16:15 +02:00 | 311 commits to main since this releaseAffected products: consumers modeling typed relationships with sub-classification
(direct vs dotted-line management; spouse / sibling / colleague; collaborator vs competitor;
etc.), and anyone wanting to enforce the pairing oftype+subtypeon every write.
Additive; drop-in from 7.29.x. No deprecations.Symmetric —
subtypeon relationships (parity with 7.29.0 nouns)subtype?: stringis now a first-class standard field on every relationship, mirroring the
noun-side work shipped in 7.29.0. Verbs and nouns are now first-class peers — every API
available on the noun side has a verb-side mirror.const ceoId = await brain.add({ type: NounType.Person, subtype: 'employee', data: 'Avery' }) const vpId = await brain.add({ type: NounType.Person, subtype: 'employee', data: 'Jordan' }) await brain.relate({ from: ceoId, to: vpId, type: VerbType.ReportsTo, subtype: 'direct' // sub-classification on the edge })Read & filter:
// Fast-path filter — column-store hit, not metadata fallback const direct = await brain.getRelations({ from: ceoId, type: VerbType.ReportsTo, subtype: 'direct' }) // Set membership const all = await brain.getRelations({ from: ceoId, type: VerbType.ReportsTo, subtype: ['direct', 'dotted-line'] }) // Traversal filter (depth-1 in JS; multi-hop lands on Cortex native) const reports = await brain.find({ connected: { from: ceoId, via: VerbType.ReportsTo, subtype: 'direct', depth: 1 } })New —
updateRelation()closes a long-standing gapVerbs previously had no update method — the only way to change a relationship was
delete-then-recreate, which lost the relation id. 7.30 shipsbrain.updateRelation():await brain.updateRelation({ id: relId, subtype: 'dotted-line' }) await brain.updateRelation({ id: relId, weight: 0.5, confidence: 0.9 }) // Change verb type — re-indexes in graph adjacency, id preserved await brain.updateRelation({ id: relId, type: VerbType.WorksWith })New — O(1) verb subtype counts via the persisted rollup
_system/verb-subtype-statistics.jsonmirrors the noun-side rollup shipped in 7.29.0.
Per-VerbType-per-subtype counts are maintained incrementally and persisted; reads are O(1):brain.counts.byRelationshipSubtype(VerbType.ReportsTo) // → { direct: 12, 'dotted-line': 3 } brain.counts.byRelationshipSubtype(VerbType.ReportsTo, 'direct') // O(1) point // → 12 brain.counts.topRelationshipSubtypes(VerbType.ReportsTo, 3) // → [['direct', 12], ['dotted-line', 3]] brain.relationshipSubtypesOf(VerbType.ReportsTo) // → ['direct', 'dotted-line']New —
brain.requireSubtype(type, options)per-type enforcementUnified API for noun OR verb types — register specific types as requiring a subtype,
optionally with a fixed vocabulary:brain.requireSubtype(NounType.Person, { values: ['employee', 'customer', 'vendor'], required: true }) brain.requireSubtype(VerbType.ReportsTo, { values: ['direct', 'dotted-line'], required: true }) // Now this throws — Person requires subtype: await brain.add({ type: NounType.Person, data: 'no subtype' }) // And this throws — 'matrix' isn't in the registered vocabulary: await brain.relate({ from: a, to: b, type: VerbType.ReportsTo, subtype: 'matrix' })New — Brain-wide strict mode
new Brainy({ requireSubtype: true })enforces subtype on every public write across the
whole brain. Composes with per-type rules; per-type rules win when both apply.// Every write must include subtype const brain = new Brainy({ requireSubtype: true }) // Exempt specific types (e.g. catch-all Thing) const brain2 = new Brainy({ requireSubtype: { except: [NounType.Thing, NounType.Custom] } })When strict mode is on:
- Every
add()/addMany()/update()/relate()/relateMany()/updateRelation()
rejects writes missing a subtype on a non-exempt type. addMany()andrelateMany()validate every item BEFORE any storage write —
atomic-fail semantics, no partial writes.- Brainy's own infrastructure writes (VFS root, directories, files) bypass via the
metadata.isVFSEntity: truemarker so existing consumers' VFS usage continues to work.
The brain-wide flag becomes the default in 8.0.0; the type-level
subtypefield becomes
required at the type system level. The full 8.0 contract upgrade is coordinated through the
internal platform handoff (CTX-SUBTYPE-8.0-CONTRACT).migrateField()extended to verbsThe migration helper shipped in 7.29.0 now walks verbs too via the new
entityKindoption:// Migrate verb-side metadata.kind → top-level subtype await brain.migrateField({ from: 'metadata.kind', to: 'subtype', entityKind: 'verb' }) // Or walk nouns and verbs in one pass await brain.migrateField({ from: 'metadata.kind', to: 'subtype', entityKind: 'both' })Default is
entityKind: 'noun'(backward-compatible).Symmetry — noun + verb capability matrix
7.30 closes every gap between nouns and verbs. Every capability available on the noun side
has a verb-side mirror:Capability Nouns Verbs subtypetop-level field✓ (7.29) ✓ (7.30 new) Standard-field set STANDARD_ENTITY_FIELDSSTANDARD_VERB_FIELDS(new)Field resolver helper resolveEntityFieldresolveVerbField(new)Statistics rollup _system/subtype-statistics.json_system/verb-subtype-statistics.json(new)Counts breakdown counts.bySubtype/topSubtypes/subtypesOfcounts.byRelationshipSubtype/topRelationshipSubtypes/relationshipSubtypesOf(new)Fast-path filter find({type, subtype})getRelations({type, subtype})+find({connected, subtype})(new)Update method update()updateRelation()(new — closed pre-7.30 gap)Migration helper migrateField()migrateField({entityKind: 'verb'|'both'})(new)Enforcement requireSubtype(NounType, ...)requireSubtype(VerbType, ...)— one unified APIBrain-wide strict mode new Brainy({ requireSubtype })covers bothsame Cortex compatibility
Verb subtype works under Cortex out of the box via auto-field-indexing. Cortex parity items
for the verb side (native query planner recognition,verbSubtypeCountsByTypenative rollup,
per-edge subtype on native graph adjacency for multi-hop traversal filtering) ship in the
next Cortex release. Not a Brainy blocker.Docs
Full guide:
docs/guides/subtypes-and-facets.md(extended with Layer V + Enforcement
sections). The verb subtype + enforcement APIs are documented indocs/api/README.md.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- Every
-
released this
2026-06-05 02:26:04 +02:00 | 313 commits to main since this releaseAffected products: anyone modeling entities with per-product sub-classification — every
consumer that's been reaching formetadata.kind, a custommetadata.subtypefield, a
data.kindshape inside the payload, or similar ad-hoc conventions. Additive; drop-in from
7.28.x. No deprecations.New —
subtypepromoted to a top-level standard fieldsubtype?: stringis now a first-class standard field on every entity, alongsidetype/
confidence/weight. Use it as the platform-standard primitive for sub-classifying entities
within a NounType (Person→'employee'/'customer';Document→'invoice'/'contract';
Event→'milestone'/'meeting'):await brain.add({ data: 'Avery Brooks — runs the AI lab', type: NounType.Person, subtype: 'employee', // top-level write param metadata: { department: 'ai-lab' } }) // Fast-path filter — column-store hit, not metadata fallback: const employees = await brain.find({ type: NounType.Person, subtype: 'employee' }) // Set membership: const internal = await brain.find({ type: NounType.Person, subtype: ['employee', 'contractor'] })Flat string, no hierarchy — your vocabulary, your choice. Brainy stores and counts, never validates.
New — O(1) subtype counts via the persisted rollup
A new
_system/subtype-statistics.jsonrollup is maintained incrementally as entities are added,
updated, and deleted — mirroring the existingnounCountsByTypemachinery with the same self-heal
behavior on poison detection. Counts are O(1) at billion scale:brain.counts.bySubtype(NounType.Person) // → { employee: 12, customer: 847, vendor: 34 } brain.counts.bySubtype(NounType.Person, 'employee') // O(1) point count // → 12 brain.counts.topSubtypes(NounType.Person, 3) // → [['customer', 847], ['employee', 12], ['vendor', 34]] brain.subtypesOf(NounType.Person) // → ['customer', 'employee', 'vendor']New —
brain.trackField()for other metadata facetsFor facets that aren't the primary sub-classification (
status,source,role,paradigm),
trackFieldregisters a field for cardinality + per-NounType breakdown stats without promoting
each one to a top-level slot. Piggybacks on the existing aggregation engine, so backfill-on-define
applies — registering on a populated brain scans existing entities on the first query:brain.trackField('status', { perType: true }) await brain.counts.byField('status') // → { todo: 12, doing: 3, done: 47 } await brain.counts.byField('status', { type: NounType.Task }) // → { todo: 8, doing: 2, done: 30 } // Opt-in vocabulary validation: brain.trackField('priority', { values: ['low', 'medium', 'high'] }) // brain.add({ ..., metadata: { priority: 'urgent' } }) → throwsNew — generic
brain.migrateField()for one-shot rewritesStreams every entity and copies a value from one field path to another. Supports top-level
standard fields,metadata.*, anddata.*paths; idempotent; with optionalreadBoth: true
deprecation window that preserves the source field alongside the new one:// Phase 1: dual-populate (legacy readers still work) await brain.migrateField({ from: 'metadata.kind', to: 'subtype', readBoth: true }) // ...readers migrate to subtype at their own pace... // Phase 2: clear the source field await brain.migrateField({ from: 'metadata.kind', to: 'subtype' }) // → { scanned: 1500, migrated: 1500, skipped: 0, errors: [] }Supports
batchSizeandonProgressfor large brains.Aggregation composition
subtypeis a standard-field group-by dimension out of the box — nowhere:wrapper, no
metadata-fallback overhead:await brain.find({ aggregate: { groupBy: ['type', 'subtype'], metrics: { count: { op: 'COUNT' } } } }) // [ // { groupKey: { type: 'person', subtype: 'customer' }, count: 847 }, // { groupKey: { type: 'person', subtype: 'employee' }, count: 12 }, // { groupKey: { type: 'document', subtype: 'invoice' }, count: 2103 }, // ... // ]Cortex compatibility
Subtype works under Cortex out of the box via auto-field-indexing. Cortex will land its own
native-side query-planner recognition +subtypeCountsByTypenative rollup in the next Cortex
release for full parity withtype's fast path. Not a Brainy blocker — subtype reads/writes
function correctly with current Cortex.Docs
Full guide:
docs/guides/subtypes-and-facets.md. Subtype is documented as a core primitive
throughoutREADME.md,docs/DATA_MODEL.md,docs/architecture/finite-type-system.md,
docs/api/README.md, anddocs/QUERY_OPERATORS.md.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
v7.28.0 Stable
released this
2026-05-28 21:27:29 +02:00 | 318 commits to main since this releaseDownloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
v7.27.0 Stable
released this
2026-05-28 20:55:37 +02:00 | 320 commits to main since this releaseDownloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
Source code (ZIP)
-
v7.26.0 Stable
released this
2026-05-28 19:38:18 +02:00 | 322 commits to main since this releaseWhat's Changed
- feat: stable EntityIdMapper — rebuild() no longer renumbers (2.4.0 #1, the foundation) by @dpsifr in https://github.com/soulcraftlabs/brainy/pull/1
New Contributors
- @dpsifr made their first contribution in https://github.com/soulcraftlabs/brainy/pull/1
Full Changelog: https://github.com/soulcraftlabs/brainy/compare/v7.25.0...v7.26.0
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads