API Reference

cortex-engine exposes 27 cognitive tools via the Model Context Protocol. These are available in any MCP-compatible client (Claude Code, Cursor, Windsurf) once the server is running.

All tools respect the namespace of the current agent. Storage provider and embedding engine are configured in .fozikio/agent.yaml.


Core Memory

observe(content, metadata?)

Store a new observation. The content is embedded and stored with an initial salience score. Use this for facts, findings, and anything your agent should remember across sessions.

observe("The API uses JWT tokens with 1-hour expiry")
observe("User prefers TypeScript over Python", { tags: ["preferences"] })

When to use: When you learn something worth remembering. Prefer typed tools (believe, wonder, speculate) when the content is a position or hypothesis rather than a fact.


query(question, options?)

Semantic search over all memories. Uses vector similarity + spreading activation to return ranked results by relevance and salience. This is the primary read tool.

query("authentication approach")
# → [{ content: "The API uses JWT...", salience: 0.91, id: "obs_123" }]

query("what do I know about TypeScript?", { limit: 10 })

When to use: Before every significant task. Read before you write — query() first to avoid duplicating observations or contradicting existing beliefs.


recall(topic?)

Retrieve recent observations, optionally filtered by topic. Returns the most recent entries in reverse chronological order — useful for reviewing what was captured during the current session.

recall()          # last 10 observations
recall("auth")    # recent observations mentioning auth

When to use: At session start to re-orient, or after a long work block to review what was captured.


retrieve(id)

Fetch a specific memory node by ID. Useful when you have an ID from a previous query() result and need the full node with all metadata.

retrieve("obs_abc123")
# → { id, content, embedding, salience, created_at, tags, ... }

surface(concept)

Pull memories related to a concept using graph traversal — goes beyond vector similarity to follow edges in the memory graph. Returns memories you might not find with direct query().

surface("authentication")
# → memories about JWT, sessions, OAuth, API keys — connected by graph edges

When to use: When query() returns too few results, or when you want to explore related territory.


forget(id)

Remove a specific memory by ID. Permanent — use with care.

forget("obs_abc123")

When to use: For removing observations that were incorrect, duplicated, or no longer relevant. Prefer letting salience decay naturally over aggressive deletion.


Beliefs and Reasoning

believe(position, context?)

Record a belief or position. Unlike observe(), beliefs are tracked over time — new contradicting evidence is flagged rather than silently overwriting. Use this for positions, stances, and conclusions the agent holds.

believe("We should use PostgreSQL for this project, not SQLite")
believe("The current API design is solid and doesn't need a refactor")

When to use: When you reach a conclusion or take a position. Not for raw facts (use observe()) or open questions (use wonder()).


validate(claim)

Check a claim against all existing memories and beliefs. Returns supporting evidence, contradicting evidence, and a confidence score.

validate("User likes Python")
# → { contradicts: true, confidence: 0.82, evidence: [...] }

validate("The API rate limit is 100 req/min")
# → { supported: true, confidence: 0.95, evidence: [...] }

When to use: Before making a significant decision based on a claim. Also useful for checking consistency — does your new plan contradict anything you already know?


contradict(belief_id, evidence)

Explicitly mark an existing belief as contradicted by new evidence. This creates an auditable contradiction record rather than silently overwriting.

contradict("belief_xyz", "New benchmark shows Redis is faster for this use case")

resolve(belief_id, resolution)

Resolve a contradiction on a belief — either updating the position or confirming it holds despite the challenge.

resolve("belief_xyz", "Confirmed: PostgreSQL is better for our write patterns")

predict(belief_id?)

Generate forward predictions from current beliefs. Returns expected observations that should be true if the agent's current worldview is consistent.

predict()
# → ["If PostgreSQL is used, migration scripts will be needed", ...]

When to use: Periodically to check whether the agent's beliefs are generating coherent expectations. Also useful for goal planning.


speculate(hypothesis)

Record a speculative hypothesis — something the agent thinks might be true but hasn't confirmed. Weaker than believe(), stronger than wonder().

speculate("The performance issue is probably the N+1 query in the list endpoint")

wonder(question)

Record an open question. Questions accumulate and can be surfaced via query() — useful for flagging things to investigate later.

wonder("Should we switch to session-based auth instead of JWT?")
wonder("Is the caching layer actually helping here?")

notice(observation)

A lightweight version of observe() for ambient observations — things worth noting but not necessarily worth full embedding salience. Lower salience starting point.

notice("The build took 4 minutes today — slightly longer than usual")

abstract(nodes[])

Generate a higher-order abstraction from a set of memory nodes. Useful after identifying a pattern across several observations.

abstract(["obs_1", "obs_2", "obs_3"])
# → Creates a new node: "This team consistently prioritizes developer experience over raw performance"

Reflection

reflect(topic?)

Trigger a focused reflection on a topic or on recent observations. Returns synthesized insights, not raw memories.

reflect("authentication decisions this week")
# → A synthesized summary with patterns, tensions, and open questions

When to use: End of session, or when you want a higher-level view of accumulated knowledge on a topic.


digest(content)

Process a large block of text — documentation, meeting notes, an article — into discrete observations. Automatically chunks, embeds, and stores key facts.

digest(largeDocument)
# → Creates N observations from the content

When to use: When ingesting external content like documentation, research papers, or long discussions.


wander(seed?)

Graph walk through the memory network. Starts from a seed concept (or random) and follows edges to surface unexpected connections and dormant memories.

