brain

package
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package brain is Tacklr's knowledge-base retrieval engine.

Canonical architecture (Engrams, two jobs, search, graph, tools): docs/knowledge.md.

Public surface

Hosts use Engine (NewEngine + options), a Store implementation, an optional graph via WithGraph, kind registration (ApplyKinds / WithKinds), and composition helpers (LandingIDs, ExpandMany, ExpandByRecipe, SortRichObjects). MemoryStore and MemoryGraph are in-process backends for tests and offline hosts. Durable backends are injected: brain/postgres.Store and brain/helixgraph.Graph. Agent tools are registered by the harness when AgentOptions.Brain is set — they call Engine methods only.

Graph backend packages implement GraphReader / GraphWriter / GraphObjectSearcher / GraphEdgeSearcher. Dual-write property keys and Helix schema details stay inside those packages.

Hosts attach an Engine via AgentOptions.Brain. This package does not import postgres, helixgraph, the harness, session, or telemetry; Scope is passed in by the caller.

Engrams as files (vfs.Provider)

brain.Open returns a vfs.OpenFunc so first-class objects appear as Markdown + YAML files (vfs imports stay one-way: this package imports vfs). Layout is host-chosen: mode=prefix (default /engram/<kind-slug>/<slug>.md) or mode=roots (/deal/acme.md). Kind names are host KindSpecs and must be path-safe (no '/' or '..'). Only parent kinds are directories; parts/chunks are not files. Write/Close/PutFile parse, validate, and Put (fail closed). Rename is delete+create. Graph edges stay in the graph backend and show up through path-native link/expand/find_links — not sidecar files.

SearchContext is the retrieval session surface: host namespace + active ResultSet for continue (replaced on each search, find_exact, find_objects, or large expand).

Kind schemas (host migrations)

Object kinds are host/user-defined for determinism. Register with ApplyKinds (or WithKinds). Agent-defined kinds are out of scope.

Explicit writes (no handoff side effects)

Durable objects are written only via Engine.Put / SoftDelete (host SDK) or kind-scoped agent tools. Context handoff never writes the knowledge base.

Hosts map save_* tools via AgentOptions.BrainWriteKinds. Write for retrieval: fill title and summary (and useful properties) so search and find_objects work.

Graph nodes are live, not static: every parent Put dual-writes node props in place (edges preserved). SoftDelete removes the graph node first, then soft-deletes the store row. Revive via Put recreates the graph node.

Store vs graph (complementary)

The Store is the source of truth and document corpus: full rows, parts/chunks, BM25 + dense hybrid search, property filters, soft-delete, containment (parent_id). Tools: search, find_exact, read; expand children. search may pass ScopeIDs to limit hits to a parent neighborhood.

The graph holds first-class entity nodes and cross-object edges only (not chunks). Helix owns: native text/vector indexes, $distance ranking, graph topology, edge props, BothE neighbor walks, optional tenant indexes on namespace. Tacklr does not reimplement BM25/HNSW or in-process neighbor indexes for Helix. We dual-write searchable props (EntityIndexText + embedding), Link edges, fuse graph text+vector channels with RRF, then hydrate full rows from the Store under Scope.

Tools: find_objects (after graph Bootstrap), expand with relation_types, link. Optional: helixgraph.EnsureEdgeTextIndex(rel) + SearchEdgesText for note search on a known relation label.

GraphRAG-style composition (host-agnostic):

find_objects (entity land; filters via schema filterable_fields)
  or search/find_exact (corpus) → LandingIDs (parent promote)
→ expand / ExpandMany (max_hops, direction, WantContainment)
  or ExpandByRecipe (host-named ExpandRequest template) → hydrate Store
→ optional find_links (edge text) for relationship-first land
→ search(scope_ids=…) for neighborhood corpus
→ optional host Reranker after hydrate; SortRichObjects for peer ordering

Graph-first then store drill-down:

find_objects / expand(graph) → graph ids → hydrate from Store
expand() containment → Store.ListChildren (chunks)
read / search → Store

schema() returns filter_usage.tools listing search, find_exact, and find_objects so agents know filterable_fields apply to entity find as well as corpus search.

Embeddings: WithEmbedder on NewEngine. Parents embed EntityIndexText; parts embed IndexText with parent title prefix (corpus only). One embedding dimension per process. Helix hosts must call helixgraph.Graph.Bootstrap (or EnsureSearchIndexes) so HasObjectSearch is true; MemoryGraph is always ready when attached. Bootstrap(true) enables Helix tenant filtering when the image supports it.

Boot sketch

store, err := postgres.New(pool)
store.EmbeddingDim = 1536 // optional; default 1536
if err := store.Setup(ctx, specs...); err != nil { return err }
g, err := helixgraph.New(helixURL)
if err := g.Bootstrap(ctx, false); err != nil { return err }
eng, err := brain.NewEngine(store, brain.WithEmbedder(emb), brain.WithGraph(g))
if err := eng.LoadKindsFromStore(ctx); err != nil { return err }

Integration tests (skipped under -short / without Docker):

  • postgres.Store: Testcontainers + brain/testdata/Dockerfile.postgres
  • helixgraph: Testcontainers + ghcr.io/helixdb/enterprise-dev (in-memory)

Index

Constants

View Source
const (
	DefaultProfile    = "brain"
	DefaultMountPoint = "/workspace/engram"
	ModePrefix        = "prefix"
	ModeRoots         = "roots"
	// MaxEngramReadDir caps Provider ReadDir / ListByKind listings (paginate later).
	MaxEngramReadDir = 500
)

Mount layout and factory defaults.

View Source
const (
	PropSlug    = "slug"
	PropVFSPath = "vfs_path"
)

Reserved store properties persisted on objects without a KindSpec field. slug is the Engram filename stem. vfs_path is Provider-internal (full virtual path); it is not a Markdown front-matter key.

Variables

View Source
var (
	// ErrNotFound is returned when an object is missing, soft-deleted, or outside scope.
	ErrNotFound = errors.New("brain: object not found")
	// ErrInvalid groups validation failures (empty query, missing args, frozen catalog).
	ErrInvalid = errors.New("brain: invalid")
	// ErrUnsupported groups missing backend capabilities (no writer, no graph, no listing).
	ErrUnsupported = errors.New("brain: unsupported")
	// ErrGraphEnsure / ErrGraphRemove are dual-write failures. Callers re-Put
	// after fixing the graph; store row is the source of truth.
	ErrGraphEnsure = errors.New("brain: graph ensure object")
	ErrGraphRemove = errors.New("brain: graph remove object")
)

