atom

package
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package atom implements the MemoryAtom domain: atomic fact units extracted from decisions, knowledge items, and procedural memories. Atoms form a directed graph via memory_links, enabling graph traversal queries.

Index

Constants

View Source
const (
	// DigestStatusPending is the initial state written by AddAtom, before
	// the LLM atomizer has processed the atom.
	DigestStatusPending = "pending"
	// DigestStatusDone marks an atom whose digestion step (atomization or
	// consolidation) finished successfully.
	DigestStatusDone = "done"
	// DigestStatusFailed marks an atom whose digestion step errored;
	// error_msg carries the failure detail.
	DigestStatusFailed = "failed"
	// DigestStatusConsolidated marks an original atom that the daily
	// atom-consolidation cron (internal/scheduler/atom_consolidation.go)
	// merged into a condensed atom.
	DigestStatusConsolidated = "consolidated"
	// DigestStatusPromoted marks a consolidated atom that was promoted to a
	// pending knowledge proposal, either manually via the
	// promote_atom_to_knowledge MCP tool or automatically by the weekly
	// atom-bridge cron (internal/scheduler/atom_bridge.go).
	DigestStatusPromoted = "promoted"
)

Digest status enum — the single source of truth for the legal values of memory_atoms.digest_status. Both backend stores (Postgres: store.go; SQLite: internal/storage/sqlite/atom.go) validate every SetDigestStatus call against this enum before issuing the UPDATE, so nothing — including a prompt-injected MCP tool call carrying an arbitrary string — can write an unrecognised status into the column (.claude/rules/backend-security-design.md §2: adversarial input handling).

Values mirror the migration COMMENT on the column (migrations/000062_memory_atoms_promoted_status.up.sql): 'pending | done | failed | consolidated | promoted'. Do not re-declare these literals elsewhere — reference these constants instead (G6 decision 8f25c58d).

View Source
const (
	// PromotionMinContentRunes is the minimum atom content length, measured
	// in Unicode runes (not bytes, so CJK/emoji content is measured
	// correctly), required for promotion to a knowledge proposal.
	PromotionMinContentRunes = 80
	// PromotionMinTags is the minimum tag count required for promotion.
	PromotionMinTags = 2
)

Promotion eligibility gate — shared by the manual promote_atom_to_knowledge MCP tool (internal/mcp/tools_atom.go) and the weekly atom-bridge cron job (internal/scheduler/atom_bridge.go) so the two promotion paths can never silently diverge on quality-gate criteria (G6 decision 8f25c58d).

Variables

View Source
var ErrInvalidDigestStatus = errors.New("atom: invalid digest_status")

ErrInvalidDigestStatus is returned by SetDigestStatus when the caller supplies a status outside the five-value enum above.

View Source
var ErrNotFound = errors.New("atom: not found")

ErrNotFound is returned when a requested atom does not exist.

Functions

func IsValidDigestStatus

func IsValidDigestStatus(status string) bool

IsValidDigestStatus reports whether status is one of the five legal digest_status enum values. Both backend stores' SetDigestStatus call this before sending the UPDATE so an adversarial or buggy caller cannot write an arbitrary string into digest_status.

Types

type AddAtomParams

type AddAtomParams struct {
	WorkspaceID *uuid.UUID
	ParentTable string
	ParentID    uuid.UUID
	Content     string
	Keywords    []string
	Tags        []string
}

AddAtomParams holds parameters for creating a new atom.

type AddLinkParams

type AddLinkParams struct {
	FromAtomID uuid.UUID
	ToAtomID   uuid.UUID
	LinkType   string
	Confidence float64
}

AddLinkParams holds parameters for creating a directed link between two atoms.

type Atom

