fleet-memory/skills/hindsight-docs/references/developer/api/mental-models.md
Nicolò Boschi a706905653
feat(skill): validate links, strip images, include openapi.json and changelog (#614)
* feat(skill): validate links, strip images, include openapi.json and changelog

- Add post-processing step to rewrite Docusaurus site-root paths (e.g.
  /developer/foo) to proper relative .md paths within the skill
- Strip markdown and HTML images from all generated files since assets
  are not bundled with the skill
- Copy hindsight-docs/static/openapi.json into references/openapi.json
  and map /api-reference links to it
- Include changelog.md from src/pages/ alongside faq and best-practices
- Add final validation step that fails the build if any link still
  points outside the skill directory

* ci: run generate-docs-skill in verify-generated-files job

* fix(skill): strip unresolvable site-root links instead of leaving them broken

* fix(skill): write file when images stripped but no links rewritten

* chore(skill): regenerate with fixed links, stripped images, changelog and openapi

* fix(skill): handle changelog as directory, add agno/hermes integrations, rebase on main
2026-03-19 12:32:33 +01:00

14 KiB

Mental Models

User-curated summaries that provide high-quality, pre-computed answers for common queries.

{/* Import raw source files */}

What Are Mental Models?

Mental models are saved reflect responses that you curate for your memory bank. When you create a mental model, Hindsight runs a reflect operation with your source query and stores the result. During future reflect calls, these pre-computed summaries are checked first — providing faster, more consistent answers.

graph LR
    A[Create Mental Model] --> B[Run Reflect]
    B --> C[Store Result]
    C --> D[Future Queries]
    D --> E{Match Found?}
    E -->|Yes| F[Return Mental Model]
    E -->|No| G[Run Full Reflect]

Why Use Mental Models?

Benefit Description
Consistency Same answer every time for common questions
Speed Pre-computed responses are returned instantly
Quality Manually curated summaries you've reviewed
Control Define exactly how key topics should be answered

Hierarchical Retrieval

During reflect, the agent checks sources in priority order:

  1. Mental Models — User-curated summaries (highest priority)
  2. Observations — Consolidated knowledge
  3. Raw Facts — Ground truth memories

Mental models are checked first because they represent your explicitly curated knowledge.


Create a Mental Model

Creating a mental model runs a reflect operation in the background and saves the result:

Python

# Create a mental model (runs reflect in background)
result = client.create_mental_model(
    bank_id=BANK_ID,
    name="Team Communication Preferences",
    source_query="How does the team prefer to communicate?",
    tags=["team", "communication"]
)

# Returns an operation_id - check operations endpoint for completion
print(f"Operation ID: {result.operation_id}")

Node.js

// Create a mental model (runs reflect in background)
const result = await client.createMentalModel(
    BANK_ID,
    'Team Communication Preferences',
    'How does the team prefer to communicate?',
    { tags: ['team', 'communication'] },
);

// Returns an operation_id — check operations endpoint for completion
console.log(`Operation ID: ${result.operation_id}`);

CLI

# Create a mental model (runs reflect in background)
hindsight mental-model create "$BANK_ID" \
  "Team Communication Preferences" \
  "How does the team prefer to communicate?"

Go

# Section 'create-mental-model' not found in api/mental-models.go

Parameters

Parameter Type Required Description
name string Yes Human-readable name for the mental model
source_query string Yes The query to run to generate content
id string No Custom ID for the mental model (alphanumeric lowercase with hyphens). Auto-generated if omitted.
tags list No Tags for filtering during retrieval
max_tokens int No Maximum tokens for the mental model content
trigger object No Trigger settings (see Automatic Refresh)

Create with Custom ID

Assign a stable, human-readable ID to a mental model so you can retrieve or update it by name instead of relying on the auto-generated UUID:

Python

# Create a mental model with a specific custom ID
result_with_id = client.create_mental_model(
    bank_id=BANK_ID,
    name="Communication Policy",
    source_query="What are the team's communication guidelines?",
    id="communication-policy"
)

print(f"Created with custom ID: {result_with_id.operation_id}")

Node.js

// Create a mental model with a specific custom ID
const resultWithId = await client.createMentalModel(
    BANK_ID,
    'Communication Policy',
    "What are the team's communication guidelines?",
    { id: 'communication-policy' },
);

console.log(`Created with custom ID: ${resultWithId.operation_id}`);

CLI

# Create a mental model with a specific custom ID
hindsight mental-model create "$BANK_ID" \
  "Communication Policy" \
  "What are the team's communication guidelines?" \
  --id communication-policy

Go

# Section 'create-mental-model-with-id' not found in api/mental-models.go

:::tip Custom IDs must be lowercase alphanumeric and may contain hyphens (e.g. team-policies, q4-status). If a mental model with that ID already exists, the request is rejected.

Automatic Refresh

Mental models can be configured to automatically refresh when observations are updated. This keeps them in sync with the latest knowledge without manual intervention.

Trigger Settings

Setting Type Default Description
refresh_after_consolidation bool false Automatically refresh after observations consolidation

When refresh_after_consolidation is enabled, the mental model will be re-generated every time the bank's observations are consolidated — ensuring it always reflects the latest synthesized knowledge.

Python

# Create a mental model with automatic refresh enabled
result = client.create_mental_model(
    bank_id=BANK_ID,
    name="Project Status",
    source_query="What is the current project status?",
    trigger={"refresh_after_consolidation": True}
)

# This mental model will automatically refresh when observations are updated
print(f"Operation ID: {result.operation_id}")

Node.js

// Create a mental model with automatic refresh enabled
const result2 = await client.createMentalModel(
    BANK_ID,
    'Project Status',
    'What is the current project status?',
    { trigger: { refreshAfterConsolidation: true } },
);

// This mental model will automatically refresh when observations are updated
console.log(`Operation ID: ${result2.operation_id}`);

CLI

# Create a mental model and get its ID for subsequent operations
hindsight mental-model create "$BANK_ID" \
  "Project Status" \
  "What is the current project status?"

Go

# Section 'create-mental-model-with-trigger' not found in api/mental-models.go

When to Use Automatic Refresh

Use Case Automatic Refresh Why
Real-time dashboards Enabled Status should always be current
Policy summaries Disabled Policies change infrequently, manual refresh preferred
User preferences Enabled Preferences evolve with new interactions
FAQ answers Disabled Answers are curated, should be reviewed before updating

:::tip Enable automatic refresh for mental models that need to stay current. Disable it for curated content where you want to review changes before they go live.

List Mental Models

Python

# List all mental models in a bank
mental_models = client.list_mental_models(bank_id=BANK_ID)

for mental_model in mental_models.items:
    print(f"- {mental_model.name}: {mental_model.source_query}")

Node.js

// List all mental models in a bank
const mentalModels = await client.listMentalModels(BANK_ID);

for (const mm of mentalModels.items) {
    console.log(`- ${mm.name}: ${mm.source_query}`);
}

CLI

# List all mental models in a bank
hindsight mental-model list "$BANK_ID"

Go

# Section 'list-mental-models' not found in api/mental-models.go

Get a Mental Model

Python

# Section 'get-mental-model' not found in api/mental-models.py

Node.js

// Get a specific mental model
const mentalModel = await client.getMentalModel(BANK_ID, mentalModelId);

console.log(`Name: ${mentalModel.name}`);
console.log(`Content: ${mentalModel.content}`);
console.log(`Last refreshed: ${mentalModel.last_refreshed_at}`);

CLI

# Section 'get-mental-model' not found in api/mental-models.sh

Go

# Section 'get-mental-model' not found in api/mental-models.go

Response Fields

Field Type Description
id string Unique mental model ID
bank_id string Memory bank ID
name string Human-readable name
source_query string The query used to generate content
content string The generated mental model text
tags list Tags for filtering
last_refreshed_at string When the mental model was last updated
created_at string When the mental model was created
reflect_response object Full reflect response including based_on facts

Refresh a Mental Model

Re-run the source query to update the mental model with current knowledge:

Python

# Section 'refresh-mental-model' not found in api/mental-models.py

Node.js

// Refresh a mental model to update with current knowledge
const refreshResult = await client.refreshMentalModel(BANK_ID, mentalModelId);

console.log(`Refresh operation ID: ${refreshResult.operation_id}`);

CLI

# Section 'refresh-mental-model' not found in api/mental-models.sh

Go

# Section 'refresh-mental-model' not found in api/mental-models.go

Refreshing is useful when:

  • New memories have been retained that affect the topic
  • Observations have been updated
  • You want to ensure the mental model reflects current knowledge

Update a Mental Model

Update the mental model's name:

Python

# Section 'update-mental-model' not found in api/mental-models.py

Node.js

// Update a mental model's metadata
const updated = await client.updateMentalModel(BANK_ID, mentalModelId, {
    name: 'Updated Team Communication Preferences',
    trigger: { refresh_after_consolidation: true },
});

console.log(`Updated name: ${updated.name}`);

CLI

# Section 'update-mental-model' not found in api/mental-models.sh

Go

# Section 'update-mental-model' not found in api/mental-models.go

Delete a Mental Model

Python

# Section 'delete-mental-model' not found in api/mental-models.py

Node.js

// Delete a mental model
await client.deleteMentalModel(BANK_ID, mentalModelId);

CLI

# Section 'delete-mental-model' not found in api/mental-models.sh

Go

# Section 'delete-mental-model' not found in api/mental-models.go

Tags and Visibility

Mental models support the same tag system as memories. When you assign tags to a mental model, those tags control both which memories it reads during refresh and when it is surfaced during reflect.

How tags affect mental model refresh

When a mental model is refreshed (manually or automatically), it runs an internal reflect call to regenerate its content. If the mental model has tags, that reflect call uses all_strict tag matching — meaning it will only read memories that carry all of the mental model's tags. Untagged memories are excluded.

Mental model tags: ["user:alice"]

During refresh, it reads:
  ✅ "Alice prefers async communication"     — has "user:alice"
  ✅ "Team uses Slack for announcements"      — has "user:alice" (plus other tags)
  ❌ "Company policy: no meetings on Fridays" — untagged, excluded
  ❌ "Bob dislikes long meetings"             — no "user:alice" tag

This means a mental model tagged ["user:alice"] will also pick up memories tagged ["user:alice", "team"] — extra tags on a memory don't disqualify it. Only the mental model's own tags are required to be present.

How tags affect mental model lookup during reflect

When you call reflect with tags, those same tags are used to filter which mental models the agent can see. A mental model is visible only if its tags overlap with the tags on the reflect request.

For more details on tag matching modes (any, any_strict, all, all_strict) and worked examples, see the Recall tags reference.


History

Every time a mental model's content changes (via refresh or manual update), the previous version is saved with a timestamp. You can retrieve the full change log with the history endpoint:

Python

# Section 'get-mental-model-history' not found in api/mental-models.py

Node.js

// Get the change history of a mental model
const history = await client.getMentalModelHistory(BANK_ID, mentalModelId);

for (const entry of history) {
    console.log(`Changed at: ${entry.changed_at}`);
    console.log(`Previous content: ${entry.previous_content}`);
}

CLI

# Section 'get-mental-model-history' not found in api/mental-models.sh

Go

# Section 'get-mental-model-history' not found in api/mental-models.go

Response

The endpoint returns a list of history entries, most recent first:

Field Type Description
previous_content string | null The content before this change (null if not available)
changed_at string ISO 8601 timestamp of when the change occurred

Each entry captures the content before the change and when it happened. The current content is returned by the standard Get a Mental Model endpoint.

:::note History tracking is enabled by default. Set HINDSIGHT_API_ENABLE_MENTAL_MODEL_HISTORY=false to disable it.

Use Cases

Use Case Example
FAQ Answers Pre-compute answers to common customer questions
Onboarding Summaries "What should new team members know?"
Status Reports "What's the current project status?" refreshed weekly
Policy Summaries "What are our security policies?"

Next Steps

  • Reflect — How the agentic loop uses mental models
  • Observations — How knowledge is consolidated
  • Operations — Track async mental model creation