Coarse categories for errors.Is. Wrap a specific message at the call site (fmt.Errorf("…: %w", ErrInvalid)) instead of adding a sentinel per situation.

Functions

func EngramPath added in v0.2.0

func EngramPath(point, mode, kind, slug string) string

EngramPath is the virtual path for an Engram file (prefix or roots).

func EntityIndexText

func EntityIndexText(obj Object) string

EntityIndexText builds text for first-class graph nodes and parent embeddings: title, summary, scalar properties (sorted keys), and full content.

func FilterSQL added in v0.2.0

func FilterSQL(scope Scope, filters Filter, startArg int) (string, []any, error)

FilterSQL compiles filters into a WHERE fragment and bound args for a relational store. startArg is the first $N placeholder (usually 2 when $1 is the query). The fragment begins with AND when non-empty.

func FormatEngram added in v0.2.0

func FormatEngram(f EngramFile) ([]byte, error)

FormatEngram encodes an Engram as Markdown + YAML front matter. Key order is stable: id, domain, slug, title, then remaining property keys sorted. vfs_path is never written (Provider-internal).

func IndexText

func IndexText(obj Object) string

IndexText joins non-empty title, summary, and content for corpus part embeds.

func IndexTextWithParent

func IndexTextWithParent(obj Object, parentTitle string) string

IndexTextWithParent prefixes parent context (bursting-style) when parentTitle is set.

func IsContainmentRelation

func IsContainmentRelation(rel string) bool

IsContainmentRelation is true for contains / part_of (and partof).

func IsParentKind added in v0.2.0

func IsParentKind(spec KindSpec) bool

IsParentKind reports whether a kind is listed as files (not parts/chunks).

func KindSlug added in v0.2.0

func KindSlug(kind string) string

KindSlug is the v1 directory name for a kind (lowercased).

func LandingIDs

func LandingIDs(objects []RichObject) []uuid.UUID

LandingIDs returns unique first-class object ids suitable for graph expand / link endpoints from rich hits (search, find_exact, find_objects). Parts use ParentID; parents use their own ID. Nil / empty parent pointers are skipped.

Use after corpus search so Phase 1 can land on chunks while Phase 2 expands from the dual-written parent entity on Helix.

func MountForKind added in v0.2.0

func MountForKind(specs []vfs.MountSpec, kind string) (vfs.MountSpec, bool)

MountForKind selects the roots mount for kind, then a prefix mount, then any brain mount. Harness tool adapters use this canonical layout resolver.

func NormalizeRelationTypes

func NormalizeRelationTypes(rels []string) []string

NormalizeRelationTypes trims, drops empties, and dedupes labels (case-insensitive). Exported so backends (e.g. helixgraph) share one normalizer.

func Open added in v0.2.0

func Open(eng *Engine, scope Scope) vfs.Open

Open returns a vfs.Open over Engine objects (Engrams as Markdown files). Hosts pass At("engram", brain.Open(eng, scope)).

func PersistKinds

func PersistKinds(ctx context.Context, w KindWriter, specs ...KindSpec) error

PersistKinds upserts validated kind specs into any KindWriter (additive).

func Slugify added in v0.2.0

func Slugify(title string) string

Slugify is the path slug for an Engram title (same rules as vfs.Slugify).

func SortRichObjects

func SortRichObjects(objects []RichObject, key string, desc bool)

SortRichObjects sorts objects in place by a well-known or property key. Keys: "updated_at", "created_at", "title", "position", or a property name.

func SplitRelationTypes

func SplitRelationTypes(rels []string) (wantContainment bool, graphLabels []string)

SplitRelationTypes returns whether containment apply and remaining graph labels. Empty input means containment-only.

func ValidateFilters

func ValidateFilters(f Filter) error

ValidateFilters checks well-known fields and property value shapes. Empty is valid.

func ValidateFiltersAgainst

func ValidateFiltersAgainst(f Filter, cat *KindCatalog) error

ValidateFiltersAgainst runs structural validation, then catalog rules when non-empty.

func ValidateObject

func ValidateObject(obj Object, cat *KindCatalog) error

ValidateObject checks an object against the kind catalog when non-empty.

func ValidateObjectIdentity added in v0.2.0

func ValidateObjectIdentity(obj Object) error

ValidateObjectIdentity checks id, kind, and namespace before a store Put.

Types

type Attr added in v0.2.0

type Attr struct {
	Name  string `json:"name" desc:"Attribute name (e.g. org, workspace)."`
	Value string `json:"value" desc:"Attribute value. Must not contain '.'."`
}

Attr is one named isolation dimension (org, workspace, …). Name and Value must be non-empty and must not contain '.'.

type EdgeMeta

type EdgeMeta struct {
	Note       string     `json:"note,omitempty"`
	Status     string     `json:"status,omitempty"`     // e.g. active, resolved
	Role       string     `json:"role,omitempty"`       // e.g. primary buyer vs cc
	Confidence float64    `json:"confidence,omitempty"` // 0 means unset; otherwise typically (0,1]
	EvidenceID *uuid.UUID `json:"evidence_id,omitempty"`
	CreatedAt  time.Time  `json:"created_at,omitempty"`
	UpdatedAt  time.Time  `json:"updated_at,omitempty"`
}

EdgeMeta is optional metadata on a non-containment relationship (why/how/when linked). Kept short and relational — full bodies stay on objects in the Store.

func (EdgeMeta) IsZero

func (m EdgeMeta) IsZero() bool

IsZero reports whether meta carries no meaningful fields.

type EdgeSearchHit

type EdgeSearchHit struct {
	FromID       uuid.UUID
	ToID         uuid.UUID
	RelationType string
	Meta         EdgeMeta
	Score        float64
}

EdgeSearchHit is one graph edge search result (endpoints + meta + score).

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the retrieval facade over a Store.

func NewEngine

func NewEngine(store Store, opts ...EngineOption) (*Engine, error)

NewEngine builds an Engine over a Store. store must be non-nil.

func (*Engine) ApplyKinds

func (e *Engine) ApplyKinds(ctx context.Context, specs ...KindSpec) error

ApplyKinds is the host migration entry point: desired process catalog + optional durable upsert.

