index

package
v0.4.5 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package index is the rebuildable cache.

Nothing here is authoritative. Delete .logos/index.db, run `logos index`, and you are back to identical state derived entirely from the markdown.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Hit

type Hit struct {
	Slug, Title, Kind, Body string
	Score                   float64
	// FirstSeen is the note's date from its frontmatter, unix seconds, or zero
	// when it has none. Carried on the hit rather than looked up later because a
	// caller filtering "what did I do last month" needs it for every candidate,
	// and a per-hit query to answer that would be the retrieval path's slowest
	// step for the sake of one integer already sitting in the row.
	FirstSeen int64
	// Via is set when the note was pulled in as a graph neighbour rather than
	// matched directly, so the UI can show why it is in context.
	Via string
}

Hit is one retrieved note.

type Index

type Index struct {
	Vault string
	DB    *sql.DB
}

func Open

func Open(vaultDir string) (*Index, error)

func (*Index) Ask

func (ix *Index) Ask(p *provider.Provider, embedModel, chatModel, question string, k, budget int) (string, []Hit, error)

Ask is retrieval plus generation. Context is capped by character budget rather than token count so this stays honest on a 4k-context local model.

func (*Index) Close

func (ix *Index) Close() error

func (*Index) EdgeCount

func (ix *Index) EdgeCount() (int, error)

func (*Index) EmbedPending

func (ix *Index) EmbedPending(p *provider.Provider, model string, batch int) (int, error)

EmbedPending embeds every note that lacks a vector, in batches — a round trip per note makes a 2000-note vault take minutes instead of seconds.

func (*Index) Expand

func (ix *Index) Expand(hits []Hit, minConf float64, limit int) ([]Hit, error)

Expand pulls in notes linked from the top hits. This is the payoff of keeping a graph at all: asking about a project surfaces the people on it even when their notes share no vocabulary with the question.

func (*Index) HitBySlug

func (ix *Index) HitBySlug(slug string) (Hit, bool)

func (*Index) HybridSearch

func (ix *Index) HybridSearch(p *provider.Provider, model, query string, k int) ([]Hit, error)

HybridSearch fuses vector and lexical rankings with reciprocal rank fusion.

RRF scores each result by 1/(rank+k) summed across both lists, which needs no score normalisation between two incomparable scales (cosine distance vs bm25) — it only trusts the ordering each method is confident about. k=60 is the value from the original RRF paper and is not sensitive.

func (*Index) LexicalSearch

func (ix *Index) LexicalSearch(query string, k int) ([]Hit, error)

LexicalSearch is the FTS arm on its own, as full Hits. It is the fallback for a machine with no embedding model: worse than hybrid, but it needs no runtime and no vectors, so retrieval still works on a fresh checkout.

func (*Index) NoteCount

func (ix *Index) NoteCount() (int, error)

func (*Index) Search

func (ix *Index) Search(p *provider.Provider, model, query string, k int) ([]Hit, error)

func (*Index) Sync

func (ix *Index) Sync() (SyncReport, error)

Sync reads every note in the vault and reconciles it against the cache. Only notes whose content hash changed are re-parsed and marked for re-embedding.

func (*Index) SyncInsights

func (ix *Index) SyncInsights() (int, error)

SyncInsights restores dreamed insights from the vault.

Must run after SyncMemories: an insight cites the two memory ids it bridges, and `logos dream review` renders those endpoints, so the memories have to be back before the proposal about them can be read.

Returns how many insights it put back.

func (*Index) SyncLog

func (ix *Index) SyncLog() (int, error)

SyncLog restores the memory timeline from the vault.

Must run after SyncMemories and SyncPending, for the same reason they run in that order: an event is about a memory, and the memory has to be back before the history of it means anything.

Returns how many events it put back, counting the ones it synthesised for memories that predate the file.

func (*Index) SyncLoops

func (ix *Index) SyncLoops() (int, error)

SyncLoops restores open loops from the vault.

The fifth thing that only the database knew, and the one with no excuse left: `logos loop add` wrote a commitment into commitments and nowhere else, so the documented-safe rebuild emptied the list, and the list coming back empty is indistinguishable from having finished everything on it.

Returns how many loops it put back.

func (*Index) SyncMemories

func (ix *Index) SyncMemories(p *provider.Provider, embedModel string) (int, error)

SyncMemories reconciles the memory store against its markdown in the vault.

The mirror of Sync, for the other half of what the system knows. Notes are rebuilt from files on every index; memories were not, which made "delete the database and reindex" true for one half and quietly destructive for the other. Running both from one command is what makes the guarantee whole.

Returns how many memories the vault held.

func (*Index) SyncNotes

func (ix *Index) SyncNotes() (int, error)

SyncNotes restores working notes the vault holds and the index does not.

The third half of the same guarantee. Checkpoints were always safe because they are read from markdown; memories became safe when Import landed; notes were the last thing that existed only in the database, so `rm -rf .logos` silently threw away exactly the in-flight work note_progress exists to keep.

Returns how many it restored.

func (*Index) SyncPending

func (ix *Index) SyncPending() (restored, rescued int, err error)

SyncPending restores the memory review queue from the vault.

The fourth thing that only the database knew. A memory an agent proposed sits in quarantine until a person accepts it, and quarantine's whole point is that it is *not* written into memories/<kind>.md — so the queue lived in .logos/index.db alone, and the documented-safe rebuild threw away proposals nobody had reviewed yet, with `logos doctor` afterwards reporting "nothing pending" as though they had been.

Must run after SyncMemories: a proposal accepted since the last flush is an active memory now, and Import has to have restored it before the queue is allowed to have an opinion about that id.

Returns how many proposals it put back, and how many it rescued out of a cache that was their only copy.

type SyncReport

type SyncReport struct {
	Added, Updated, Removed, Unchanged int
	// Skipped counts files the walk found but did not index: symlinks, and
	// files that could not be read. They are reported rather than silently
	// dropped, because "the index is missing a note" is otherwise invisible.
	Skipped int
}

Jump to

Keyboard shortcuts

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