type Atom struct {
	ID           uuid.UUID  `json:"id"`
	WorkspaceID  *uuid.UUID `json:"workspace_id,omitempty"`
	ParentTable  string     `json:"parent_table"`
	ParentID     uuid.UUID  `json:"parent_id"`
	Content      string     `json:"content"`
	Keywords     []string   `json:"keywords"`
	Tags         []string   `json:"tags"`
	CreatedAt    time.Time  `json:"created_at"`
	DigestStatus *string    `json:"digest_status,omitempty"`
}

Atom is the domain model for an atomic fact unit.

type Link struct {
	FromAtomID uuid.UUID `json:"from_atom_id"`
	ToAtomID   uuid.UUID `json:"to_atom_id"`
	LinkType   string    `json:"link_type"` // same_entity|same_action|same_time|same_project
	Confidence float64   `json:"confidence"`
	CreatedAt  time.Time `json:"created_at"`
}

Link is a directed edge between two atoms.

type PromotionEligibility

type PromotionEligibility struct {
	ContentOK    bool
	ContentRunes int
	TagsOK       bool
	TagCount     int
}

PromotionEligibility reports the outcome of the promotion quality gate for a candidate atom's content and tags. Both sub-checks are exposed (rather than a single bool) so callers can surface a specific error message per failing condition, as promote_atom_to_knowledge does; callers that only need the combined verdict use Eligible().

func CheckPromotionEligibility

func CheckPromotionEligibility(content string, tags []string) PromotionEligibility

CheckPromotionEligibility evaluates content and tags against the shared promotion quality gate: content length >= PromotionMinContentRunes runes AND len(tags) >= PromotionMinTags.

func (PromotionEligibility) Eligible

func (e PromotionEligibility) Eligible() bool

Eligible reports whether both the content-length and tag-count gates passed.

type Store

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

Store is the Postgres-backed implementation of StoreIface.

func New

func New(pool *pgxpool.Pool, workspaceID *uuid.UUID) *Store

New returns a Store backed by the given pool, scoped to the optional workspaceID. nil workspaceID = legacy unscoped mode.

func (*Store) AddAtom

func (s *Store) AddAtom(ctx context.Context, p AddAtomParams) (*Atom, error)

AddAtom inserts a new atom and returns the persisted record.

func (s *Store) AddLink(ctx context.Context, p AddLinkParams) error

AddLink inserts a directed link. ON CONFLICT DO NOTHING so repeated calls are idempotent.

func (*Store) CountByDigestStatus

func (s *Store) CountByDigestStatus(ctx context.Context, workspaceID *uuid.UUID, status string) (int64, error)

CountByDigestStatus counts atoms with the given digest_status, optionally scoped to a workspace.

func (*Store) CountTotal

func (s *Store) CountTotal(ctx context.Context, workspaceID *uuid.UUID) (int64, error)

CountTotal returns the total number of atoms scoped to the given workspace.

func (*Store) ListByDigestStatus

func (s *Store) ListByDigestStatus(ctx context.Context, workspaceID *uuid.UUID, status string, limit int) ([]Atom, error)

ListByDigestStatus returns up to limit atoms with the given digest_status, ordered by created_at ASC. Mirrors the CountByDigestStatus query shape.

func (*Store) ListByParent

func (s *Store) ListByParent(ctx context.Context, parentTable string, parentID uuid.UUID) ([]Atom, error)

ListByParent returns all atoms for a given parent table + id.

func (*Store) PruneAtoms

func (s *Store) PruneAtoms(ctx context.Context, cutoff time.Time) (int64, error)