func (*Engine) Catalog

func (e *Engine) Catalog() *KindCatalog

Catalog returns the process kind catalog for inspection and host filter validation (e.g. ValidateFiltersAgainst). Empty means open mode. Prefer store.Setup plus LoadKindsFromStore, or ApplyKinds; do not mutate catalog fields directly.

func (*Engine) Continue

func (e *Engine) Continue(ctx context.Context, scope Scope, resultSetID uuid.UUID, limit int, results ResultSetStore) (page SearchPage, err error)

Continue returns the next page of a prior ResultSet under scope.

func (*Engine) Expand

func (e *Engine) Expand(ctx context.Context, scope Scope, req ExpandRequest, results ResultSetStore) (res ExpandResult, err error)

Expand returns the structural neighborhood of object_id under scope.

func (*Engine) ExpandByRecipe

func (e *Engine) ExpandByRecipe(ctx context.Context, scope Scope, objectID uuid.UUID, recipeName string, results ResultSetStore) (ExpandResult, error)

ExpandByRecipe looks up a host-registered ExpandRecipe and runs Expand with it.

func (*Engine) ExpandMany

func (e *Engine) ExpandMany(ctx context.Context, scope Scope, req ExpandManyRequest) (res ExpandManyResult, err error)

ExpandMany walks the graph from many landing ids without paging / SearchContext. First seed to claim a neighbor wins Relation.SourceID. Out-of-scope seeds are skipped.

func (*Engine) FindExact

func (e *Engine) FindExact(ctx context.Context, scope Scope, req SearchRequest, results ResultSetStore) (SearchPage, error)

FindExact runs equality-first exact retrieval (no dense channel), then lexical + trigram fusion, promotion, and ResultSet materialization.

func (e *Engine) FindLinks(ctx context.Context, scope Scope, req FindLinksRequest) (res FindLinksResult, err error)

FindLinks lands on relationships via GraphEdgeSearcher, then hydrates endpoints under Scope.

func (*Engine) FindObjects

func (e *Engine) FindObjects(ctx context.Context, scope Scope, req FindObjectsRequest, results ResultSetStore) (page SearchPage, err error)

FindObjects ranks knowledge objects as entities via GraphObjectSearcher (Helix text/vector or MemoryGraph), then hydrates under Scope from the store. Filters use the same catalog rules as search/find_exact (schema filterable_fields). Not a substitute for corpus Search: no part promotion evidence path.

func (*Engine) FreezeCatalog

func (e *Engine) FreezeCatalog()

FreezeCatalog rejects further RegisterKinds / LoadKindsFromStore. Also auto-frozen on first search/find_exact when the catalog is non-empty.

func (*Engine) Get added in v0.2.0

func (e *Engine) Get(ctx context.Context, scope Scope, id uuid.UUID) (Object, error)

Get returns the stored object (including Content) under scope.

func (*Engine) GetByProperty added in v0.2.0

func (e *Engine) GetByProperty(ctx context.Context, scope Scope, key, value string) (Object, error)

GetByProperty returns the first live object whose properties[key] equals value.

func (*Engine) HasEdgeSearch

func (e *Engine) HasEdgeSearch() bool

HasEdgeSearch reports whether FindLinks is available.

func (*Engine) HasGraphWriter

func (e *Engine) HasGraphWriter() bool

HasGraphWriter reports whether Put dual-write and Link are available.

func (*Engine) HasObjectSearch

func (e *Engine) HasObjectSearch() bool

HasObjectSearch reports whether FindObjects / find_objects is available.

func (*Engine) KindsWithObjects added in v0.2.0

func (e *Engine) KindsWithObjects(ctx context.Context, scope Scope) ([]string, error)

KindsWithObjects lists distinct parent-kind names that already have objects under scope.

func (e *Engine) Link(ctx context.Context, scope Scope, from, to uuid.UUID, relationType string) error

Link creates a non-containment edge from→to between first-class, visible objects. Both endpoints must exist under scope, must not be soft-deleted, and must not be parts. Equivalent to LinkWith with zero EdgeMeta.

func (*Engine) LinkWith

func (e *Engine) LinkWith(ctx context.Context, scope Scope, from, to uuid.UUID, relationType string, meta EdgeMeta) error

LinkWith is Link plus optional relationship metadata (note, status, role, …).

func (*Engine) ListByKind added in v0.2.0

func (e *Engine) ListByKind(ctx context.Context, scope Scope, kind string, limit int) ([]Object, error)

ListByKind returns first-class objects of kind (parent_id unset), newest-title order left to the store.

func (*Engine) ListChildren

func (e *Engine) ListChildren(ctx context.Context, scope Scope, parentID uuid.UUID) ([]RichObject, error)

ListChildren returns ordered children for a parent visible under scope.

func (*Engine) LoadKindsFromStore

func (e *Engine) LoadKindsFromStore(ctx context.Context) error

LoadKindsFromStore replaces the process catalog from the store.

func (*Engine) Put

func (e *Engine) Put(ctx context.Context, scope Scope, obj Object) (Object, error)

Put upserts a knowledge object under scope. Catalog non-empty → ValidateObject. Namespace filled from scope when missing. ID generated when nil. Put refuses objects that already have DeletedAt set. When WithEmbedder is set and index text is non-empty, embeds and stores the vector; embed errors fail the Put (fail closed). Parent Puts dual-write the graph node (in-place upsert; edges preserved). If the graph Ensure fails after a successful store write, the store row remains (source of truth); callers should re-Put after fixing the graph.

func (*Engine) Read

func (e *Engine) Read(ctx context.Context, scope Scope, id uuid.UUID) (RichObject, error)

Read returns the full rich object for id under scope.

func (*Engine) RegisterExpandRecipe

func (e *Engine) RegisterExpandRecipe(r ExpandRecipe) error

RegisterExpandRecipe adds or replaces a named expand view. Safe for concurrent use with ExpandByRecipe.

func (*Engine) RegisterKinds

func (e *Engine) RegisterKinds(_ context.Context, specs ...KindSpec) error

RegisterKinds merges host kind definitions into the process catalog. Re-registering an existing kind name replaces that kind. Fails if the catalog is frozen.

func (*Engine) Schema

func (e *Engine) Schema(ctx context.Context, kind string) (SchemaResult, error)

