Documentation
¶
Index ¶
- Constants
- Variables
- func KeyFingerprint(key string) string
- func WriteManifest(dir string, m Manifest) error
- type AccessConfig
- type AccessKey
- type BackfillResult
- type Cortex
- func (c *Cortex) Add(t *trace.Trace) error
- func (c *Cortex) Archive(id string) error
- func (c *Cortex) ArchiveDir() string
- func (c *Cortex) BackfillCreateEvents(dryRun bool) (BackfillResult, error)
- func (c *Cortex) CheckSourceLock(id string) error
- func (c *Cortex) Close() error
- func (c *Cortex) DerivedBy(id string) ([]string, error)
- func (c *Cortex) DivergenceCount() (int, error)
- func (c *Cortex) Events(traceID string) ([]event.Event, error)
- func (c *Cortex) EventsSince(afterID string, limit int) ([]event.Event, error)
- func (c *Cortex) Get(id string) (*Row, error)
- func (c *Cortex) GetClock() (federation.VClock, error)
- func (c *Cortex) List(opts ListOptions) ([]Row, error)
- func (c *Cortex) MergeClock(remote federation.VClock) error
- func (c *Cortex) Purge(days int) error
- func (c *Cortex) Recover(id string) error
- func (c *Cortex) Remove(id string) error
- func (c *Cortex) ReplayEvent(e event.Event) error
- func (c *Cortex) ResolveDivergence(divergenceID, acceptOrigin, customBody string) error
- func (c *Cortex) Search(query string, opts ListOptions) ([]Row, error)
- func (c *Cortex) SetForceSourceLock(v bool)
- func (c *Cortex) Sync() (SyncResult, error)
- func (c *Cortex) SyncWithOptions(opts SyncOptions) (SyncResult, error)
- func (c *Cortex) TraceFile(id string, archived bool) string
- func (c *Cortex) TracesDir() string
- func (c *Cortex) Trash(id string) error
- func (c *Cortex) TrashDir() string
- func (c *Cortex) TrashFile(id string) string
- func (c *Cortex) Unarchive(id string) error
- func (c *Cortex) Update(id string) error
- type FederationConfig
- type ListOptions
- type Manifest
- type PeerEntry
- type Row
- type SyncOptions
- type SyncResult
Constants ¶
const ( FederationModeSync = "sync" // bidirectional: pull from peers + serve events FederationModePublish = "publish" // outbound only: serve events, never pull FederationModeSubscribe = "subscribe" // inbound only: pull from peers, refuse to serve )
Federation mode constants.
const ( PeerModeSync = "sync" // actively pull from this peer PeerModePaused = "paused" // configured but skipped by the syncer )
Peer mode constants.
const AccessKeyEnvVar = "NOEMA_MCP_KEY"
AccessKeyEnvVar is the environment variable that overrides cortex.md's access.shared_key_file. When set to a non-empty, non- whitespace value it is used as the MCP shared key, and any configured file path is recorded so the caller can warn about the override.
const ManifestVersion = 2
ManifestVersion is the current cortex.md schema version. Cortexes written at this version carry an `id` field; cortexes at any earlier version must be migrated via `noema migrate cortex-id` before federation will accept them.
Variables ¶
var ErrSourceLocked = errors.New("trace is source-locked")
ErrSourceLocked is returned when a mutation is attempted on a source-locked trace from a foreign origin.
Functions ¶
func KeyFingerprint ¶ added in v0.3.0
KeyFingerprint returns a non-secret SHA-256 fingerprint of an MCP shared key, formatted SSH-style as SHA256:<pair>:<pair>:... Safe to log, display in federation_status, and read aloud over an out-of-band channel when confirming a pairing.
func WriteManifest ¶ added in v0.3.0
WriteManifest writes the manifest back to cortex.md in the given directory.
Types ¶
type AccessConfig ¶ added in v0.3.0
type AccessConfig struct {
// line is the shared bearer token. Relative paths are resolved
// against the cortex directory. The manifest itself never holds the
// secret — only a pointer to where it lives.
SharedKeyFile string `yaml:"shared_key_file,omitempty"`
}
AccessConfig holds MCP endpoint authentication settings for cortex.md. When SharedKeyFile is set, the HTTP MCP endpoint runs in shared-key mode and every incoming request must carry a matching Authorization bearer header. See docs/design/mcp-auth-plan.md for the full design.
type AccessKey ¶ added in v0.3.0
type AccessKey struct {
// Value is the raw bearer token. It must never be logged, written to
// the event log, serialised to MCP responses, or echoed in error
// messages. Only the Fingerprint is safe to surface.
Value string
// Source is "env" (NOEMA_MCP_KEY), "file" (read from disk), or ""
// (open mode).
Source string
// Path is the absolute file path the key was read from when
// Source == "file", or the configured-but-overridden file path when
// Source == "env" and the manifest also declared a shared_key_file.
// Empty when neither applies.
Path string
// Fingerprint is a non-secret SHA-256 digest of Value, formatted
// SSH-style (e.g. SHA256:a3:f1:...:c2). Safe to log and display.
Fingerprint string
}
AccessKey is the resolved shared key for the HTTP MCP endpoint, along with metadata about where it came from and a non-secret fingerprint. The zero value represents open mode (no authentication).
func LoadAccessKey ¶ added in v0.3.0
func LoadAccessKey(cortexDir string, cfg *AccessConfig) (AccessKey, error)
LoadAccessKey resolves the active MCP shared key for a cortex.
Resolution order (highest priority first):
- NOEMA_MCP_KEY — if set to a non-empty value, wins. The configured file path is still recorded in AccessKey.Path so the caller can log that the env var overrode it.
- cfg.SharedKeyFile — read relative to cortexDir unless already absolute. The file is validated for permissions, size, and format (see loadKeyFile).
- Open mode — returns the zero AccessKey with a nil error.
Errors are returned when the env var is set to only whitespace, when a configured file cannot be read, when permissions are looser than 0600, when the file exceeds 4 KiB, when it is empty or whitespace only, or when it contains two or more non-empty lines.
func (AccessKey) EnvOverride ¶ added in v0.3.0
EnvOverride reports whether NOEMA_MCP_KEY took precedence over a configured access.shared_key_file. Callers use this to emit the one-line warning on startup.
type BackfillResult ¶ added in v0.3.0
type BackfillResult struct {
BackfilledIDs []string // active traces that received a synthetic create event
SkippedIDs []string // traces with no create event but currently archived/trashed
}
BackfillResult summarises a `noema events backfill` operation. The slices hold trace IDs (not row counts) so the caller can render them line-by-line for the operator's audit trail.
type Cortex ¶
type Cortex struct {
ID string // ULID, stable across renames; the federation identity key
Name string // human-readable display label
Dir string
DB *db.DB
// contains filtered or unexported fields
}
func Open ¶
Open opens an existing Cortex by directory path. It ensures required subdirectories exist and auto-purges expired trash.
func (*Cortex) ArchiveDir ¶
func (*Cortex) BackfillCreateEvents ¶ added in v0.3.0
func (c *Cortex) BackfillCreateEvents(dryRun bool) (BackfillResult, error)
BackfillCreateEvents emits synthetic `create` events for any active trace that lacks one in the event log. This folds traces that pre-date the event log — or that landed via `noema sync`, which intentionally emits no events because it is reconciliation, not a semantic mutation — back into the federated history so peers can replay them.
Each backfilled event uses a fresh ULID, the local cortex_id and origin, the current wall-clock time as the event timestamp, and a JSON snapshot of the trace's current frontmatter + body. The trace's own `created` field (in the markdown frontmatter and the DB row) is left untouched, so the audit trail still surfaces "this happened on <real date>" — the event timestamp only records when the backfill ran. Using wall-clock time keeps per-cortex ULID monotonicity and avoids the event log lying about when the event was actually appended.
Archived and trashed traces are skipped: emitting only a `create` event for them would leave federation diverged (peers would materialise the trace as active and never see the archive/trash). Recover or unarchive the trace first if it needs to federate.
If dryRun is true, no events are written and the vector clock is not touched, but the returned result still lists every trace that would have been backfilled or skipped — so operators can preview before committing.
The iteration is idempotent: traces that already have a create event in the log (whether locally emitted or replayed from a peer) are not in the candidate set, so running this twice is a no-op on the second pass.
func (*Cortex) CheckSourceLock ¶ added in v0.5.0
CheckSourceLock returns ErrSourceLocked if the trace is source-locked by a foreign origin. The check is skipped when forceSourceLock is set.
func (*Cortex) DerivedBy ¶ added in v0.3.0
DerivedBy returns all trace IDs that list the given trace as a source.
func (*Cortex) DivergenceCount ¶ added in v0.3.0
DivergenceCount returns the number of unresolved divergence traces.
func (*Cortex) Events ¶ added in v0.3.0
Events returns the event log for a specific trace, ordered chronologically.
func (*Cortex) EventsSince ¶ added in v0.3.0
EventsSince returns events after the given ULID cursor, up to limit.
func (*Cortex) GetClock ¶ added in v0.3.0
func (c *Cortex) GetClock() (federation.VClock, error)
GetClock returns the current vector clock.
func (*Cortex) MergeClock ¶ added in v0.3.0
func (c *Cortex) MergeClock(remote federation.VClock) error
MergeClock merges a remote vector clock into the local clock.
func (*Cortex) Purge ¶ added in v0.2.0
Purge permanently deletes traces that have been in the trash for more than days days. A days value of 0 is treated as 30.
func (*Cortex) Recover ¶ added in v0.2.0
Recover moves a trace out of the trash and back to the active traces directory.
func (*Cortex) Remove ¶
Remove permanently deletes a trace from disk and the database. Use Trash for recoverable deletion.
func (*Cortex) ReplayEvent ¶ added in v0.3.0
ReplayEvent materializes a remote event locally without emitting a new event. The remote event is stored in the local log with its original ID and origin.
func (*Cortex) ResolveDivergence ¶ added in v0.3.0
ResolveDivergence resolves a divergence trace by either picking one of the versions stored in the divergence body (by origin name) or applying a caller-supplied custom merge. Exactly one of acceptOrigin or customBody must be non-empty. The divergence trace is trashed once the original is updated.
func (*Cortex) SetForceSourceLock ¶ added in v0.5.0
SetForceSourceLock enables or disables the source-lock override. When enabled, mutations on source-locked traces succeed with a warning instead of being refused. Intended for CLI --force flags only.
func (*Cortex) Sync ¶ added in v0.2.2
func (c *Cortex) Sync() (SyncResult, error)
Sync reconciles the database with the current state of the markdown files on disk. It walks traces/, archive/traces/, and trash/traces/, upserts every file it finds, and reports orphaned DB rows (not deleted — just reported).
func (*Cortex) SyncWithOptions ¶ added in v0.3.0
func (c *Cortex) SyncWithOptions(opts SyncOptions) (SyncResult, error)
SyncWithOptions is Sync with explicit options. See SyncOptions.
func (*Cortex) Trash ¶ added in v0.2.0
Trash moves a trace to the trash directory for deferred deletion.
type FederationConfig ¶ added in v0.3.0
type FederationConfig struct {
Mode string `yaml:"mode,omitempty"` // sync | publish | subscribe
Peers []PeerEntry `yaml:"peers,omitempty"`
Interval string `yaml:"interval,omitempty"` // e.g. "30s", "1m"
}
FederationConfig holds peer declarations for cortex.md.
func (*FederationConfig) EffectiveMode ¶ added in v0.5.0
func (fc *FederationConfig) EffectiveMode() string
EffectiveMode returns the configured federation mode, defaulting to "sync".
type ListOptions ¶
type Manifest ¶
type Manifest struct {
ID string `yaml:"id,omitempty"`
Name string `yaml:"name"`
Purpose string `yaml:"purpose,omitempty"`
Owner string `yaml:"owner,omitempty"`
Created string `yaml:"created"`
Version int `yaml:"version"`
Access *AccessConfig `yaml:"access,omitempty"`
Federation *FederationConfig `yaml:"federation,omitempty"`
}
Manifest is the cortex.md file at the root of each Cortex.
func Create ¶
Create initialises a new Cortex on disk and registers it. dir is the parent directory; the cortex is created as dir/<name>/. Returns the freshly written manifest so callers can surface the new cortex's ULID to the user (see `noema init`).
func ReadManifest ¶ added in v0.2.2
ReadManifest parses the cortex.md manifest in the given cortex directory.
func (Manifest) PeerLabelCollidesWithSelf ¶ added in v0.3.0
PeerLabelCollidesWithSelf reports whether the proposed peer label is the same as this cortex's own name. This is a federation safety guardrail: even after the cortex-id migration (docs/design/cortex-uuid-plan.md), a label collision is confusing in display surfaces and should be rejected at config time.
func (Manifest) ValidateFederation ¶ added in v0.5.0
ValidateFederation checks that the federation mode and per-peer modes in the manifest are recognized values. Returns nil when there is no federation block or when all values are valid.
type PeerEntry ¶ added in v0.3.0
type PeerEntry struct {
Name string `yaml:"name"`
Endpoint string `yaml:"endpoint"`
CA string `yaml:"ca,omitempty"` // path to CA cert for TLS verification
Mode string `yaml:"mode,omitempty"` // sync | paused
}
PeerEntry is a peer declared in cortex.md.
func (PeerEntry) EffectiveMode ¶ added in v0.5.0
EffectiveMode returns the configured peer mode, defaulting to "sync".
type Row ¶
type Row struct {
ID string
Title string
Type string
Author string
Origin string
Tags []string
DerivedFrom []string
ArchivedAt string
TrashedAt string
CreatedAt string
UpdatedAt string
ContentHash string
SourceLocked bool
SourceHash string
}
Row is a DB row joined with tags, returned by list/search operations.
type SyncOptions ¶ added in v0.3.0
type SyncOptions struct {
// Recover, when true, attempts to rebuild missing files for orphaned DB
// rows from the local event log. Off by default so manual `rm` of a trace
// file remains a valid way to mark it for cleanup.
Recover bool
}
SyncOptions controls optional Sync behaviors.
type SyncResult ¶ added in v0.2.2
type SyncResult struct {
Added int // files found on disk but not in DB
Updated int // files found on disk and already in DB (re-synced)
Recovered int // orphaned DB rows whose files were rebuilt from the event log
Orphaned int // IDs in DB with no corresponding file on disk (after recovery)
}
SyncResult summarises what Sync found.