native

package
v0.7.3 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: MIT Imports: 27 Imported by: 0

Documentation

Overview

Package native holds the Go-side implementations of Ogham tools for the absorption path described in docs/plans/2026-04-16-go-cli-enterprise.md. A subcommand is "native" when it bypasses the Python sidecar and reads/ writes the database directly via pgx.

The default path for every subcommand is still the sidecar. Native is opt-in via --native until each tool has been dogfooded enough.

Index

Constants

View Source
const (
	AdvanceDefaultDwellHours           = 1.0
	AdvanceDefaultSurpriseGate         = 0.3
	AdvanceDefaultImportanceGate       = 0.5
	AdvanceDefaultEditingWindowMinutes = 30
)

AdvanceLifecycleDefaults match Python's lifecycle.py constants.

View Source
const (
	LintDefaultSampleSize         = 10
	LintDefaultStableDays         = 90
	LintDefaultOrphanGraceMinutes = 5
)

LintDefaults mirror Python's wiki_lint module-level defaults.

View Source
const (
	StatusOK        = "ok"
	StatusNotCached = "not_cached"
)

QueryTopicSummaryStatus enumerates the response shapes.

View Source
const DecayThreshold = 0.25

DecayThreshold is the confidence floor below which a memory is considered "decayed" for the DecayCount stat. 0.25 sits well below the schema default of 0.5 and is empirically near-invisible in hybrid_search ranking -- memories that reach it are candidates for cleanup or reinforcement.

Variables

View Source
var ValidRelationshipTypes = []string{
	"supports", "contradicts", "supersedes", "refines", "references",
}

Relationship types the schema accepts. Matches the PostgreSQL `relationship_type` enum defined in schema_postgres.sql. Kept as a sorted slice so clients can discover the valid set.

Functions

func ActiveProfile added in v0.7.0

func ActiveProfile(cfg *Config) string

ActiveProfile returns the profile to use for tool calls. Precedence, highest first:

  1. $OGHAM_PROFILE env var
  2. ~/.ogham/active_profile sentinel file
  3. cfg.Profile (loaded from TOML / applyEnv)
  4. "default"