Schema returns kind documentation. Empty kind lists all registered kinds. When the process catalog is non-empty it is the source of truth; otherwise the store registry is used.

func (*Engine) Search

func (e *Engine) Search(ctx context.Context, scope Scope, req SearchRequest, results ResultSetStore) (SearchPage, error)

Search runs hybrid retrieval (BM25 + optional vector), RRF, temporal decay, parent promotion, and materializes a ResultSet into results.

func (*Engine) SoftDelete

func (e *Engine) SoftDelete(ctx context.Context, scope Scope, id uuid.UUID) error

SoftDelete removes the graph node first (when present), then marks the store row deleted. Graph-first keeps store intact if graph removal fails. If store SoftDelete fails after a successful graph remove, re-Put re-creates the graph node.

func (*Engine) SyncKindsToStore

func (e *Engine) SyncKindsToStore(ctx context.Context) error

SyncKindsToStore pushes the process catalog to the store.

func (e *Engine) Unlink(ctx context.Context, scope Scope, from, to uuid.UUID, relationType string) error

Unlink removes a non-containment edge from→to. Endpoints must be visible first-class objects.

type EngineConfig

type EngineConfig struct {
	CandidateK          int
	RRFk                int
	Lambda              *float64
	EvidenceN           int
	DefaultLimit        int
	MaxLimit            int
	ExpandInlineMax     int
	SiblingRadius       int
	GraphNeighborK      int
	MaxExpandHops       int // max MaxHops on expand (default 4)
	MaxGraphExpandRPCs  int // cap Neighbors calls per multi-hop expand (default 64)
	MaxResultSetSize    int
	FailOnEmbedderError bool
	FailOnGraphError    bool
	Now                 func() time.Time
}

EngineConfig holds engine-owned ranking knobs (not tool arguments). Lambda nil → default mild decay; explicit 0 disables temporal bias. FailOn* false (default) soft-degrades embedder/graph failures; true surfaces errors.

func DefaultEngineConfig

func DefaultEngineConfig() EngineConfig

DefaultEngineConfig returns mild production defaults.

type EngineOption

type EngineOption func(*Engine)

EngineOption configures NewEngine.

func WithConfig

func WithConfig(cfg EngineConfig) EngineOption

WithConfig sets ranking configuration (normalized by NewEngine).

func WithEmbedder

func WithEmbedder(e QueryEmbedder) EngineOption

WithEmbedder sets the optional query embedder for hybrid search.

func WithExpandRecipes

func WithExpandRecipes(recipes ...ExpandRecipe) EngineOption

WithExpandRecipes registers host-named expand views at construct time. Each recipe is a named ExpandRequest template (ObjectID filled at call time). Invalid recipes (empty name) fail NewEngine.

func WithGraph

func WithGraph(g GraphReader) EngineOption

WithGraph sets the optional non-containment graph backend (helixgraph or MemoryGraph). Writer and object-search capabilities are resolved once here (not re-asserted per call).

func WithKinds

func WithKinds(specs ...KindSpec) EngineOption

WithKinds registers host-defined object kinds at construct time. Invalid specs cause NewEngine to fail. Kinds are host/user-owned for determinism.

func WithReranker

func WithReranker(r Reranker) EngineOption

WithReranker sets an optional post-hydrate reranker for search and find_objects.

type EngramFile added in v0.2.0

type EngramFile struct {
	ID         uuid.UUID
	Kind       string
	Slug       string
	Title      string
	Properties map[string]any
	Body       string
}

EngramFile is the Markdown + YAML front-matter view of a first-class object.

Front-matter reserved keys: id, domain/kind, slug, title. Remaining keys become Object.Properties. The body becomes Object.Content.

Parse splits on the first pair of --- fences. A --- line inside the YAML block ends front matter (standard). The body after the closing fence may contain ---; there is no support for a --- document start inside the YAML mapping itself.

func EngramFromObject added in v0.2.0

func EngramFromObject(obj Object) EngramFile

EngramFromObject serializes a stored object (drops vfs_path from front matter).

func ParseEngram added in v0.2.0

func ParseEngram(data []byte) (EngramFile, error)

ParseEngram decodes Markdown with optional YAML front matter.

type Evidence

type Evidence struct {
	PartID     uuid.UUID      `json:"part_id"`
	Title      string         `json:"title,omitempty"`
	Snippet    string         `json:"snippet,omitempty"`
	Score      float64        `json:"score,omitempty"`
	Position   *int           `json:"position,omitempty"`
	Properties map[string]any `json:"properties,omitempty"`
}

Evidence is a part that justified a parent hit during search.

type ExpandManyRequest

type ExpandManyRequest struct {
	ObjectIDs       []uuid.UUID
	RelationTypes   []string
	MaxHops         int
	Direction       string
	NeighborBudget  int  // max unique neighbors total; default MaxResultSetSize
	WantContainment bool // same semantics as ExpandRequest.WantContainment
}

ExpandManyRequest expands several landing objects with shared hop parameters.

type ExpandManyResult

type ExpandManyResult struct {
	Objects []RichObject `json:"objects"`
}

ExpandManyResult is a flat neighbor list; Relation.SourceID is the landing id.

type ExpandRecipe

type ExpandRecipe struct {
	Name            string
	RelationTypes   []string
	MaxHops         int
	Direction       string
	WantContainment bool
}

ExpandRecipe is a host-registered named ExpandRequest template. ObjectID (and optional Limit / ResultSetStore) are supplied at call time. Register at construct via WithExpandRecipes, or later via RegisterExpandRecipe.

type ExpandRequest

type ExpandRequest struct {
	ObjectID      uuid.UUID
	RelationTypes []string // graph labels; contains/part_of also request containment
	MaxHops       int      // graph depth; default 1; capped by MaxExpandHops
	Direction     string   // out | in | both (default both)
	Limit         int
	// WantContainment forces Postgres containment (children / parent+siblings)
	// alongside any graph labels. When RelationTypes is empty, containment is
	// always applied (default expand). Prefer this flag over smuggling "contains"
	// into RelationTypes when registering recipes or ExpandMany.
	WantContainment bool
}

ExpandRequest is the engine input for expand.

type ExpandResult

type ExpandResult struct {
	Objects     []RichObject `json:"objects"`
	ResultSetID uuid.UUID    `json:"result_set_id,omitempty"`
	HasMore     bool         `json:"has_more"`
	Mode        string       `json:"mode"` // children | neighborhood | graph | mixed
}

