Skip to main content
Observations are individual memories stored during a session. They can represent decisions, bugs, patterns, or any notable information.

Add Observation

POST /observations Create a new observation or update an existing one via deduplication.

Request Body

session_id
string
required
Session ID this observation belongs to
type
string
required
Observation type: manual, architecture, bug, decision, pattern, config, discovery, learning, passive
title
string
required
Short title for the observation (max 200 chars)
content
string
required
Full observation content (max 2000 chars, truncated automatically)
tool_name
string
Tool that generated this observation (e.g., “bash”, “edit”, “grep”)
project
string
Project name for filtering
scope
string
default:"project"
Scope: project or personal
topic_key
string
Topic key for grouping related observations (e.g., “architecture/auth-flow”)

Response

id
integer
The observation ID (auto-incremented)
status
string
Always “saved”

Example

curl -X POST http://127.0.0.1:7437/observations \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "session-abc123",
    "type": "bug",
    "title": "Auth token expiration issue",
    "content": "Users were experiencing unexpected logouts due to token expiration not being handled properly. Fixed by implementing refresh token rotation.",
    "project": "engram",
    "scope": "project"
  }'
{
  "id": 42,
  "status": "saved"
}

Passive Capture

POST /observations/passive Automatically extract and save learnings from structured text (e.g., session summaries).

Request Body

session_id
string
required
Session ID
content
string
required
Text containing ”## Key Learnings:” or ”## Aprendizajes:” section
project
string
Project name
source
string
Source identifier (e.g., “subagent-stop”, “session-end”)

Response

extracted
integer
Total learnings found in the text
saved
integer
New observations created
duplicates
integer
Learnings skipped (already exist)

Example

curl -X POST http://127.0.0.1:7437/observations/passive \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "session-abc123",
    "project": "engram",
    "content": "## Key Learnings:\n\n1. SQLite FTS5 requires careful query sanitization\n2. Deduplication works best with content hashing\n3. Topic keys enable cross-session continuity"
  }'
{
  "extracted": 3,
  "saved": 3,
  "duplicates": 0
}

Get Recent Observations

GET /observations/recent Retrieve recent observations with optional filtering.

Query Parameters

project
string
Filter by project name
scope
string
Filter by scope: project or personal
limit
integer
default:"20"
Maximum observations to return (1-100)

Response

Returns an array of observations (see schema below).

Example

curl "http://127.0.0.1:7437/observations/recent?project=engram&limit=5"
[
  {
    "id": 42,
    "session_id": "session-abc123",
    "type": "bug",
    "title": "Auth token expiration issue",
    "content": "Users were experiencing unexpected logouts...",
    "tool_name": null,
    "project": "engram",
    "scope": "project",
    "topic_key": null,
    "revision_count": 1,
    "duplicate_count": 1,
    "last_seen_at": null,
    "created_at": "2024-03-15 14:30:00",
    "updated_at": "2024-03-15 14:30:00",
    "deleted_at": null
  }
]

Get Single Observation

GET /observations/{id} Retrieve a specific observation by ID.

Path Parameters

id
integer
required
Observation ID

Response

Returns a single observation object (see schema below).

Example

curl http://127.0.0.1:7437/observations/42

Update Observation

PATCH /observations/{id} Update an existing observation. All fields are optional.

Path Parameters

id
integer
required
Observation ID to update

Request Body

type
string
New observation type
title
string
New title
content
string
New content
project
string
New project name
scope
string
New scope
topic_key
string
New topic key

Response

Returns the updated observation object.

Example

curl -X PATCH http://127.0.0.1:7437/observations/42 \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Auth token expiration fix",
    "type": "fix"
  }'

Delete Observation

DELETE /observations/{id} Soft-delete or permanently delete an observation.

Path Parameters

id
integer
required
Observation ID to delete

Query Parameters

hard
boolean
default:"false"
If true, permanently deletes. If false, soft-deletes (sets deleted_at)

Response

id
integer
The observation ID
status
string
Always “deleted”
hard_delete
boolean
Whether this was a permanent deletion

Example

# Soft delete
curl -X DELETE http://127.0.0.1:7437/observations/42

# Hard delete
curl -X DELETE "http://127.0.0.1:7437/observations/42?hard=true"
{
  "id": 42,
  "status": "deleted",
  "hard_delete": false
}

Get Timeline

GET /timeline Get chronological context around a specific observation.

Query Parameters

observation_id
integer
required
The anchor observation ID
before
integer
default:"5"
Number of observations to retrieve before the anchor
after
integer
default:"5"
Number of observations to retrieve after the anchor

Response

focus
object
The anchor observation
before
array
Observations before the anchor (chronological order)
after
array
Observations after the anchor (chronological order)
session_info
object
Session containing the anchor observation
total_in_range
integer
Total observations in the session

Example

curl "http://127.0.0.1:7437/timeline?observation_id=42&before=3&after=3"
{
  "focus": {
    "id": 42,
    "session_id": "session-abc123",
    "type": "bug",
    "title": "Auth token expiration issue",
    "content": "Users were experiencing unexpected logouts...",
    "created_at": "2024-03-15 14:30:00"
  },
  "before": [
    {
      "id": 39,
      "title": "Implemented refresh token rotation",
      "is_focus": false
    }
  ],
  "after": [
    {
      "id": 43,
      "title": "Added token expiration tests",
      "is_focus": false
    }
  ],
  "session_info": {
    "id": "session-abc123",
    "project": "engram",
    "started_at": "2024-03-15 14:00:00"
  },
  "total_in_range": 15
}

Observation Schema

Complete observation object structure:
interface Observation {
  id: number;
  session_id: string;
  type: string;
  title: string;
  content: string;
  tool_name?: string | null;
  project?: string | null;
  scope: string;  // "project" | "personal"
  topic_key?: string | null;
  revision_count: number;
  duplicate_count: number;
  last_seen_at?: string | null;  // ISO 8601
  created_at: string;  // ISO 8601
  updated_at: string;  // ISO 8601
  deleted_at?: string | null;  // ISO 8601
}

Deduplication

Engram automatically deduplicates observations within a 15-minute window using:
  1. Content hash - Normalized content comparison
  2. Topic key - Same topic = update existing observation
  3. Duplicate tracking - Increments duplicate_count and updates last_seen_at
This prevents noise from repeated observations while preserving evidence of recurrence.

Build docs developers (and LLMs) love