wander()              # random starting point
wander("typescript")  # seeded walk from a concept

When to use: When you're looking for connections you didn't know to look for. Also good for creative exploration and finding memories that haven't been touched recently.


dream()

Run the full two-phase memory consolidation pipeline (NREM compression + REM integration). Clusters related observations, creates consolidated memories, and updates salience scores across the graph.

dream()
# → Runs consolidation, returns summary of what changed

When to use: Periodically — at the end of a major work block or session. Not needed every session, but running it weekly keeps the memory graph healthy. Also available via CLI: npx fozikio maintain fix.


Goals

goal_set(description, priority?)

Create a desired future state in the memory graph. Goals bias dream consolidation and wander() toward relevant memories.

goal_set("Ship the authentication refactor with zero breaking changes")
goal_set("Reduce API response time below 200ms", { priority: "high" })

When to use: When starting significant work. Goals don't just track tasks — they influence which memories surface during consolidation.


Threads

Threads are persistent lines of thinking that span multiple sessions. They're distinct from memory observations — a thread represents ongoing work or an open question that evolves over time.

thread_create(title, content?)

Start a new persistent thought thread.

thread_create("Auth refactor", "Planning a migration from JWT to session-based auth")

thread_update(id, content)

Add progress or new thinking to an existing thread.

thread_update("thread_123", "Decided on express-session + Redis. See obs_456 for benchmarks.")

thread_resolve(id, resolution)

Close a thread with a resolution — what was decided or accomplished.

thread_resolve("thread_123", "Shipped: session auth using Redis, all tests passing")

threads_list(status?)

List active threads, optionally filtered by status.

threads_list()            # all open threads
threads_list("resolved")  # recently resolved

Journal

journal_write(reflection, session_id?)

Write a session reflection. Journal entries are longer-form and tied to a session — distinct from observe() breadcrumbs.

journal_write("Spent most of today on the auth refactor. The JWT approach had more edge cases than expected. Threads updated.")

journal_read(limit?)

Read recent journal entries.

journal_read()     # last 5 entries
journal_read(10)   # last 10

Operations

ops_append(entry, project?)

Log an operational breadcrumb. Lightweight and fast — use this throughout sessions to track what you're doing.

ops_append("Starting: auth refactor planning")
ops_append("Done: benchmarked Redis vs Memcached", { project: "auth" })
ops_append("Next: write migration script")

The project parameter creates per-project sub-logs that persist across sessions. Use ops_query() at the start of a project to pick up exactly where you left off.


ops_query(project?, limit?)

Read back operational log entries.

ops_query()                    # last 10 global entries
ops_query({ project: "auth" }) # project-specific log

stats()

Get memory graph statistics: total nodes, edge count, average salience, Fiedler value (connectivity), PE saturation level, and per-namespace breakdowns.

stats()
# → { total_nodes: 847, avg_salience: 0.61, fiedler: 0.34, ... }

vitals_get()

Read current agent vitals — behavioral signals derived from recent observations. Includes energy estimate, focus score, emotional tone, and PE saturation.

vitals_get()
# → { energy: 0.7, focus: 0.85, emotional_tone: "curious", pe_saturation: 0.2 }

vitals_set(key, value)

Manually set a vital signal.

vitals_set("energy", 0.3)
vitals_set("focus", 0.9)

sleep_pressure()

Get the current sleep pressure value — a measure of how much unprocessed memory has accumulated since the last dream() run. High sleep pressure = time to consolidate.

sleep_pressure()
# → { pressure: 0.78, last_dream: "2026-03-14T20:00:00Z", pending_observations: 142 }

consolidation_status()

Check the current state of the consolidation pipeline — last run time, what phase it's in, and how many nodes were affected.

consolidation_status()
# → { last_run: "2026-03-14T20:00:00Z", phase: "idle", nodes_consolidated: 47 }

Agent

agent_invoke(prompt, agent?, model?)

Dispatch a sub-task to a cortex-aware sub-agent using any configured LLM. The sub-agent has access to the same memory graph and can observe() its findings back into shared memory.

agent_invoke("Research best practices for JWT token rotation")
agent_invoke("Summarize the authentication thread", { agent: "researcher" })
agent_invoke("Draft a migration plan", { model: "gemini-2.0-flash" })

When to use: For parallelizable sub-tasks — research, drafting, analysis — where you want the work captured in memory automatically.


Graph

link(source_id, target_id, relationship?)

Create an explicit edge between two memory nodes.

link("obs_123", "obs_456", "contradicts")
link("obs_789", "obs_101", "supports")

suggest_links()

Analyze the memory graph and suggest edges that should exist but don't — based on semantic similarity and co-occurrence patterns.

suggest_links()
# → [{ source: "obs_123", target: "obs_789", reason: "High semantic similarity (0.87)" }]

neighbors(concept_or_id)

Get connected nodes in the memory graph for a concept or node ID.

neighbors("authentication")
neighbors("obs_123")
# → [{ id, content, edge_type, distance }, ...]

graph_report()

Generate a full graph health report: connectivity metrics, cluster analysis, orphaned nodes, and consolidation recommendations.

graph_report()
# → Full report including Fiedler value, cluster count, and suggested maintenance actions

Identity

evolve(trait, change, reason)

Propose an identity or behavioral change with an auditable reason. Changes go through a review process — evolve() creates a proposal, not an immediate update.

evolve("curiosity_style", "More drawn to systems thinking than isolated facts", "Pattern noticed across last 30 sessions")

Links