memory-schema · git:20261012.373ec2e · 2026-10-12 · sha256 2fb37d186903b6b0

memory-schema git:20261012.373ec2eA

Immutable. This exact content never changes and is served at /api/v1/blob/2fb37d186903b6b0.

---
name: memory-schema
description: "Manage Basic Memory schemas: find unschemaed notes, infer and edit schemas, validate notes, detect drift. Use when structured note types (Task, Person, Meeting) need consistency across the graph."
---

# Memory Schema

Manage structured note types using Basic Memory's Picoschema system. Schemas define what fields a note type should have, making notes uniform, queryable, and validatable.

## When to Use

- **New note type emerging** — you notice several notes share the same structure (meetings, people, decisions)
- **Validation check** — confirm existing notes conform to their schema
- **Schema drift** — detect fields that notes use but the schema doesn't define (or vice versa)
- **Schema evolution** — add/remove/change fields as requirements evolve
- **On demand** — user asks to create, check, or manage schemas

## Picoschema Syntax Reference

Schemas are defined in YAML frontmatter using Picoschema — a compact notation for describing note structure.

### Basic Types

```yaml
schema:
  name: string, person's full name
  age: integer, age in years
  score: number, floating-point rating
  active: boolean, whether currently active
```

Supported types: `string`, `integer`, `number`, `boolean`.

### Optional Fields

Append `?` to the field name:

```yaml
schema:
  title: string, required field
  subtitle?: string, optional field
```

### Enums

Use `(enum)` with a list of allowed values:

```yaml
schema:
  status(enum, current state): [active, blocked, done, abandoned]
```

Optional enum:

```yaml
schema:
  priority?(enum, task priority): [low, medium, high, critical]
```

### Arrays

Use `(array)` for list fields:

```yaml
schema:
  tags(array): string, categorization labels
  steps?(array): string, ordered steps to complete
```

### Relations

Reference other entity types directly:

```yaml
schema:
  parent_task?: Task, parent task if this is a subtask
  attendees?(array): Person, people who attended
```

Relations create edges in the knowledge graph, linking notes together.

### Validation Settings

```yaml
settings:
  validation: warn    # warn (log issues) or strict (errors)
```

Use `strict` as the canonical enforcing mode. `error` is accepted only as a compatibility alias.

### Complete Example

```yaml
---
title: Meeting
type: schema
entity: Meeting
version: 1
schema:
  topic: string, what was discussed
  date: string, when it happened (YYYY-MM-DD)
  attendees?(array): Person, who attended
  decisions?(array): string, decisions made
  action_items?(array): string, follow-up tasks
  status?(enum, meeting state): [scheduled, completed, cancelled]
settings:
  validation: warn
---
```

## Discovering Unschemaed Notes

Look for clusters of notes that share structure but have no schema:

1. **Search by type**: `search_notes(note_types=["meeting"])` — if many notes share a `type` but no `schema/Meeting.md` exists, it's a candidate.

2. **Infer a schema**: Use `schema_infer` to analyze existing notes and generate a suggested schema:
   ```python
   schema_infer(note_type="Meeting")
   schema_infer(note_type="Meeting", threshold=0.5)  # fields in 50%+ of notes
   ```
   The threshold (0.0–1.0) controls how common a field must be to be included. Default is usually fine; lower it to catch rarer fields.

3. **Review the suggestion** — the inferred schema shows field names, types, and frequency. Decide which fields to keep, make optional, or drop.

## Creating a Schema

Write the schema note to `schema/<EntityName>`:

```python
write_note(
  title="Meeting",
  directory="schema",
  note_type="schema",
  metadata={
    "entity": "Meeting",
    "version": 1,
    "schema": {
      "topic": "string, what was discussed",
      "date": "string, when it happened",
      "attendees?(array)": "Person, who attended",
      "decisions?(array)": "string, decisions made"
    },
    "settings": {"validation": "warn"}
  },
  content="""# Meeting

Schema for meeting notes.

## Observations
- [convention] Meeting notes live in memory/meetings/ or as daily entries
- [convention] Always include date and topic
- [convention] Action items should become tasks when complex"""
)
```

### Key Principles

- **Schema notes live in `schema/`** — one note per entity type
- **`note_type="schema"`** marks it as a schema definition
- **`entity: Meeting`** in metadata names the type it applies to
- **`version: 1`** in metadata — increment when making breaking changes
- **`settings.validation: warn`** is recommended to start — it logs issues without blocking writes

## Validating Notes

Check how well existing notes conform to their schema:

```python
# Validate all notes of a type
schema_validate(note_type="Meeting")

# Validate a single note
schema_validate(identifier="meetings/2026-02-10-standup")
```

**Important:** `schema_validate` checks for schema fields as **observation categories** in the note body — e.g., a `status` field expects `- [status] active` as an observation. Fields stored only in frontmatter metadata won't satisfy validation. To pass cleanly, include schema fields as both frontmatter values (for metadata search) and observations (for schema validation).

Validation reports **missing required fields** (as observation categories, or relations
for entity-reference fields) and **invalid enum values**. Undeclared observation categories
and relations are listed as informational "unmatched" items. Scalar values are not
type-checked.

### Handling Validation Results

- **`warn` mode**: Review warnings periodically. Fix notes that are clearly wrong; add optional fields to the schema for legitimate new patterns.
- **`strict` mode**: Use where conformance matters (e.g., automated pipelines consuming notes).

## Detecting Drift

Over time, notes evolve and schemas lag behind. Use `schema_diff` to find divergence:

```python
schema_diff(note_type="Meeting")
```

Diff reports:
- **Fields in notes but not in schema** — candidates for adding to the schema (as optional)
- **Schema fields rarely used** — consider making optional or removing
- **Cardinality changes** — a field that moved between single-value and array

## Schema Evolution

When note structure changes:

1. **Run diff** to see current state: `schema_diff(note_type="Meeting")`
2. **Update the schema note** via `edit_note` with the `metadata` parameter. Top-level
   keys are replaced whole, so pass the complete updated `schema` map along with the new
   `version`:
   ```python
   edit_note(
     identifier="schema/Meeting",
     operation="append",
     content="",
     metadata={
       "version": 2,
       "schema": {
         "topic": "string, what was discussed",
         "date": "string, when it happened",
         "attendees?(array)": "Person, who attended",
         "decisions?(array)": "string, decisions made",
         "location?": "string, where it happened"
       }
     }
   )
   ```
3. **Re-validate** to confirm existing notes still pass: `schema_validate(note_type="Meeting")`
4. **Fix outliers** — update notes that don't conform to the new schema

### Evolution Guidelines

- **Additive changes** (new optional fields) are safe — no version bump needed
- **Breaking changes** (new required fields, removed fields, type changes) should bump `version`
- **Prefer optional over required** — most fields should be optional to start
- **Don't over-constrain** — schemas should describe common structure, not enforce rigid templates
- **Schema as documentation** — even if validation is set to `warn`, the schema serves as living documentation for what notes of that type should contain

## Workflow Summary

```
1. Notice repeated note structure → infer schema (schema_infer)
2. Review + create schema note   → write to schema/ (write_note)
3. Validate existing notes       → check conformance (schema_validate)
4. Fix outliers                  → edit non-conforming notes (edit_note)
5. Periodically check drift      → detect divergence (schema_diff)
6. Evolve schema as needed       → update schema note (edit_note)
```