Documentation
¶
Index ¶
- func Decrypt(key, data, noteID []byte) ([]byte, error)
- func Encrypt(key, plaintext, noteID []byte) ([]byte, error)
- func MaskSensitive(notes []*model.Note) []*model.Note
- type AddOptions
- type ClassifyOptions
- type Container
- type KeyManager
- type NoteService
- func (s *NoteService) Add(ctx context.Context, content string, opts AddOptions) (*model.Note, error)
- func (s *NoteService) Delete(ctx context.Context, id string) error
- func (s *NoteService) Get(ctx context.Context, id string) (*model.Note, error)
- func (s *NoteService) List(ctx context.Context, filters db.Filters, limit, offset int) ([]*model.Note, error)
- func (s *NoteService) ScrubSensitiveSummaries(ctx context.Context) (int, error)
- type SearchOptions
- type SearchResult
- type SearchService
- type TaggerService
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Decrypt ¶
Decrypt decrypts data produced by Encrypt. Returns an error if the auth tag fails — data has been tampered with.
Types ¶
type AddOptions ¶
type AddOptions struct {
ClassifyOptions
DefaultSensitive bool // from config — used when IsSensitive is not explicitly set
}
AddOptions carries user-supplied options for adding a note.
type ClassifyOptions ¶
type ClassifyOptions struct {
Category string // explicit category; empty = auto-detect
Tags []string // explicit tags; nil = auto-detect
IsSensitive *bool // explicit sensitivity; nil = auto-detect
}
ClassifyOptions carries optional user-supplied overrides.
type Container ¶
type Container struct {
Notes *NoteService
Search *SearchService
DB db.Adapter
}
Container holds all initialised services and adapters.
type KeyManager ¶
type KeyManager struct {
// contains filtered or unexported fields
}
KeyManager handles master secret storage and encryption key derivation. The derived key is never stored — it is rederived per process.
func NewKeyManager ¶
func NewKeyManager(configDir string) (*KeyManager, error)
NewKeyManager initialises the key manager, generating a master secret and salt on first run if they don't exist.
func (*KeyManager) DeriveKey ¶
func (km *KeyManager) DeriveKey() ([]byte, error)
DeriveKey derives a 32-byte AES key from the master secret and salt.
type NoteService ¶
type NoteService struct {
// contains filtered or unexported fields
}
NoteService orchestrates saving, fetching, and deleting notes. It coordinates the DB adapter, embedding adapter, tagger, and encryption.
func NewNoteService ¶
func NewNoteService(dbAdapter db.Adapter, embAdapter embedding.Adapter, tagger *TaggerService, keyMgr *KeyManager) *NoteService
NewNoteService creates a NoteService with all required dependencies.
func (*NoteService) Add ¶
func (s *NoteService) Add(ctx context.Context, content string, opts AddOptions) (*model.Note, error)
Add classifies, embeds, encrypts (if sensitive), and persists a note.
func (*NoteService) Delete ¶
func (s *NoteService) Delete(ctx context.Context, id string) error
Delete removes a note by ID.
func (*NoteService) List ¶
func (s *NoteService) List(ctx context.Context, filters db.Filters, limit, offset int) ([]*model.Note, error)
List returns notes matching the given filters.
func (*NoteService) ScrubSensitiveSummaries ¶
func (s *NoteService) ScrubSensitiveSummaries(ctx context.Context) (int, error)
ScrubSensitiveSummaries validates summaries of sensitive notes saved before summaries were checked (#53) and replaces the ones that leak content. Each note is checked once; the database records it. Returns how many summaries were replaced.
type SearchOptions ¶
type SearchOptions struct {
TopK int
Category string
Tags []string
// IsSensitive optionally restricts results by the sensitive flag.
// nil = no filter (default); pointer to false = exclude sensitive
// notes from results before they reach the LLM. Used by the MCP
// server to prevent sensitive notes leaking to the calling agent.
IsSensitive *bool
// MaxDistance is the L2-distance ceiling for keeping a candidate note.
//
// = 0 → use the service default (typically 1.0)
// > 0 → keep notes with Distance <= MaxDistance
// < 0 → disable filtering entirely (return whatever the DB returned)
//
// The "= 0 means default" overload means an *exact* 0 threshold cannot be
// expressed via this field. In practice this is fine: with L2-normalised
// embeddings, bit-exact distance 0 implies bit-identical content, which is
// not a useful retrieval target.
MaxDistance float32
// OnStep is an optional progress hook invoked at the start of each
// pipeline phase ("embedding", "searching", "answering"). Used by the
// CLI to update a spinner label. Must be cheap and non-blocking.
OnStep func(step string)
}
SearchOptions carries optional filters for a search query.
type SearchResult ¶
SearchResult holds both the LLM-generated answer and the raw notes used as context.
type SearchService ¶
type SearchService struct {
// contains filtered or unexported fields
}
SearchService implements the RAG pipeline for natural language queries. All external concerns are pluggable via adapters — Voyage/Ollama for embeddings, Claude/Ollama for the LLM, SQLite/(future)Postgres for storage.
Flow:
- Embed the user query (embedding adapter)
- Vector similarity search → top-K notes (DB adapter)
- Drop notes beyond the relevance threshold
- Decrypt sensitive notes in memory
- Inject remaining notes as context → answer (LLM adapter)
func NewSearchService ¶
func NewSearchService(dbAdapter db.Adapter, embAdapter embedding.Adapter, llmAdapter llm.Adapter, keyMgr *KeyManager, maxDistance float32, topK int) *SearchService
NewSearchService creates a SearchService with all required dependencies. maxDistance and topK supply service-level defaults; pass 0 to use built-ins.
func (*SearchService) Retrieve ¶
func (s *SearchService) Retrieve(ctx context.Context, query string, opts SearchOptions) ([]*model.Note, error)
Retrieve runs the embed → vector search → threshold filter → decrypt pipeline and returns the candidate notes. No LLM call.
Used by the MCP tool surface: the calling agent (Claude Code, Cursor) is itself an LLM and prefers to reason over raw candidates rather than a pre-generated answer from inode's local model.
func (*SearchService) Search ¶
func (s *SearchService) Search(ctx context.Context, query string, opts SearchOptions) (*SearchResult, error)
Search embeds the query, retrieves top-K notes, decrypts them, and returns an LLM-generated answer alongside the source notes.
type TaggerService ¶
type TaggerService struct {
// contains filtered or unexported fields
}
TaggerService classifies notes into categories and tags. When the user provides values explicitly, they are passed through (with normalisation). Otherwise the LLM adapter is called for auto-detection.
func NewTaggerService ¶
func NewTaggerService(llmAdapter llm.Adapter) *TaggerService
NewTaggerService creates a TaggerService backed by the given LLM adapter.
func (*TaggerService) Classify ¶
func (t *TaggerService) Classify(ctx context.Context, content string, opts ClassifyOptions) (llm.ClassifyResult, error)
Classify returns the final classification for a note. User-supplied values take precedence; the LLM fills in anything missing.