ExpandResult is the agent-facing expand payload.

type FieldSpec

type FieldSpec struct {
	Name        string    `json:"name"`
	Type        FieldType `json:"type"`
	Description string    `json:"description,omitempty"`
	Required    bool      `json:"required,omitempty"`
	Operators   []string  `json:"operators,omitempty"` // always eq, or eq+in (see NormalizeKindSpec)
	Examples    []string  `json:"examples,omitempty"`
}

FieldSpec describes one filterable (and later writable) property on a kind.

type FieldType

type FieldType string

FieldType is the closed set of property types for kind schemas.

const (
	FieldTypeString   FieldType = "string"
	FieldTypeNumber   FieldType = "number"
	FieldTypeBoolean  FieldType = "boolean"
	FieldTypeDateTime FieldType = "datetime"
)

type Filter added in v0.2.0

type Filter struct {
	Kind          StringMatch
	Title         StringMatch
	CreatedAfter  string
	CreatedBefore string
	UpdatedAfter  string
	UpdatedBefore string
	Props         map[string]PropFilter
}

Filter narrows retrieval. Well-known fields plus Props. Eq or list (In).

func DecodeFilter added in v0.2.0

func DecodeFilter(m map[string]any) (Filter, error)

DecodeFilter maps a JSON object (tool boundary) onto Filter.

type FilterUsage

type FilterUsage struct {
	// Tools list knowledge tools that accept the same property filter keys as filterable_fields.
	Tools []string `json:"tools"`
	// Note is short instruction text for the agent.
	Note string `json:"note"`
}

FilterUsage is agent-facing guidance for structured filters (shared by corpus and entity find).

func DefaultFilterUsage

func DefaultFilterUsage() FilterUsage

DefaultFilterUsage is embedded in every SchemaResult.

type FindLinksRequest

type FindLinksRequest struct {
	RelationType string // required edge label (e.g. about, references)
	Query        string
	Limit        int
}

FindLinksRequest searches graph edges by text (Helix edge text index or MemoryGraph).

type FindLinksResult

type FindLinksResult struct {
	Links []LinkHit `json:"links"`
}

FindLinksResult is the agent-facing edge search payload.

type FindObjectsRequest

type FindObjectsRequest struct {
	Query   string
	Kinds   []string // optional host kind names; empty = all kinds
	Filters Filter   // same property keys as search; see schema filterable_fields
	Limit   int
}

FindObjectsRequest is the engine input for entity/object find (graph node search).

type GraphEdgeSearcher

type GraphEdgeSearcher interface {
	SearchEdgesText(ctx context.Context, relationType, query string, limit int) ([]EdgeSearchHit, error)
}

GraphEdgeSearcher finds edges by text (e.g. Helix TextSearchEdges on note).

type GraphNeighbor

type GraphNeighbor struct {
	ObjectID     uuid.UUID
	RelationType string
	Direction    string // "out" | "in"
	Meta         EdgeMeta
}

GraphNeighbor is one edge-adjacent object from the knowledge graph.

type GraphObjectSearcher

type GraphObjectSearcher interface {
	SearchText(ctx context.Context, query string, limit int, namespace Namespace) ([]ScoredID, error)
	SearchVector(ctx context.Context, embedding []float32, limit int, namespace Namespace) ([]ScoredID, error)
}

GraphObjectSearcher finds entity nodes by text and/or vector (Helix native indexes or MemoryGraph in-process). Results are ranked best-first; Engine hydrates under Scope. Namespace is applied by MemoryGraph via Covers; Helix returns unscoped candidates and Engine hydrates under Scope.

type GraphReader

type GraphReader interface {
	Neighbors(ctx context.Context, objectID uuid.UUID, relationTypes []string, limit int) ([]GraphNeighbor, error)
}

GraphReader traverses non-containment relations. Engine hydrates ids under Scope.

type GraphWriter

type GraphWriter interface {
	GraphReader
	// EnsureObject upserts a graph node for obj.ID (searchable props when available).
	// Must preserve incident edges (update in place, not drop+recreate).
	EnsureObject(ctx context.Context, obj Object) error
	// RemoveObject drops the node (and incident edges) after/with store soft-delete.
	RemoveObject(ctx context.Context, id uuid.UUID) error
	// AddEdge creates a directed edge from→to with optional relationship metadata.
	AddEdge(ctx context.Context, from, to uuid.UUID, relationType string, meta EdgeMeta) error
	// RemoveEdge drops the directed labeled edge from→to (idempotent if missing).
	RemoveEdge(ctx context.Context, from, to uuid.UUID, relationType string) error
}

GraphWriter persists graph nodes and non-containment edges (Helix dual-write / MemoryGraph). Embeds GraphReader so a single WithGraph value can satisfy both read and write.

type KindCatalog

type KindCatalog struct {
	// contains filtered or unexported fields
}

KindCatalog is the process-local enforcement view of registered kinds. Empty means open mode. Specs are treated as immutable after registration.

func (*KindCatalog) All

func (c *KindCatalog) All() []KindSpec

func (*KindCatalog) Empty

func (c *KindCatalog) Empty() bool

func (*KindCatalog) Freeze

func (c *KindCatalog) Freeze()

func (*KindCatalog) Get

func (c *KindCatalog) Get(kind string) (KindSpec, bool)

func (*KindCatalog) Names

func (c *KindCatalog) Names() []string

type KindReader

type KindReader interface {
	GetKind(ctx context.Context, kind string) (ObjectKind, error)
	ListKinds(ctx context.Context) ([]ObjectKind, error)
}

KindReader reads durable kind schema rows (schema fallback, LoadKindsFromStore).

type KindRegistry

type KindRegistry interface {
	KindReader
	KindWriter
}

KindRegistry is KindReader + KindWriter for durable kind schemas.

type KindSpec

type KindSpec struct {
	Kind        string
	Description string
	IsParent    bool
	IsPart      bool
	Fields      []FieldSpec
}

KindSpec is the host-facing definition of a knowledge object kind.

func KindSpecFromObjectKind

func KindSpecFromObjectKind(k ObjectKind) (KindSpec, error)

KindSpecFromObjectKind parses a registry row into a KindSpec.

func NormalizeKindSpec

func NormalizeKindSpec(spec KindSpec) (KindSpec, error)

NormalizeKindSpec validates a kind and fills default operators (eq / eq+in).