A cfg of nil is tolerated for callers that only have a HOME-scoped view (the CLI `ogham profile current` command, for example, doesn't need the full config to answer the question).

func ClearActiveProfile added in v0.7.0

func ClearActiveProfile() error

ClearActiveProfile deletes the sentinel file. Subsequent ActiveProfile calls fall through to cfg.Profile (the TOML baseline). Missing-file is a no-op (not an error) so callers can treat it as idempotent.

func CountDecayEligible

func CountDecayEligible(ctx context.Context, cfg *Config, profile string) (int, error)

CountDecayEligible returns the number of memories that would be affected by a decay pass. Mirrors Python's Hebbian-decay predicate.

func CountExpired

func CountExpired(ctx context.Context, cfg *Config, profile string) (int, error)

CountExpired is a dry-run count of expired memories in a profile.

func CreateRelationship added in v0.7.0

func CreateRelationship(ctx context.Context, cfg *Config, opts CreateRelationshipOptions) error

CreateRelationship inserts a single edge into memory_relationships. Used by store_decision.related_memories to materialise the supporting links after the new decision is stored. Idempotent on the unique key (source_id, target_id, relationship) -- repeat calls return the existing edge rather than erroring.

func DecayFactor added in v0.7.0

func DecayFactor(ageDays, lambda, beta float64) float64

DecayFactor returns Shodh's hybrid decay multiplier for a memory of given age. Pure function -- no I/O.

0-3 days: exponential exp(-lambda * age)
3+ days:  power-law (age/3)^(-beta)

Mirrors Python's src/ogham/lifecycle.py::hybrid_decay_factor for cross-stack parity.

func DefaultPath

func DefaultPath() string

DefaultPath returns the standard config location. Same file as the sidecar-mode config -- just reads different sections.

func DeriveSidecarExtras

func DeriveSidecarExtras(cfg *Config) string

DeriveSidecarExtras computes the correct `uv tool run --from ogham-mcp[...]` extras spec from a config. Combines the backend extra (postgres for the direct-DB Python backend; nothing for the Supabase PostgREST backend which is the base install) with the embedding provider extra (gemini, voyage, mistral -- openai and ollama are in the base).

Returns a comma-separated string ready to be placed inside the [...] brackets of a ogham-mcp install spec, or "" if no extras are needed.

func Inscribe added in v0.7.3

func Inscribe(ctx context.Context, cfg *Config, sessionID, cwd string, opts HookOptions) (string, error)

Inscribe drains session context to Ogham before compaction.

Mirrors Python ogham.hooks.pre_compact: build a short plaintext summary identifying the session and store it with tags marking it as a compaction drain. Returns the content that was stored (or that would have been stored when DryRun is true) so the caller can echo it for verification.

Inscribe is best-effort: a store failure returns the content + a wrapped error, so the caller can log without breaking the PreCompact hook flow that triggered it.

func LoadEnvFiles

func LoadEnvFiles() []string

LoadEnvFiles returns env-var assignments (KEY=VALUE) drawn from the same files Python ogham reads, in the same precedence order. Higher-priority entries appear later in the slice so callers that do

cmd.Env = append(os.Environ(), LoadEnvFiles()...)

end up with Python-equivalent precedence (later wins under Go's exec).

Order, lowest to highest:

  1. ~/.ogham/config.env (global fallback)
  2. ./.env (project-local, overrides global)

func OverallScore added in v0.7.3

func OverallScore(dims []DimensionResult) float64

OverallScore is the mean of dimension scores, rounded to one decimal. Empty slice yields 0.0 -- mirrors Python's overall_score behaviour.

func PipelineCounts added in v0.7.0

func PipelineCounts(ctx context.Context, cfg *Config, profile string) (map[string]int64, error)

PipelineCounts returns the {stage: count} distribution for the dashboard Lifecycle card. Read-only -- does not advance anything.

Mixed-version safe: if the memory_lifecycle table is absent (pre-026 DB), returns all rows under 'fresh' without error.

func Recall added in v0.7.3

func Recall(ctx context.Context, cfg *Config, cwd string, opts HookOptions) (string, error)

Recall returns markdown context to restore after compaction.

Mirrors Python ogham.hooks.post_compact: hybrid_search using a "recent work and decisions" query, limit 10, longer content truncation (300 vs 200) than SessionStart since post-compact users often need more detail to rebuild context. Same best-effort pattern as SessionStart -- never propagate search failures.

func Save

func Save(path string, cfg *Config) error

Save writes cfg to path as TOML with 0600 perms (API keys live here). Creates parent directories as needed. Existing keys not known to native.Config are preserved by reading the file first, merging on top of the parsed structure, and re-emitting; this avoids clobbering fields like api_key + gateway_url that the sidecar-mode loader owns.

func SaveEnvFile

func SaveEnvFile(path string, cfg *Config) error

SaveEnvFile writes an env-file (KEY=VALUE, one per line) mirror of the TOML config's Python-relevant variables. Python ogham reads this file either directly (its config loader checks ~/.ogham/config.env) or via shell sourcing. Keeping it in sync means Python + Go agree on config without either having to parse the other's format.

func SentinelPath added in v0.7.0

func SentinelPath() string

SentinelPath returns ~/.ogham/active_profile. Exposed so tests can override the HOME env to isolate the sentinel from the user's real profile without polluting it.

func SessionStart added in v0.7.3

func SessionStart(ctx context.Context, cfg *Config, cwd string, opts HookOptions) (string, error)

SessionStart returns markdown context to inject at session start.

Mirrors Python ogham.hooks.session_start: hybrid_search using the project name as the query, format the top results as a markdown bullet list under a "## Session Context" heading. Returns empty string when no results so the caller can treat that as "no context" without an error.

Best-effort by design: a search failure returns ("", nil) rather than propagating the error. Claude Code's SessionStart hook should never block the editor on an Ogham outage.

func SwitchProfile added in v0.7.0

func SwitchProfile(profile string) error

SwitchProfile writes profile to the sentinel file atomically (temp file + rename) so a crash mid-write cannot leave a half-written or empty sentinel for the next read.

Refuses empty or whitespace-only names -- the caller should use ClearActiveProfile() to explicitly fall back to the TOML baseline.

Types

type AdvanceLifecycleOptions added in v0.7.1

type AdvanceLifecycleOptions struct {
	DwellHours           float64
	SurpriseGate         float64
	ImportanceGate       float64
	EditingWindowMinutes int
}

AdvanceLifecycleOptions tunes the gates. Zero values pick the Python-matching defaults.

type AuditEvent

type AuditEvent struct {
	EventTime time.Time `json:"event_time"`
	Profile   string    `json:"profile"`
	Operation string    `json:"operation"`
	MemoryID  *string   `json:"memory_id,omitempty"`
	Details   any       `json:"details,omitempty"`
}

AuditEvent mirrors a row from the audit_log table (projected to the columns the CLI displays).

func Audit

func Audit(ctx context.Context, cfg *Config, profile, operation string, limit int) ([]AuditEvent, error)

Audit returns the most recent audit events for a profile.

func AuditEntries added in v0.7.0

func AuditEntries(ctx context.Context, cfg *Config, profile, operation string, before time.Time, limit int) ([]AuditEvent, error)

AuditEntries is the paginated variant used by the dashboard's Audit view. Adds a `before` cursor so HTMX infinite scroll can request the next page by passing the oldest-visible event_time back. All other semantics match Audit: profile scope, optional operation filter, event_time DESC ordering.

Passing a zero time for before is equivalent to Audit(limit).

type AutoLink struct {
	ID         string  `json:"id"`
	Similarity float64 `json:"similarity"`
	Content    string  `json:"content,omitempty"`
}

AutoLink is a prospective link candidate surfaced at store time. v0.5 preview does not write the memory_links row; that lands in a follow-up commit so the orchestrator + extraction + surprise path can ship independently.

type Breakdown

type Breakdown struct {
	Name  string `json:"name"`
	Count int64  `json:"count"`
}

type CheckResult

type CheckResult struct {
	Name     string        `json:"name"`
	OK       bool          `json:"ok"`
	Duration time.Duration `json:"duration_ns"`
	Detail   string        `json:"detail,omitempty"`
	Error    string        `json:"error,omitempty"`
}

CheckResult captures the outcome of a single parallel probe. Fields are named so JSON output is self-describing.

type CleanupResult

type CleanupResult struct {
	Profile     string `json:"profile"`
	ExpiredSeen int    `json:"expired_seen"`
	Deleted     int    `json:"deleted"`
}

func Cleanup

func Cleanup(ctx context.Context, cfg *Config, profile string) (*CleanupResult, error)

Cleanup deletes expired memories in a profile via cleanup_expired_memories RPC.

type ConfidenceResult added in v0.7.0

type ConfidenceResult struct {
	ID         string  `json:"id"`
	Profile    string  `json:"profile"`
	Confidence float64 `json:"confidence"`
}

ConfidenceResult carries the post-update confidence score so callers can surface the new value to the user. Mirrors the Python tool shape -- reinforce/contradict both return the same payload, only the "status" label differs.

func UpdateConfidence added in v0.7.0

func UpdateConfidence(ctx context.Context, cfg *Config, id string, signal float64, profile string) (*ConfidenceResult, error)

UpdateConfidence applies a signal to an existing memory's confidence via the database's update_confidence function. Both reinforce_memory (strength 0.5-1.0) and contradict_memory (strength 0.0-0.5) route through here -- the SQL function handles the math (EMA-style blend of the existing confidence with the new signal).

The strength parameter is validated at the MCP handler layer so we don't reject legitimate migration / backfill calls from direct Go callers that may want to force-set a value.

type Config

type Config struct {
	Database  Database  `toml:"database"`
	Embedding Embedding `toml:"embedding"`
	Profile   string    `toml:"profile"`
}

Config is the native-mode view of ~/.ogham/config.toml. It deliberately does not re-declare fields from internal/config.Config -- sidecar-mode commands still go through that loader. Native-mode adds the extra keys a Go tool needs to talk to Postgres and an embedding provider directly.

func Load

func Load(path string) (*Config, error)

Load reads TOML then layers env vars on top. Before reading env vars it auto-loads any dotenv files found at the standard locations (~/.ogham/config.env and ./.env) -- same search order Python uses, same behaviour the sidecar path already has via connectSidecar. A user whose Python sidecar works today will have a working native path without any extra configuration.

Env precedence (lowest to highest): process env, ~/.ogham/config.env, project ./.env, then TOML overrides.

func (*Config) ResolveBackend

func (c *Config) ResolveBackend() (string, error)

ResolveBackend picks the backend with this precedence:

  1. explicit cfg.Database.Backend if set
  2. SupabaseURL populated => supabase
  3. URL populated => postgres
  4. error asking the user to configure one

func (*Config) SidecarEnv

func (c *Config) SidecarEnv() []string

SidecarEnv returns the env vars a spawned Python sidecar needs. Lets the Go CLI treat TOML as canonical and push values into the subprocess environment so Python sees them as it always has.

type ConnectionSuggestion added in v0.7.0

type ConnectionSuggestion struct {
	ID             string    `json:"id"`
	Content        string    `json:"content"`
	SharedCount    int       `json:"shared_count"`
	SharedEntities []string  `json:"shared_entities"`
	CreatedAt      time.Time `json:"created_at"`
	Tags           []string  `json:"tags,omitempty"`
}

ConnectionSuggestion is a memory that shares entities with a target but has no explicit relationship edge. Surfaces "hidden" connections through the entity graph.

func SuggestConnections added in v0.7.0

func SuggestConnections(ctx context.Context, cfg *Config, memoryID string, minShared, limit int) ([]ConnectionSuggestion, error)

SuggestConnections finds memories that share at least min_shared entities with memory_id but have no explicit relationship to it yet. Python-parity inline SQL: joins memory_entities against a target's entity set and excludes anything already in memory_relationships.

type CreateRelationshipOptions added in v0.7.0

type CreateRelationshipOptions struct {
	SourceID     string
	TargetID     string
	Relationship string  // one of ValidRelationshipTypes
	Strength     float64 // default 1.0
	CreatedBy    string  // default "user"
	Metadata     map[string]any
}

CreateRelationshipOptions captures one edge creation. strength gets clamped to [0, 1]; createdBy defaults to "user" for tool-driven writes (auto-linker uses "auto" directly).

type Database

type Database struct {
	// Backend is "postgres" (pgx direct) or "supabase" (PostgREST).
	// Auto-detected when empty: SUPABASE_URL => supabase, DATABASE_URL => postgres.
	Backend string `toml:"backend"`

	// URL is the Postgres connection string when Backend == "postgres".
	URL string `toml:"url"`

	// SupabaseURL is the project base URL (https://xxx.supabase.co) when
	// Backend == "supabase". REST endpoint derives as {URL}/rest/v1.
	SupabaseURL string `toml:"supabase_url"`
	SupabaseKey string `toml:"supabase_key"`
}

type DayCount added in v0.7.0

type DayCount struct {
	Day   time.Time `json:"day"`
	Count int64     `json:"count"`
}

DayCount is a single cell in the Calendar heatmap: "on this UTC day, the active profile stored N memories." Day is always UTC-normalised to midnight so the dashboard renderer doesn't have to worry about server-local-tz drift.

func StoreCountsByDay added in v0.7.0

func StoreCountsByDay(ctx context.Context, cfg *Config, days int) ([]DayCount, error)

StoreCountsByDay returns per-day memory counts for the active profile covering the trailing `days` calendar days (inclusive of today). Zero or missing days are NOT filled in -- the Calendar renderer walks a complete 365-day grid and overlays the returned counts via a map lookup, defaulting missing days to zero.

days <= 0 is treated as 365 (the Calendar heatmap default).

type DecayResult

type DecayResult struct {
	Profile  string `json:"profile"`
	Decayed  int    `json:"decayed"`
	DryRun   bool   `json:"dry_run"`
	Eligible int    `json:"eligible"`
}

func Decay

func Decay(ctx context.Context, cfg *Config, profile string, batchSize int, dryRun bool) (*DecayResult, error)

Decay applies Hebbian decay for a profile. When dryRun is true, only counts.

type DeleteResult

type DeleteResult struct {
	ID      string `json:"id"`
	Profile string `json:"profile"`
}

DeleteResult is returned by Delete on success.

func Delete

func Delete(ctx context.Context, cfg *Config, id, profile string) (*DeleteResult, error)

type DimensionResult added in v0.7.3

type DimensionResult struct {
	Name   string  `json:"name"`
	Score  float64 `json:"score"`
	Zone   Zone    `json:"zone"`
	Detail string  `json:"detail"`
}

DimensionResult is one row of the extended health report. Mirrors Python ogham.health_dimensions.DimensionResult so the JSON wire format is identical between Python sidecar and Go native paths.

func ComputeCorpusSize added in v0.7.3

func ComputeCorpusSize(ctx context.Context, cfg *Config, profile string) DimensionResult

ComputeCorpusSize scores the profile's memory count. Scoring:

count >= 100   => 10.0                 (GREEN)
count 10-99    => 5.0 -> 7.99 (linear) (AMBER)
count 1-9      => 0.x -> 4.99 (linear) (RED)
count == 0     => 0.0                  (RED, "empty profile")

Uses GetStats for both backends -- already battle-tested across Supabase / Postgres in the rest of the CLI.

func ComputeDBFreshness added in v0.7.3

func ComputeDBFreshness(ctx context.Context, cfg *Config, profile string) DimensionResult

ComputeDBFreshness scores how recently the given profile wrote a memory. The scoring curve matches Python ogham.health_dimensions:

age <= 24h   => 10.0           (GREEN)
24h-72h      => 7.99 -> 5.0    (AMBER, linear)
72h-30d      => 4.99 -> 0.0    (RED, linear; capped at 30d excess)
no rows      => 0.0            (RED -- "dead writer")

A query error surfaces as RED with the error in Detail.

func ComputeE2EProbe added in v0.7.3

func ComputeE2EProbe(ctx context.Context, cfg *Config, profile string) DimensionResult

ComputeE2EProbe scores a synthetic round-trip against the live store. Writes a single memory with a unique tag, searches for it, then deletes it. Any failure -> RED 0.0. Success -> GREEN 10.0 with the total wall-clock duration in Detail.

Uses native.Store + native.Search + native.Delete -- no new SQL. Cleanup runs in a defer so a failed search still removes the row.

type Embedder

type Embedder interface {
	// Embed returns the embedding vector for text. Length must equal the
	// dimension the Embedder was configured with.
	Embed(ctx context.Context, text string) ([]float32, error)

	// Name returns a short identifier for error/log messages.
	Name() string

	// Dimension returns the output vector length. Callers that need to
	// assert schema compatibility (vector(512) etc.) can check here.
	Dimension() int
}

Embedder produces a fixed-dimension embedding vector for a single text. All providers in the absorption path implement this same contract so the rest of the code doesn't care which provider is configured.

func NewEmbedder

func NewEmbedder(cfg *Config) (Embedder, error)

NewEmbedder constructs an Embedder from a native.Config. Providers are added as they are absorbed; Gemini is the first, matching the user's current .env configuration. Returns a clear error on unknown providers rather than silently falling back to a default.

type Embedding

type Embedding struct {
	Provider  string `toml:"provider"`
	APIKey    string `toml:"api_key"`
	Model     string `toml:"model"`
	Dimension int    `toml:"dimension"`

	// BaseURL lets providers that can be self-hosted (Ollama today;
	// OpenAI via Azure / LocalAI proxies in v0.5+) point at a custom
	// endpoint instead of the provider default. Empty string means
	// "use provider default". Populated from OLLAMA_URL today; v0.5
	// embedders will add OPENAI_BASE_URL / MISTRAL_BASE_URL as they land.
	BaseURL string `toml:"base_url"`
}

type ExploreOptions added in v0.7.0

type ExploreOptions struct {
	Depth       int      // default 1
	MinStrength float64  // default 0.5
	Limit       int      // default 5
	Tags        []string // filter seed results
	Source      string   // filter seed results
	Profile     string
}

ExploreOptions configures the graph-walk seed + traversal.

type ExtendedHealthReport added in v0.7.3

type ExtendedHealthReport struct {
	Profile          string            `json:"profile"`
	OverallScore     float64           `json:"overall_score"`
	OverallZone      Zone              `json:"overall_zone"`
	Dimensions       []DimensionResult `json:"dimensions"`
	PortedDimensions int               `json:"ported_dimensions"`
	TotalDimensions  int               `json:"total_dimensions"`
	DeferredNotice   string            `json:"deferred_notice,omitempty"`
	DurationMs       float64           `json:"duration_ms"`
}

ExtendedHealthReport is the JSON payload `ogham health --extended` emits. Mirrors the shape Python's compose_health produces, with the caveat that this Path-B batch ships only 3 of the 8 dimensions. PortedDimensions / TotalDimensions make the partial state explicit so users (and dashboards) don't read this as a stable 8-row format until the follow-up session lands.

func ComposeExtendedHealth added in v0.7.3

func ComposeExtendedHealth(ctx context.Context, cfg *Config, profile string) ExtendedHealthReport

ComposeExtendedHealth runs every dimension in this batch and returns a single report. Each dimension is wrapped in a recover so one panicking probe doesn't take the whole report down -- matches the Python exception-catching pattern in compose_health.

type FindRelatedOptions added in v0.7.0

type FindRelatedOptions struct {
	Depth             int
	MinStrength       float64
	RelationshipTypes []string
	Limit             int
}

FindRelatedOptions tunes the graph walk from a known memory.

type GraphMemory added in v0.7.0

type GraphMemory struct {
	ID            string         `json:"id"`
	Content       string         `json:"content"`
	Metadata      map[string]any `json:"metadata,omitempty"`
	Source        string         `json:"source,omitempty"`
	Tags          []string       `json:"tags,omitempty"`
	Relevance     float64        `json:"relevance,omitempty"`
	Confidence    float64        `json:"confidence,omitempty"`
	Depth         int            `json:"depth"`
	Relationship  string         `json:"relationship,omitempty"`
	EdgeStrength  float64        `json:"edge_strength,omitempty"`
	ConnectedFrom string         `json:"connected_from,omitempty"`
}

GraphMemory is a memory row returned from graph-walk queries. The extra fields (Depth, Relationship, EdgeStrength, ConnectedFrom) describe how this row was reached -- depth 0 means direct seed match, depth > 0 means we traversed N edges to get here.

func ExploreKnowledge added in v0.7.0

func ExploreKnowledge(ctx context.Context, cfg *Config, query string, opts ExploreOptions) ([]GraphMemory, error)

ExploreKnowledge runs hybrid search for query, then walks the relationship graph Depth hops deep. Returns seed matches at depth 0 and connected memories at depth 1+.

func FindRelated added in v0.7.0

func FindRelated(ctx context.Context, cfg *Config, memoryID string, opts FindRelatedOptions) ([]GraphMemory, error)

FindRelated traverses the relationship graph from memory_id and returns reachable memories with depth + edge strength annotations.

type GraphNode added in v0.7.1

type GraphNode struct {
	ID            string         `json:"id"`
	Content       string         `json:"content"`
	Metadata      map[string]any `json:"metadata,omitempty"`
	Source        string         `json:"source,omitempty"`
	Tags          []string       `json:"tags,omitempty"`
	Confidence    float64        `json:"confidence,omitempty"`
	Depth         int            `json:"depth"`
	Relationship  string         `json:"relationship,omitempty"`
	EdgeStrength  float64        `json:"edge_strength,omitempty"`
	ConnectedFrom string         `json:"connected_from,omitempty"`
	DirectionUsed string         `json:"direction_used,omitempty"`
}

GraphNode is a row returned from wiki_walk_graph. Carries the path metadata (depth, edge strength, direction) alongside the memory's own fields. Distinct from GraphMemory (used by hybrid-search-driven graph walks) because the wiki walk has direction_used, no relevance, and confidence is canonically present.

type HealthOptions

type HealthOptions struct {
	// LiveEmbedder performs a real embedding API call if true. Costs
	// one provider token per run; defaults off so `ogham health` is free.
	LiveEmbedder bool
}

HealthOptions lets callers opt into live external calls.

type HookOptions added in v0.7.3

type HookOptions struct {
	Profile string
	DryRun  bool
}

HookOptions controls the hook entry points (SessionStart, Recall, Inscribe). All fields are optional; zero values mean "use the default that mirrors the Python ogham.hooks implementation".

Profile follows the standard precedence: explicit Profile here > cfg.Profile > "default".

DryRun is honoured by Inscribe -- when true, the drain memory is composed and returned but NOT written to the store. SessionStart and Recall ignore DryRun (they're read-only).

type LinkUnlinkedOptions added in v0.7.0

type LinkUnlinkedOptions struct {
	BatchSize int
	Threshold float64
	MaxLinks  int
	Profile   string
}

LinkUnlinkedOptions mirrors the Python tool. Defaults match Python: batch_size=100, threshold=0.85, max_links=5.

type LinkUnlinkedResult added in v0.7.0

type LinkUnlinkedResult struct {
	Status    string `json:"status"` // "linked" | "nothing_to_link"
	Profile   string `json:"profile"`
	Processed int    `json:"processed"`
	BatchSize int    `json:"batch_size"`
}

LinkUnlinkedResult is the payload for the MCP tool.

func LinkUnlinked added in v0.7.0

func LinkUnlinked(ctx context.Context, cfg *Config, opts LinkUnlinkedOptions) (*LinkUnlinkedResult, error)

LinkUnlinked backfills auto-links for memories that don't have any yet. Returns the count of memories processed (not links created). Call repeatedly until processed=0 after a batch import.

type LintCategory added in v0.7.1

type LintCategory struct {
	Count  int              `json:"count"`
	Sample []map[string]any `json:"sample"`

	// OlderThanDays is non-zero only for stale_lifecycle (Python
	// includes this in its response so callers can see the threshold
	// they queried at).
	OlderThanDays int `json:"older_than_days,omitempty"`

	// Skipped is set on summary_drift when includeDrift=false so the
	// caller can tell "0 drift" from "we didn't check".
	Skipped bool `json:"skipped,omitempty"`
}

LintCategory is the count + sample shape every category returns. Kept generic so the JSON output mirrors the Python report structure.

type LintReport added in v0.7.1

type LintReport struct {
	Profile        string       `json:"profile"`
	Healthy        bool         `json:"healthy"`
	IssueCount     int          `json:"issue_count"`
	Contradictions LintCategory `json:"contradictions"`
	Orphans        LintCategory `json:"orphans"`
	StaleLifecycle LintCategory `json:"stale_lifecycle"`
	StaleSummaries LintCategory `json:"stale_summaries"`
	SummaryDrift   LintCategory `json:"summary_drift"`
}

LintReport is the aggregate response from LintWiki.

func LintWiki added in v0.7.1

func LintWiki(ctx context.Context, cfg *Config, profile string, opts LintWikiOptions) (*LintReport, error)

LintWiki computes the read-only lint report. Profile defaults to the active profile when empty.

type LintWikiOptions added in v0.7.1

type LintWikiOptions struct {
	SampleSize   int  // default 10
	StableDays   int  // default 90
	IncludeDrift bool // default true (caller passes opts; LintWiki sets if zero-value)
	// contains filtered or unexported fields
}

LintWikiOptions mirrors the Python lint_report keyword args.

func (*LintWikiOptions) SetIncludeDrift added in v0.7.1

func (o *LintWikiOptions) SetIncludeDrift(v bool)

SetIncludeDrift makes the includeDrift flag explicit. Calling this distinguishes "I want drift skipped" from "I left the field at the zero value (false) by accident." The default when unset is true.

type ListOptions

type ListOptions struct {
	Limit  int
	Source string
	Tags   []string
	Before time.Time
	OnDate time.Time
}

ListOptions captures the optional filters for List. Mirrors Python's list_recent_memories signature with two dashboard-friendly additions:

  • Before: if non-zero, restricts the result set to memories strictly older than the given timestamp. Used by the Timeline view's HTMX infinite scroll -- the client passes the oldest-visible created_at back as `?before=...` and the server returns the next page.
  • OnDate: if non-zero, restricts to memories whose created_at falls on the same UTC calendar day as the given time. Used by the Calendar heatmap drill-in (`/timeline?on=YYYY-MM-DD`).

Before and OnDate are mutually exclusive in practice -- OnDate narrows to a single day, Before paginates. If both are set we apply both; the Timeline handler never sends both together.

type MaskedConfig

type MaskedConfig struct {
	Profile   string            `json:"profile"`
	Database  MaskedDatabase    `json:"database"`
	Embedding MaskedEmbedding   `json:"embedding"`
	Paths     map[string]string `json:"paths"`
	// Warnings is a list of operator-facing diagnostics. Empty when the
	// config looks healthy. Currently flags configured-but-unprivileged
	// Supabase keys (anon / publishable) before the first request 401s.
	Warnings []string `json:"warnings,omitempty"`
}

MaskedConfig is a safe-to-print view of Config with secret values replaced by "<redacted>".

func Mask

func Mask(cfg *Config) MaskedConfig

Mask returns a redacted view of cfg. URL passwords and all API keys are replaced with "<redacted>". Empty fields are left empty so the reader can see which settings are missing.

type MaskedDatabase

type MaskedDatabase struct {
	Backend     string `json:"backend"`
	URL         string `json:"url,omitempty"`
	SupabaseURL string `json:"supabase_url,omitempty"`
	SupabaseKey string `json:"supabase_key,omitempty"`
	// SupabaseKeyKind reports the role behind the configured key:
	// "secret" / "service_role" (good), "anon" / "publishable" (bad,
	// will 401 on RPCs), or "unknown" (couldn't tell — try anyway).
	SupabaseKeyKind string `json:"supabase_key_kind,omitempty"`
}

type MaskedEmbedding

type MaskedEmbedding struct {
	Provider  string `json:"provider"`
	Model     string `json:"model,omitempty"`
	Dimension int    `json:"dimension"`
	APIKey    string `json:"api_key,omitempty"`
}

type Memory

type Memory struct {
	ID        string    `json:"id"`
	Content   string    `json:"content"`
	Tags      []string  `json:"tags"`
	Source    string    `json:"source,omitempty"`
	CreatedAt time.Time `json:"created_at"`
}

Memory is the native-mode view of a row from the memories table. Narrow on purpose -- native tools deliberately do not project every column; they ship the subset the CLI actually needs.

func List

func List(ctx context.Context, cfg *Config, opts ListOptions) ([]Memory, error)

List returns the most recent memories for the given profile. Routes to the Supabase REST path or the pgx path depending on cfg.

type ProfileCount

type ProfileCount struct {
	Profile string `json:"profile"`
	Count   int64  `json:"count"`
}

ProfileCount is one row from get_profile_counts(): a profile name plus the number of non-expired memories in it.

func ListProfiles

func ListProfiles(ctx context.Context, cfg *Config) ([]ProfileCount, error)

ListProfiles returns every profile that currently holds at least one non-expired memory. Matches Python's list_profiles tool which calls the get_profile_counts() function.

type ProfileTTL

type ProfileTTL struct {
	Profile string `json:"profile"`
	TTLDays *int   `json:"ttl_days"`
}

ProfileTTL describes a row from profile_settings. TTLDays is nil when the profile has no explicit TTL configured (memories then never expire unless the caller sets expires_at directly on store).

func GetProfileTTL

func GetProfileTTL(ctx context.Context, cfg *Config, profile string) (*ProfileTTL, error)

GetProfileTTL reads the TTL (days) currently configured for a profile. A nil return (no row + no error) means no TTL is configured.

func SetProfileTTL

func SetProfileTTL(ctx context.Context, cfg *Config, profile string, ttlDays int) (*ProfileTTL, error)

SetProfileTTL upserts a TTL for a profile. Pass a negative ttlDays to clear the setting entirely (match Python's None semantics).

type QueryTopicSummaryResult added in v0.7.1

type QueryTopicSummaryResult struct {
	Status         string `json:"status"`
	ID             string `json:"id,omitempty"`
	TopicKey       string `json:"topic_key"`
	Profile        string `json:"profile"`
	Version        int    `json:"version,omitempty"`
	StatusField    string `json:"summary_status,omitempty"` // fresh|stale|regenerating
	SourceCount    int    `json:"source_count,omitempty"`
	ModelUsed      string `json:"model_used,omitempty"`
	UpdatedAt      string `json:"updated_at,omitempty"`
	SourceHash     string `json:"source_hash,omitempty"`
	Level          string `json:"level,omitempty"`           // form actually returned
	RequestedLevel string `json:"requested_level,omitempty"` // what caller asked for (if differs from Level)
	Body           string `json:"body,omitempty"`            // selected text (one_line|short|body)
	Message        string `json:"message,omitempty"`         // populated for not_cached
}

QueryTopicSummaryResult is the MCP-shaped response. Mirrors Python's _format_summary_response with the v0.13 `level` / `requested_level` pair appended.

When Status == "not_cached" only TopicKey + Profile + Message are populated -- the rest are zero values.

func QueryTopicSummary added in v0.7.1

func QueryTopicSummary(ctx context.Context, cfg *Config, profile, topic string, level TLDRLevel) (*QueryTopicSummaryResult, error)

QueryTopicSummary fetches a cached summary for (profile, topic) and projects it down to the requested level. cfg.Profile is used when `profile` is empty.

type Report

type Report struct {
	OK       bool          `json:"ok"`
	Duration time.Duration `json:"duration_ns"`
	Backend  string        `json:"backend"`
	Provider string        `json:"provider,omitempty"`
	Checks   []CheckResult `json:"checks"`
}

Report is the aggregate return from HealthCheck. OK is true only if every probe succeeded.

func HealthCheck

func HealthCheck(ctx context.Context, cfg *Config, opts HealthOptions) (*Report, error)

HealthCheck runs the configured probes in parallel. The whole report completes in roughly the time of the slowest probe.

Probes currently included:

  • backend: Supabase PostgREST HEAD or Postgres pgx ping
  • embedder: config validation only by default (avoids a paid Gemini call on every `ogham health`); opt in to the live API call via opts.LiveEmbedder = true

type SearchOptions

type SearchOptions struct {
	Limit      int
	Tags       []string
	Source     string
	Profile    string // single-profile override; empty => use cfg.Profile
	Profiles   []string
	EntityTags []string
	// RecencyDecay > 0 tilts scoring toward newer memories. 0 = no decay.
	RecencyDecay float64
}

SearchOptions captures the optional arguments hybrid_search_memories accepts. Nil slices mean "no filter". Zero values mean "use RPC default".

type SearchResult

type SearchResult struct {
	ID          string         `json:"id"`
	Content     string         `json:"content"`
	Source      string         `json:"source,omitempty"`
	Profile     string         `json:"profile"`
	Tags        []string       `json:"tags"`
	Metadata    map[string]any `json:"metadata,omitempty"`
	Similarity  float64        `json:"similarity"`
	KeywordRank float64        `json:"keyword_rank"`
	Relevance   float64        `json:"relevance"`
	CreatedAt   time.Time      `json:"created_at"`
}

SearchResult mirrors the column set returned by hybrid_search_memories. Narrower projection than the memories table -- only what the CLI surfaces. Metadata carries the jsonb column as a decoded map so downstream callers (BEAM harness, MCP tool handlers) can read keys like msg_ids / chat_id without a second round-trip to fetch the same row.

func Search(ctx context.Context, cfg *Config, query string, opts SearchOptions) ([]SearchResult, error)

Search runs hybrid_search_memories using whichever backend is configured:

  • "supabase": PostgREST RPC call (no direct DB connection needed)
  • "postgres": pgx direct connection to Postgres

Both paths embed the query first via the configured provider.

type Stage added in v0.7.0

type Stage string

Stage is a memory's current lifecycle stage.

const (
	StageFresh   Stage = "fresh"
	StageStable  Stage = "stable"
	StageEditing Stage = "editing"
)

type StageReport added in v0.7.1

type StageReport struct {
	Profile         string `json:"profile"`
	FreshToStable   int    `json:"fresh_to_stable"`
	EditingClosed   int    `json:"editing_closed"`
	LifecycleAbsent bool   `json:"lifecycle_absent,omitempty"`
}

StageReport is the {fresh_to_stable, editing_closed} pair Python returns. Mirrors lifecycle.StageReport so the JSON shape is identical.

func AdvanceLifecycle added in v0.7.1

func AdvanceLifecycle(ctx context.Context, cfg *Config, profile string, opts AdvanceLifecycleOptions) (*StageReport, error)

AdvanceLifecycle runs the two-batch sweep for a profile. Returns counts for each transition.

type Stats

type Stats struct {
	Profile  string      `json:"profile"`
	Total    int64       `json:"total"`
	Sources  []Breakdown `json:"sources"`
	TopTags  []Breakdown `json:"top_tags"`
	Untagged int64       `json:"untagged_count"`
	WithTTL  int64       `json:"with_ttl_count"`
	Expiring int64       `json:"expiring_within_7d"`

	// ConnectedPct is the percentage (0-100) of active memories that
	// appear as either source_id or target_id in memory_relationships.
	// Answers "how much of my graph is wired up?" -- a profile at 5%
	// connected is effectively a flat list; one at 60%+ is a real graph.
	// When Total is 0 we return 0 (no rows, no percentage to compute).
	ConnectedPct float64 `json:"connected_pct"`

	// DecayCount is the number of active memories whose confidence has
	// fallen below DecayThreshold. Confidence decays over time in the
	// schema (see memories.confidence + the nightly decay job); memories
	// below the floor are nearly invisible to hybrid_search because the
	// relevance formula multiplies by confidence. Surfacing this as a
	// headline number lets operators spot profiles that need pruning or
	// reinforcement.
	DecayCount int64 `json:"decay_count"`
}

Stats is a lightweight summary of the active profile. Narrower than Python's get_stats (which also includes decay counters, orphan counts, cache stats, and configuration echo) -- the CLI uses of stats are "how many memories", "what's my top sources/tags", and "am I on the right profile", so this covers the headline numbers without the heavier aggregations.

func GetStats

func GetStats(ctx context.Context, cfg *Config) (*Stats, error)

GetStats aggregates counts for the active profile. Picks backend from cfg.ResolveBackend().

type StoreDecisionOptions added in v0.7.0

type StoreDecisionOptions struct {
	Decision        string
	Rationale       string
	Alternatives    []string
	ReasoningTrace  string
	Tags            []string
	RelatedMemories []string // rejected until Batch E lands
	Source          string
	Profile         string
}

type StoreEventOptions added in v0.7.0

type StoreEventOptions struct {
	Event        string
	When         string
	Participants []string
	Location     string
	Tags         []string
	Source       string
	Profile      string
}

type StoreFactOptions added in v0.7.0

type StoreFactOptions struct {
	Fact           string
	Subject        string
	Confidence     float64 // default 1.0; validated [0.0, 1.0]
	SourceCitation string
	Tags           []string
	Source         string
	Profile        string
}

type StoreOptions added in v0.7.0

type StoreOptions struct {
	Tags    []string
	Source  string
	Profile string // empty -> cfg.Profile (which itself falls back to "default")
	// Language is the 2-letter ISO code the extraction pipeline uses
	// for scoring, date parsing, and recurrence detection. Empty string
	// falls back to "en". Callers should set this from metadata[language]
	// on re-embed / migration paths, or leave it empty to default to
	// English. Values not in the embedded YAML registry produce a debug
	// slog warning and fall back silently to English.
	Language string
	// DryRun skips the actual DB write. Still runs extraction + embedding
	// + surprise so the caller sees what would happen. Useful for the
	// Day 4 --native-store-preview flag where we want to confirm the
	// pipeline is green without mutating the store.
	DryRun bool
	// Metadata is caller-supplied structured context that gets merged
	// over the extracted metadata (dates, etc.) before the DB write.
	// Primary consumer: the typed-store wrappers (store_decision,
	// store_fact, store_event, store_preference) which inject type-
	// specific structure. Extracted keys lose on collision so the
	// caller's intent wins. Nil is fine -- leaves extraction output
	// alone.
	//
	// If Metadata contains a "language" string key AND StoreOptions.Language
	// is empty, the metadata value is adopted as the effective language.
	// This mirrors Python's service.py behaviour where metadata carries
	// the language signal end-to-end.
	Metadata map[string]any
}

StoreOptions captures the per-request parameters Store accepts. Nil/empty fields use the config default.

type StorePreferenceOptions added in v0.7.0

type StorePreferenceOptions struct {
	Preference   string
	Subject      string
	Alternatives []string
	Strength     string // "strong" | "normal" | "weak"; default "normal"
	Tags         []string
	Source       string
	Profile      string
}

type StoreResult added in v0.7.0

type StoreResult struct {
	ID         string         `json:"id,omitempty"`
	Profile    string         `json:"profile"`
	Tags       []string       `json:"tags"`
	Entities   []string       `json:"entities"`
	Dates      []string       `json:"dates"`
	Importance float64        `json:"importance"`
	Surprise   float64        `json:"surprise"`
	LinkedTo   []AutoLink     `json:"linked_to,omitempty"`
	Elapsed    time.Duration  `json:"elapsed"`
	DryRun     bool           `json:"dry_run,omitempty"`
	Metadata   map[string]any `json:"metadata,omitempty"`
}

StoreResult is returned by Store. ID is empty when DryRun=true.

func Store added in v0.7.0

func Store(ctx context.Context, cfg *Config, content string, opts StoreOptions) (*StoreResult, error)

Store is the Day 4 native orchestrator. Mirrors the shape of Python's store_memory tool:

  1. Serial extraction (entities, dates, importance) -- ~microseconds
  2. errgroup parallel: - embedder.Embed(content) - searchByText(content[:200]) used to compute surprise
  3. surprise = 1.0 - max(similarity from step 2); default 0.5 on empty
  4. auto-link: top-N above threshold become links in the result; the actual INSERT into memory_links is deferred to the next commit
  5. DB write via backend (postgres direct; supabase still goes through the Python sidecar until a native PostgREST write lands)

The returned StoreResult is safe to marshal to JSON; cmd/store.go emits it to --json users.

func StoreDecision added in v0.7.0

func StoreDecision(ctx context.Context, cfg *Config, opts StoreDecisionOptions) (*StoreResult, error)

func StoreEvent added in v0.7.0

func StoreEvent(ctx context.Context, cfg *Config, opts StoreEventOptions) (*StoreResult, error)

func StoreFact added in v0.7.0

func StoreFact(ctx context.Context, cfg *Config, opts StoreFactOptions) (*StoreResult, error)

func StorePreference added in v0.7.0

func StorePreference(ctx context.Context, cfg *Config, opts StorePreferenceOptions) (*StoreResult, error)

type SupabaseKeyKind added in v0.7.2

type SupabaseKeyKind string

SupabaseKeyKind classifies a Supabase API key for warning purposes. Only "anon" and "publishable" are meaningful failure cases — both lack the privileges hybrid_search_memories and the memories table need. service_role + secret are the keys Ogham actually wants. unknown covers parse failures and is treated as "no warning, give it a try".

const (
	SupabaseKeyAnon        SupabaseKeyKind = "anon"
	SupabaseKeyPublishable SupabaseKeyKind = "publishable"
	SupabaseKeyServiceRole SupabaseKeyKind = "service_role"
	SupabaseKeySecret      SupabaseKeyKind = "secret"
	SupabaseKeyUnknown     SupabaseKeyKind = "unknown"
)

func ClassifySupabaseKey added in v0.7.2

func ClassifySupabaseKey(key string) SupabaseKeyKind

ClassifySupabaseKey inspects a Supabase API key and reports its kind.

The new prefixed keys (sb_secret_*, sb_publishable_*) are opaque and can be classified by prefix alone. The legacy keys are JWTs whose payload carries a "role" claim — we base64-decode the middle segment and read it. No signature check is performed; the key is going to be sent to Supabase anyway, which is the real authority.

func (SupabaseKeyKind) IsRPCCapable added in v0.7.2

func (k SupabaseKeyKind) IsRPCCapable() bool

IsRPCCapable reports whether a key is expected to authorise the RPC and SELECT-on-memories paths Ogham relies on. Used both by the loud 401 hint and by `ogham config show` to flag misconfigured keys before the first request even leaves the box.

type TLDRLevel added in v0.7.1

type TLDRLevel string

TLDRLevel selects the resolution of a topic summary read.

  • LevelOneLine -- ~30-50 tokens, single sentence
  • LevelShort -- ~150-300 tokens, one paragraph
  • LevelBody -- ~1000 words, full markdown body (the v0.12 default)

Mirrors the Python LevelType = Literal["one_line", "short", "body"] type alias used by `query_topic_summary(level=...)`.

const (
	LevelOneLine TLDRLevel = "one_line"
	LevelShort   TLDRLevel = "short"
	LevelBody    TLDRLevel = "body"
)

func ParseTLDRLevel added in v0.7.1

func ParseTLDRLevel(s string) (TLDRLevel, error)

ParseTLDRLevel coerces a user-supplied string to a TLDRLevel. Empty input maps to LevelBody to preserve the v0.12 caller contract -- callers that don't pass `level` get the full body, same as before. Unknown values are an error rather than a silent fallback so a typo in a CLI flag doesn't quietly downgrade what got returned.

type TopicSummary added in v0.7.1

type TopicSummary struct {
	ID           string    `json:"id"`
	TopicKey     string    `json:"topic_key"`
	ProfileID    string    `json:"profile"`
	Content      string    `json:"content"`
	TLDROneLine  *string   `json:"tldr_one_line,omitempty"`
	TLDRShort    *string   `json:"tldr_short,omitempty"`
	SourceCount  int       `json:"source_count"`
	SourceCursor *string   `json:"source_cursor,omitempty"`
	SourceHash   string    `json:"source_hash,omitempty"` // hex-encoded
	TokenCount   *int      `json:"token_count,omitempty"`
	Importance   float64   `json:"importance"`
	ModelUsed    string    `json:"model_used"`
	Version      int       `json:"version"`
	Status       string    `json:"status"`
	CreatedAt    time.Time `json:"created_at"`
	UpdatedAt    time.Time `json:"updated_at"`
	StaleReason  *string   `json:"stale_reason,omitempty"`
}

TopicSummary is the post-033 topic_summaries row shape.

TLDROneLine and TLDRShort are *string because they are NULLABLE on pre-033 rows and the read path needs to distinguish "explicitly empty" (string pointer to "") from "not populated yet" (nil).

SourceHash is rendered to hex in the JSON tag because raw bytea is awkward over JSON; the Python `_format_summary_response` does the same.

type UpdateOptions added in v0.7.0

type UpdateOptions struct {
	Content  *string
	Tags     []string
	Metadata map[string]any
	// Profile override; empty -> cfg.Profile -> "default".
	Profile string
}

UpdateOptions captures per-request update semantics. Pointer / nil-slice semantics let callers distinguish "field omitted" from "explicit clear":

Content  == nil        -> leave content untouched
Content  != nil        -> replace content (and re-embed)
Tags     == nil        -> leave tags untouched
Tags     != nil, len 0 -> clear tags (PostgreSQL empty array)
Metadata == nil        -> leave metadata untouched
Metadata != nil, len 0 -> clear metadata (jsonb '{}')

Matches the Python update_memory tool contract (None vs [] vs {}).

type UpdateResult added in v0.7.0

type UpdateResult struct {
	ID            string    `json:"id"`
	Profile       string    `json:"profile"`
	UpdatedAt     time.Time `json:"updated_at"`
	FieldsUpdated []string  `json:"fields_updated"`
	ReEmbedded    bool      `json:"re_embedded"`
}

UpdateResult is returned on success. FieldsUpdated is the list of column names that were actually written, so callers can log audit.

func Update added in v0.7.0

func Update(ctx context.Context, cfg *Config, id string, opts UpdateOptions) (*UpdateResult, error)

Update re-writes an existing memory. When opts.Content is non-nil the content is re-embedded via the configured embedder before the row is written -- the old embedding would poison future similarity search if we left it behind.

Returns an error when no fields are specified for update (parity with Python: raise ValueError("No updates provided")).

type WalkKnowledgeOptions added in v0.7.1

type WalkKnowledgeOptions struct {
	// Depth is the maximum number of edges to traverse. Server clamps to
	// 0..5 (anything beyond explodes the rowset on dense profiles). 0
	// means "no walk" -- you'd just get the seed node back.
	Depth int

	// Direction is "outgoing", "incoming", or "both". Empty -> "both".
	Direction string

	// MinStrength filters edges by strength (0..1). Default 0.0 = keep all.
	MinStrength float64

	// RelationshipTypes optionally restricts to a set of relationship
	// labels (e.g. ["depends_on", "cites"]). Empty -> no filter.
	RelationshipTypes []string

	// Limit caps the result rowset. Default 50 mirrors Python.
	Limit int
}

WalkKnowledgeOptions tunes the recursive walk. Defaults match the Python wiki tool layer.

type WalkKnowledgeResult added in v0.7.1

type WalkKnowledgeResult struct {
	StartID   string      `json:"start_id"`
	Depth     int         `json:"depth"`
	Direction string      `json:"direction"`
	NodeCount int         `json:"node_count"`
	Nodes     []GraphNode `json:"nodes"`
}

WalkKnowledgeResult mirrors the Python tool wrapper:

{ start_id, depth, direction, node_count, nodes }

func WalkKnowledge added in v0.7.1

func WalkKnowledge(ctx context.Context, cfg *Config, startID string, opts WalkKnowledgeOptions) (*WalkKnowledgeResult, error)

WalkKnowledge runs the recursive graph walk from startID. Returns the flattened set of reachable memories with depth/edge metadata.

type Zone added in v0.7.3

type Zone string

Zone is a stoplight bucket for a dimension score.

Mirrors Python ogham.health_dimensions.Zone:

GREEN  score >= 8.0  -- healthy, no action needed
AMBER  score >= 5.0  -- degraded, worth investigating
RED    score <  5.0  -- broken or near-broken
const (
	ZoneGreen Zone = "GREEN"
	ZoneAmber Zone = "AMBER"
	ZoneRed   Zone = "RED"
)

func ZoneOf added in v0.7.3

func ZoneOf(score float64) Zone

ZoneOf maps a 0-10 score to its stoplight bucket.

Directories

Path Synopsis
Package cache implements the shared SQLite-backed embedding cache.
Package cache implements the shared SQLite-backed embedding cache.
Package extraction implements the regex-driven entity + date extraction that runs at store_memory time.
Package extraction implements the regex-driven entity + date extraction that runs at store_memory time.

Jump to

Keyboard shortcuts

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