PruneAtoms hard-deletes memory_atoms rows older than cutoff. Called by the daily decay pruner to enforce the 90-day TTL. Link rows referencing pruned atoms are deleted first (no FK cascade per project red-line #9; referential integrity is enforced in code).

func (*Store) Search

func (s *Store) Search(ctx context.Context, workspaceID *uuid.UUID, query string, limit int) ([]Atom, error)

Search returns atoms whose content, keywords, or tags match query via ILIKE. Scoped to workspaceID when non-nil.

func (*Store) SetDigestStatus

func (s *Store) SetDigestStatus(ctx context.Context, atomID uuid.UUID, status string, errMsg string) error

SetDigestStatus updates the digest_status and optional error_msg for a single atom. status is validated against the five-value enum (digest_status.go) before the UPDATE is sent — an invalid value is rejected with ErrInvalidDigestStatus rather than silently written to the column (backend-security-design.md §2: adversarial input handling).

func (*Store) Traverse

func (s *Store) Traverse(ctx context.Context, startAtomID uuid.UUID, depth int) (*TraverseResult, error)

Traverse performs iterative BFS from startAtomID up to min(depth, 5) hops. Returns all visited atoms and the links that were followed. Total atoms returned is capped at maxTraverseAtoms (50).

type StoreIface

type StoreIface interface {
	// AddAtom inserts a new atom and returns the persisted record.
	AddAtom(ctx context.Context, p AddAtomParams) (*Atom, error)

	// AddLink inserts a directed link between two atoms.
	// If the (from_atom_id, to_atom_id, link_type) triple already exists the
	// call is a no-op (ON CONFLICT DO NOTHING).
	AddLink(ctx context.Context, p AddLinkParams) error

	// ListByParent returns all atoms whose parent_table and parent_id match.
	ListByParent(ctx context.Context, parentTable string, parentID uuid.UUID) ([]Atom, error)

	// Traverse does BFS from startAtomID up to depth hops (capped at 5),
	// returning all visited atoms and the links that connect them.
	// Total atoms returned is capped at 50.
	Traverse(ctx context.Context, startAtomID uuid.UUID, depth int) (*TraverseResult, error)

	// Search returns atoms whose content, keywords, or tags contain query
	// (ILIKE on Postgres, LIKE on SQLite). Scoped to workspaceID when non-nil.
	Search(ctx context.Context, workspaceID *uuid.UUID, query string, limit int) ([]Atom, error)

	// PruneAtoms hard-deletes memory_atoms rows older than cutoff.
	// Called daily by the decay.Pruner to enforce the 90-day TTL.
	PruneAtoms(ctx context.Context, cutoff time.Time) (int64, error)

	// SetDigestStatus updates the digest_status and error_msg for the given atom.
	// status must be one of the five DigestStatus* constants in
	// digest_status.go (Pending, Done, Failed, Consolidated, Promoted); both
	// backend implementations validate against IsValidDigestStatus before
	// issuing the UPDATE and return ErrInvalidDigestStatus for anything else.
	// errMsg is stored only when status=DigestStatusFailed; pass "" otherwise.
	SetDigestStatus(ctx context.Context, atomID uuid.UUID, status string, errMsg string) error

	// CountByDigestStatus returns the number of atoms with the given digest_status
	// in the given workspace (nil = all workspaces).
	CountByDigestStatus(ctx context.Context, workspaceID *uuid.UUID, status string) (int64, error)

	// ListByDigestStatus returns up to limit atoms with the given digest_status,
	// scoped to workspaceID (nil = all workspaces), ordered by created_at ASC.
	// Used by the atom-bridge weekly scheduler job to collect consolidated atoms
	// eligible for promotion to knowledge proposals.
	ListByDigestStatus(ctx context.Context, workspaceID *uuid.UUID, status string, limit int) ([]Atom, error)

	// CountTotal returns the total number of atoms scoped to the given workspace
	// (nil = all workspaces). Used by the M9 consolidation cron to compare
	// against the configured capacity threshold.
	CountTotal(ctx context.Context, workspaceID *uuid.UUID) (int64, error)
}

StoreIface is the backend-agnostic contract for the MemoryAtom bounded context. Postgres-backed *Store and SQLite-backed *AtomStore both satisfy this interface.

type TraverseResult

type TraverseResult struct {
	Atoms []Atom `json:"atoms"`
	Links []Link `json:"links"`
}

TraverseResult contains atoms and links visited during a BFS traversal.

Jump to

Keyboard shortcuts

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