func (KindSpec) Field

func (s KindSpec) Field(name string) (FieldSpec, bool)

Field returns the named field when present.

type KindWriter

type KindWriter interface {
	PutKind(ctx context.Context, k ObjectKind) error
}

KindWriter upserts durable kind schema rows (ApplyKinds / PersistKinds). Not required for open-mode or process-only catalogs. Together with KindReader this is KindRegistry — implement both for a custom durable backend.

type LinkHit

type LinkHit struct {
	From         RichObject `json:"from"`
	To           RichObject `json:"to"`
	RelationType string     `json:"relation_type"`
	Meta         EdgeMeta   `json:"meta,omitempty"`
	Score        float64    `json:"score,omitempty"`
}

LinkHit is one edge land result with hydrated endpoints when visible under scope.

type MemoryGraph

type MemoryGraph struct {
	// contains filtered or unexported fields
}

MemoryGraph is an in-process GraphReader/GraphWriter/GraphObjectSearcher (tests / offline). Edges are a single map; directions are derived on Neighbors.

func NewMemoryGraph

func NewMemoryGraph() *MemoryGraph

NewMemoryGraph returns an empty graph.

func (*MemoryGraph) AddEdge

func (g *MemoryGraph) AddEdge(ctx context.Context, from, to uuid.UUID, relationType string, meta EdgeMeta) error

AddEdge implements GraphWriter. Upserts the edge for (from, to, relationType).

func (*MemoryGraph) EnsureObject

func (g *MemoryGraph) EnsureObject(ctx context.Context, obj Object) error

EnsureObject implements GraphWriter and stores searchable props for FindObjects. Replaces any prior node for the same id (live update; edges are independent).

func (*MemoryGraph) Neighbors

func (g *MemoryGraph) Neighbors(ctx context.Context, objectID uuid.UUID, relationTypes []string, limit int) ([]GraphNeighbor, error)

Neighbors implements GraphReader (both directions, deduped by object id). Single scan of the edge map, then ordered by request relation list / out-before-in.

func (*MemoryGraph) RemoveEdge added in v0.2.0

func (g *MemoryGraph) RemoveEdge(ctx context.Context, from, to uuid.UUID, relationType string) error

RemoveEdge implements GraphWriter. Missing edges succeed (idempotent).

func (*MemoryGraph) RemoveObject

func (g *MemoryGraph) RemoveObject(ctx context.Context, id uuid.UUID) error

RemoveObject implements GraphWriter.

func (*MemoryGraph) SearchEdgesText

func (g *MemoryGraph) SearchEdgesText(ctx context.Context, relationType, query string, limit int) ([]EdgeSearchHit, error)

SearchEdgesText implements GraphEdgeSearcher (substring match on edge note).

func (*MemoryGraph) SearchText

func (g *MemoryGraph) SearchText(ctx context.Context, query string, limit int, namespace Namespace) ([]ScoredID, error)

SearchText implements GraphObjectSearcher (case-fold substring on entity index text).

func (*MemoryGraph) SearchVector

func (g *MemoryGraph) SearchVector(ctx context.Context, embedding []float32, limit int, namespace Namespace) ([]ScoredID, error)

SearchVector implements GraphObjectSearcher via cosine similarity on stored embeddings.

type MemoryStore

type MemoryStore struct {
	// contains filtered or unexported fields
}

MemoryStore is an in-process Store (tests, fixtures, and ObjectWriter for Engine.Put).

func NewMemoryStore

func NewMemoryStore() *MemoryStore

NewMemoryStore returns an empty memory-backed store.

func (*MemoryStore) Get

func (s *MemoryStore) Get(_ context.Context, scope Scope, id uuid.UUID) (Object, error)

Get implements ObjectReader.

func (*MemoryStore) GetByProperty added in v0.2.0

func (s *MemoryStore) GetByProperty(_ context.Context, scope Scope, key, value string) (Object, error)

GetByProperty implements ObjectLister.

func (*MemoryStore) GetKind

func (s *MemoryStore) GetKind(_ context.Context, kind string) (ObjectKind, error)

GetKind implements KindReader.

func (*MemoryStore) GetMany

func (s *MemoryStore) GetMany(_ context.Context, scope Scope, ids []uuid.UUID) ([]Object, error)

GetMany implements ObjectReader.

func (*MemoryStore) KindsWithObjects added in v0.2.0

func (s *MemoryStore) KindsWithObjects(_ context.Context, scope Scope) ([]string, error)

KindsWithObjects implements ObjectLister.

func (*MemoryStore) ListByKind added in v0.2.0

func (s *MemoryStore) ListByKind(_ context.Context, scope Scope, kind string, limit int) ([]Object, error)

ListByKind implements ObjectLister (first-class objects only).

func (*MemoryStore) ListChildren

func (s *MemoryStore) ListChildren(_ context.Context, scope Scope, parentID uuid.UUID) ([]Object, error)

ListChildren implements ObjectReader.

func (*MemoryStore) ListKinds

func (s *MemoryStore) ListKinds(_ context.Context) ([]ObjectKind, error)

ListKinds implements KindReader.

func (*MemoryStore) Put

func (s *MemoryStore) Put(_ context.Context, obj Object) error

Put implements ObjectWriter. Soft-deleted rows may be stored; Get hides them. Clones maps/slices so callers cannot mutate the store through shared references.

func (*MemoryStore) PutKind

func (s *MemoryStore) PutKind(_ context.Context, k ObjectKind) error

PutKind implements KindWriter.

func (*MemoryStore) SearchLexical

func (s *MemoryStore) SearchLexical(_ context.Context, scope Scope, query string, filters Filter, k int) ([]ScoredID, error)

SearchLexical implements PartSearcher with a deterministic TF×IDF-style score. Only content-bearing parts (parent_id set) are candidates.

func (*MemoryStore) SearchTrigram

func (s *MemoryStore) SearchTrigram(_ context.Context, scope Scope, query string, filters Filter, k int) ([]ScoredID, error)

SearchTrigram implements PartSearcher with case-fold substring / trigram overlap.

func (*MemoryStore) SearchVector

func (s *MemoryStore) SearchVector(_ context.Context, scope Scope, embedding []float32, filters Filter, k int) ([]ScoredID, error)

SearchVector implements PartSearcher via cosine similarity on Object.Embedding.

func (*MemoryStore) SoftDelete

func (s *MemoryStore) SoftDelete(_ context.Context, scope Scope, id uuid.UUID) error

SoftDelete implements ObjectWriter.

type Namespace added in v0.2.0

type Namespace []Attr

Namespace is ordered named isolation attrs. Empty Scope means no isolation. Covers: every scope attr is present on the object with the same value.

func ParseNamespace added in v0.2.0

func ParseNamespace(nameValues ...string) (Namespace, error)

ParseNamespace builds a Namespace from name, value, name, value, ….

func (Namespace) Bind added in v0.2.0

func (ceiling Namespace) Bind(call Namespace) (Namespace, error)

Bind merges a per-call namespace onto this host ceiling. Call may add attrs. A call value that disagrees with a ceiling attr is invalid.

func (Namespace) Clone added in v0.2.0

func (n Namespace) Clone() Namespace

Clone returns a copy of n.

func (Namespace) Covers added in v0.2.0

func (scope Namespace) Covers(obj Namespace) bool

Covers reports whether obj is visible under this scope. Empty scope covers all.

func (Namespace) Empty added in v0.2.0

func (n Namespace) Empty() bool

Empty reports whether n has no attributes (no isolation when used as a Scope).

func (Namespace) Equal added in v0.2.0

func (n Namespace) Equal(o Namespace) bool

Equal reports whether n and o have the same attrs in the same order.

func (*Namespace) Scan added in v0.2.0

func (n *Namespace) Scan(src any) error

Scan implements sql.Scanner.

func (Namespace) String added in v0.2.0

func (n Namespace) String() string

String joins attribute values with ".".

func (Namespace) Validate added in v0.2.0

func (n Namespace) Validate() error

Validate checks names, values, uniqueness, and that n is non-empty.

func (Namespace) Value added in v0.2.0

func (n Namespace) Value() (driver.Value, error)

Value implements driver.Valuer (jsonb array of {name,value}).

type Object

type Object struct {
	ID          uuid.UUID
	Kind        string
	Title       string
	Summary     string
	Properties  map[string]any
	Content     string
	ContentType string
	ParentID    *uuid.UUID
	Position    *int
	// Embedding is optional dense vector for hybrid search fixtures / stores.
	Embedding []float32
	// Namespace is the ordered named isolation attrs stored on the row.
	Namespace Namespace
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time
}

Object is one row from the generic objects store (parent or part).

func ObjectFromEngram added in v0.2.0

func ObjectFromEngram(f EngramFile) Object

ObjectFromEngram maps a parsed file to an Object (no namespace / vfs_path).

func (Object) IsPart

func (o Object) IsPart() bool

IsPart reports whether the object has a parent containment link.

type ObjectKind

type ObjectKind struct {
	Kind             string
	Description      string
	IsPart           bool
	IsParent         bool
	FilterableFields json.RawMessage // JSON array from object_kinds.filterable_fields
}

ObjectKind documents a free-form kind for schema() discovery.

func ObjectKindFromSpec

func ObjectKindFromSpec(spec KindSpec) (ObjectKind, error)

ObjectKindFromSpec maps a typed kind into the durable ObjectKind row shape.

type ObjectKindInfo

type ObjectKindInfo struct {
	Kind             string          `json:"kind"`
	Description      string          `json:"description,omitempty"`
	IsPart           bool            `json:"is_part"`
	IsParent         bool            `json:"is_parent"`
	FilterableFields json.RawMessage `json:"filterable_fields,omitempty"`
}

ObjectKindInfo is the JSON form of ObjectKind for agents.

func KindInfoFromSpec

func KindInfoFromSpec(spec KindSpec) ObjectKindInfo

KindInfoFromSpec builds the agent-facing schema payload for one kind.

type ObjectLister added in v0.2.0

type ObjectLister interface {
	ListByKind(ctx context.Context, scope Scope, kind string, limit int) ([]Object, error)
	GetByProperty(ctx context.Context, scope Scope, key, value string) (Object, error)
	KindsWithObjects(ctx context.Context, scope Scope) ([]string, error)
}

ObjectLister lists first-class objects by kind and looks up a property value (used by the Engram Provider for ReadDir / path → id). Parts are omitted.

type ObjectReader

type ObjectReader interface {
	Get(ctx context.Context, scope Scope, id uuid.UUID) (Object, error)
	// GetMany returns objects for ids in the same order. Missing/out-of-scope ids are omitted.
	GetMany(ctx context.Context, scope Scope, ids []uuid.UUID) ([]Object, error)
	// ListChildren returns parts ordered by position.
	ListChildren(ctx context.Context, scope Scope, parentID uuid.UUID) ([]Object, error)
}

ObjectReader is the read port for knowledge objects.

type ObjectWriter

type ObjectWriter interface {
	Put(ctx context.Context, obj Object) error
	SoftDelete(ctx context.Context, scope Scope, id uuid.UUID) error
}

ObjectWriter persists knowledge objects (Engine.Put / SoftDelete). MemoryStore and postgres.Store implement it. Custom backends implement ObjectWriter for other deployments. Not required for read-only engines.

type PartSearcher

type PartSearcher interface {
	SearchLexical(ctx context.Context, scope Scope, query string, filters Filter, k int) ([]ScoredID, error)
	SearchVector(ctx context.Context, scope Scope, embedding []float32, filters Filter, k int) ([]ScoredID, error)
	SearchTrigram(ctx context.Context, scope Scope, query string, filters Filter, k int) ([]ScoredID, error)
}

PartSearcher is the candidate retrieval port for hybrid / exact search.

type PropFilter added in v0.2.0

type PropFilter struct {
	Eq any
	In []any
}

PropFilter is equality or match-any for one property.

type QueryEmbedder

type QueryEmbedder interface {
	Embed(ctx context.Context, text string) ([]float32, error)
}

QueryEmbedder embeds a query string for the dense search channel. When nil on the Engine, search runs lexical-only.

type Relation

type Relation struct {
	Type      string     `json:"type"`
	Direction string     `json:"direction,omitempty"` // out | in
	Depth     int        `json:"depth,omitempty"`     // hops from expand seed
	SourceID  *uuid.UUID `json:"source_id,omitempty"` // ExpandMany landing id
	EdgeMeta
}

Relation describes a non-containment hop used to reach a neighbor on expand. EdgeMeta fields are embedded so agent JSON stays flat (note, status, role, …).

func RelationFromNeighbor

func RelationFromNeighbor(n GraphNeighbor) Relation

RelationFromNeighbor maps a graph hop to the agent-facing Relation payload.

type Reranker

type Reranker interface {
	Rerank(ctx context.Context, objects []RichObject) ([]RichObject, error)
}

Reranker optionally reorders/filters hydrated rich objects after search or find_objects. Host-owned product scoring; default nil leaves engine ranking unchanged.

type ResultSet

type ResultSet struct {
	ID        uuid.UUID   `json:"id"`
	ObjectIDs []uuid.UUID `json:"object_ids"`
	// Relations carries expand hop metadata keyed by object id so continue
	// re-attaches relation fields on later pages (JSON keys are UUID strings).
	Relations map[uuid.UUID]Relation `json:"relations,omitempty"`
	Namespace Namespace              `json:"namespace,omitempty"`
	Offset    int                    `json:"offset"`
	CreatedAt time.Time              `json:"created_at"`
}

ResultSet is a ranked-list snapshot for deterministic continue() pagination.

type ResultSetStore

type ResultSetStore interface {
	Put(ctx context.Context, set ResultSet) error
	Get(ctx context.Context, id uuid.UUID) (ResultSet, error)
}

ResultSetStore holds ResultSet snapshots for continue(). SearchContext is the production implementation (single active set). Offset is advanced by Put of the same id with an updated Offset field.

type RichObject

type RichObject struct {
	ID          uuid.UUID      `json:"id"`
	Kind        string         `json:"kind"`
	Title       string         `json:"title,omitempty"`
	Summary     string         `json:"summary,omitempty"`
	Score       *float64       `json:"score,omitempty"`
	Properties  map[string]any `json:"properties,omitempty"`
	Content     string         `json:"content,omitempty"` // set by read; omitted on search hits
	ContentType string         `json:"content_type,omitempty"`
	ParentID    *uuid.UUID     `json:"parent_id,omitempty"`
	Position    *int           `json:"position,omitempty"`
	Evidence    []Evidence     `json:"evidence,omitempty"`
	// Relation is set on expand graph neighbors (how this object was reached).
	Relation  *Relation `json:"relation,omitempty"`
	CreatedAt time.Time `json:"created_at,omitempty"`
	UpdatedAt time.Time `json:"updated_at,omitempty"`
}

RichObject is the agent-facing object reference (never a bare id).

func RichFromObject

func RichFromObject(o Object, includeContent bool) RichObject

RichFromObject maps a stored object to a rich reference.

type SchemaResult

type SchemaResult struct {
	Kinds []ObjectKindInfo `json:"kinds"`
	// FilterUsage tells agents which tools accept filterable_fields and how.
	FilterUsage FilterUsage `json:"filter_usage"`
}

SchemaResult is the payload for the schema tool.

type Scope

type Scope struct {
	Namespace Namespace
}

Scope is optional retrieval isolation for Engine methods. Empty Namespace means no isolation. Non-empty applies application RLS (Namespace.Covers) so a broader scope sees objects with extra attrs.

type ScoredID

type ScoredID struct {
	ID         uuid.UUID
	Score      float64
	UpdatedAt  time.Time
	ParentID   *uuid.UUID
	Title      string
	Content    string
	Position   *int
	Properties map[string]any // part props (e.g. start_line) when the channel provides them
}

ScoredID is a candidate from a retrieval channel before fusion.

type SearchContext

type SearchContext struct {
	// contains filtered or unexported fields
}

SearchContext is the single retrieval session surface for one agent thread: host namespace isolation + the active ResultSet for continue.

func NewSearchContext

func NewSearchContext() *SearchContext

NewSearchContext returns an empty search context.

func (*SearchContext) ClearNamespace

func (c *SearchContext) ClearNamespace()

ClearNamespace clears retrieval isolation.

func (*SearchContext) Export

func (c *SearchContext) Export() ([]byte, error)

Export serializes namespace + active ResultSet for session checkpoints.

func (*SearchContext) Get

Get implements ResultSetStore.

func (*SearchContext) Namespace

func (c *SearchContext) Namespace() (Namespace, bool)

Namespace returns the host-set search namespace, if any.

func (*SearchContext) Put

func (c *SearchContext) Put(_ context.Context, set ResultSet) error

Put implements ResultSetStore: stores set as the sole active ResultSet.

func (*SearchContext) Restore

func (c *SearchContext) Restore(raw []byte) error

Restore loads a prior Export. Empty/nil clears the context.

func (*SearchContext) Scope

func (c *SearchContext) Scope() Scope

Scope returns the retrieval Scope for engine calls.

func (*SearchContext) SetNamespace

func (c *SearchContext) SetNamespace(ns Namespace)

SetNamespace sets host retrieval isolation.

type SearchPage

type SearchPage struct {
	ResultSetID uuid.UUID    `json:"result_set_id"`
	HasMore     bool         `json:"has_more"`
	Objects     []RichObject `json:"objects"`
}

SearchPage is one page of ranked rich objects plus ResultSet identity.

type SearchRequest

type SearchRequest struct {
	Query   string
	Filters Filter
	Limit   int
	// ScopeIDs, when non-empty, keeps only candidates whose id or parent_id is in the set.
	// Use after expand/find_objects to restrict corpus search to a deal-local neighborhood.
	ScopeIDs []uuid.UUID
}

SearchRequest is the engine input for search and find_exact.

type Store

type Store interface {
	ObjectReader
	KindReader
	PartSearcher
}

Store is the full read + search surface required by Engine.

type StringMatch added in v0.2.0

type StringMatch struct {
	Eq string
	In []string
}

StringMatch is equality or match-any for a well-known string field.

type WriteKinds

type WriteKinds struct {
	Discovery string // save_discovery
	Fact      string // save_fact
	Memory    string // save_memory
}

WriteKinds maps agent save_* tools to host kind names. Empty fields omit that tool. When the process catalog is non-empty, named kinds must already be registered (ApplyKinds / WithKinds).

Directories

Path Synopsis
Package helixgraph adapts HelixDB to brain.GraphReader / GraphWriter / searchers.
Package helixgraph adapts HelixDB to brain.GraphReader / GraphWriter / searchers.
Package postgres is the optional Postgres implementation of brain.Store.
Package postgres is the optional Postgres implementation of brain.Store.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL