Historicle REST API Documentation

Complete API reference for Historicle's REST API, enabling remote access to your journal data.

Table of Contents


Overview

Property Value
Base URL https://<server>:11435 (TLS) or http://<server>:11435
API Version v1
Authentication Bearer token or query parameter
Content-Type application/json (unless otherwise noted)

TLS / HTTPS

By default, the server uses HTTPS with a self-signed certificate. This provides encrypted communication between your devices, keeping your journal data private on your local network.

Why self-signed certificates are safe for local use:

  • Your data is still encrypted in transit, just like any HTTPS connection
  • The certificate is generated locally on your machine and never leaves your network
  • You're connecting to your own server, so there's no risk of connecting to an imposter
  • Commercial certificates require a public domain name, which isn't applicable for local network servers

Browser access: The first time you visit the server URL in a browser, you'll see a security warning like "Your connection is not private" or "This site's security certificate is not trusted." This is expected. Click "Advanced" and then "Proceed to [IP address]" (or similar) to continue. You only need to do this once per browser.

curl access: Add the -k flag to skip certificate verification:

curl -k https://10.0.0.217:11435/api/v1/info

Authentication

All endpoints except /api/v1/info require authentication via API key.

API Key Format

hist_<32-character-random-string>

Header Authentication (Preferred)

Authorization: Bearer hist_abc123...

Query Parameter Authentication

For endpoints that can't send headers (e.g., <img> tags):

https://server:11435/api/v1/media/123?api_key=hist_abc123...

API Key Scopes

Scope Permissions
query Read-only access to entries, people, insights, conversations
create_entry Create new entries and people
manage_entries Update and delete entries, conversations, feedback
write Upload and delete media
admin Full access to all endpoints

Authentication Errors

Status Description
401 Missing API key, invalid key, or expired key
403 Insufficient scope for the requested operation

Error Response Format

All errors follow OpenAI-compatible format:

{
  "error": {
    "message": "Human-readable error description",
    "type": "error_type",
    "code": "error_code"
  }
}

Common Status Codes

Code Description
400 Bad Request - Invalid parameters
401 Unauthorized - Authentication failed
403 Forbidden - Insufficient permissions
404 Not Found - Resource doesn't exist
429 Too Many Requests - Rate limited
500 Internal Server Error
503 Service Unavailable - Required service not ready

Endpoints

Health & Server Info

GET /api/v1/info

Server information for discovery/pairing. No authentication required.

Response:

{
  "name": "Historicle on MacBook-Pro",
  "version": "0.1.0",
  "api_version": "v1",
  "openai_compatible": true,
  "base_url": "https://10.0.0.217:11435"
}

curl:

curl -k https://10.0.0.217:11435/api/v1/info

GET /api/v1/health

Health check with system capabilities.

Scope: query

Response:

{
  "status": "ok",
  "version": "0.1.0",
  "capabilities": {
    "rag_enabled": true,
    "llm_loaded": true,
    "embedding_model": true
  },
  "entries_count": 245,
  "uptime_seconds": 3600
}

Entries

GET /api/v1/entries

List entries with pagination.

Scope: query

Query Parameters:

Parameter Type Default Description
limit int 20 Results per page (max 100)
offset int 0 Pagination offset
start_date RFC 3339 - Filter entries after date
end_date RFC 3339 - Filter entries before date

Response:

{
  "entries": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "content": "Today was a good day...",
      "created_at": "2024-12-24T10:30:00Z",
      "modified_at": "2024-12-24T10:30:00Z",
      "word_count": 156
    }
  ],
  "total": 245,
  "limit": 20,
  "offset": 0
}

curl:

curl -k -H "Authorization: Bearer hist_<key>" \
  "https://server:11435/api/v1/entries?limit=20"

POST /api/v1/entries

Create a new entry.

Scope: create_entry

Request Body:

{
  "content": "Today I went to the park with @Alice...",
  "created_at": "2024-12-24T10:30:00Z"
}
Field Type Required Description
content string Yes Entry text (supports @mentions)
created_at RFC 3339 No Defaults to current time

Response (201):

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "content": "Today I went to the park with @Alice...",
  "created_at": "2024-12-24T10:30:00Z",
  "modified_at": "2024-12-24T10:30:00Z",
  "word_count": 45
}

GET /api/v1/entries/recent

Get most recent entries.

Scope: query

Query Parameters:

Parameter Type Default Description
limit int 10 Number of entries (max 100)

POST /api/v1/entries/search

Search entries by text or semantic similarity.

Scope: query

Request Body:

{
  "query": "park visit with family",
  "semantic": true,
  "limit": 10,
  "date_range": {
    "start": "2024-01-01",
    "end": "2024-12-31"
  }
}
Field Type Default Description
query string Required Search query
semantic bool false Use semantic search (requires embedding model)
limit int 10 Max results
date_range object - Optional date filter

Response:

{
  "results": [
    {
      "entry": { ... },
      "relevance_score": 0.92,
      "excerpt": "I went to the park and saw..."
    }
  ],
  "total": 5
}

GET /api/v1/entries/:id

Get a specific entry by ID.

Scope: query


PUT /api/v1/entries/:id

Update an entry.

Scope: manage_entries

Request Body:

{
  "content": "Updated entry content..."
}

DELETE /api/v1/entries/:id

Delete an entry and associated media.

Scope: manage_entries

Response: 204 No Content


History & Statistics

GET /api/v1/history/years

Get years with entry counts.

Scope: query

Response:

[
  {"year": 2024, "count": 156},
  {"year": 2023, "count": 234}
]

GET /api/v1/history/stats/:year

Get daily statistics for a year.

Scope: query

Query Parameters:

Parameter Type Description
emotion string Filter by dominant emotion

Response:

[
  {
    "date": "2024-12-24",
    "word_count": 456,
    "entry_count": 2,
    "dominant_emotion": "joy"
  }
]

GET /api/v1/history/entries/:date

Get entries for a specific date (YYYY-MM-DD format).

Scope: query


Timeline

GET /api/v1/timeline

Get timeline entries with related data (people, media, insights).

Scope: query

Query Parameters:

Parameter Type Default Description
limit int 20 Results per page (max 100)
offset int 0 Pagination offset
start_date YYYY-MM-DD - Start date filter
end_date YYYY-MM-DD - End date filter
person_id UUID - Filter by mentioned person
interest_id UUID - Filter by mentioned interest
emotion string - Filter by dominant emotion

Response:

{
  "entries": [
    {
      "entry": { "id": "...", "content": "...", ... },
      "people": [{ "id": "...", "name": "Alice" }],
      "media": [{ "id": "...", "thumbnail_url": "..." }],
      "insights": { "dominant_emotion": "joy", ... }
    }
  ],
  "has_more": true,
  "total_count": 456
}

GET /api/v1/timeline/date-range

Get the date range of all entries.

Scope: query

Response:

{
  "earliest": "2020-01-15T10:30:00Z",
  "latest": "2024-12-24T10:30:00Z"
}

GET /api/v1/timeline/emotions

Get available emotions for filtering.

Scope: query

Response:

["joy", "sadness", "anger", "fear", "surprise", "neutral"]

People (Dramatis Personae)

GET /api/v1/people

List all people.

Scope: query

Response:

{
  "people": [
    {
      "id": "person-uuid",
      "name": "Alice",
      "bio": "My best friend from college",
      "tags": ["friend", "college"],
      "metadata": {
        "how_met": "University",
        "relationship_type": "friend"
      },
      "created_at": "2024-01-01T00:00:00Z",
      "modified_at": "2024-01-01T00:00:00Z"
    }
  ],
  "total": 42
}

POST /api/v1/people

Create a new person.

Scope: create_entry

Request Body:

{
  "name": "Bob",
  "bio": "My brother",
  "tags": ["family"],
  "metadata": {
    "how_met": "Family member",
    "relationship_context": "Sibling"
  }
}

GET /api/v1/people/search

Search people by name.

Scope: query

Query Parameters:

Parameter Type Required Description
query string Yes Search term

GET /api/v1/people/:id

Get a specific person.

Scope: query


PUT /api/v1/people/:id

Update a person.

Scope: manage_entries


DELETE /api/v1/people/:id

Delete a person.

Scope: manage_entries


GET /api/v1/people/:id/entries

Get entry IDs where a person is mentioned.

Scope: query

Response:

[
  "550e8400-e29b-41d4-a716-446655440000",
  "550e8400-e29b-41d4-a716-446655440001"
]

Interests

Interests are topics, hobbies, or concepts that can be referenced in journal entries using #hashtag syntax. Like people, interests can have their own metadata including resources, notes, and visual customization.

GET /api/v1/interests

List all interests.

Scope: query

Response:

{
  "interests": [
    {
      "id": "interest-uuid",
      "name": "Photography",
      "description": "Landscape and nature photography",
      "color": "#22c55e",
      "icon": "mdi:camera",
      "metadata": {
        "started_date": "2024-01-15",
        "resources": [
          {
            "title": "Photography 101",
            "url": "https://example.com/course",
            "resource_type": "course",
            "notes": "Great beginner course"
          }
        ],
        "notes": "Learning composition and lighting"
      },
      "created_at": "2024-01-01T00:00:00Z",
      "modified_at": "2024-01-01T00:00:00Z"
    }
  ],
  "total": 15
}

POST /api/v1/interests

Create a new interest.

Scope: create_entry

Request Body:

{
  "name": "Hiking",
  "description": "Mountain trails and outdoor exploration",
  "color": "#10b981",
  "icon": "mdi:hiking",
  "metadata": {
    "started_date": "2023-06-01",
    "resources": [
      {
        "title": "Best Trails App",
        "url": "https://trails.example.com",
        "resource_type": "tool",
        "notes": "Helpful for finding new routes"
      }
    ],
    "notes": "Goal: Complete 50 trails this year"
  }
}
Field Type Required Description
name string Yes Interest name (max 500 chars)
description string No Interest description (max 10,000 chars)
color string No Hex color code (e.g., #22c55e)
icon string No Iconify icon name (e.g., mdi:camera)
metadata object No Interest metadata (see below)

InterestMetadata Structure:

Field Type Description
started_date string When the user started this interest (YYYY-MM-DD)
resources array Related resources (books, websites, courses, etc.)
notes string Personal notes (max 10,000 chars)

InterestResource Structure:

Field Type Required Description
title string Yes Resource title (max 500 chars)
url string No Resource URL (max 2,000 chars)
resource_type string Yes Type of resource (see below)
notes string No Notes about this resource

ResourceType Values:

  • book - Books and written materials
  • website - Websites and online resources
  • course - Online or offline courses
  • video - Video content
  • podcast - Podcast episodes or series
  • article - Articles and blog posts
  • tool - Tools and applications
  • other - Other resource types

Response (201):

{
  "id": "interest-uuid",
  "name": "Hiking",
  "description": "Mountain trails and outdoor exploration",
  "color": "#10b981",
  "icon": "mdi:hiking",
  "metadata": {
    "started_date": "2023-06-01",
    "resources": [
      {
        "title": "Best Trails App",
        "url": "https://trails.example.com",
        "resource_type": "tool",
        "notes": "Helpful for finding new routes"
      }
    ],
    "notes": "Goal: Complete 50 trails this year"
  },
  "created_at": "2024-12-24T10:30:00Z",
  "modified_at": "2024-12-24T10:30:00Z"
}

GET /api/v1/interests/search

Search interests by name.

Scope: query

Query Parameters:

Parameter Type Required Description
query string Yes Search term (prefix match)

Response:

[
  {
    "id": "interest-uuid",
    "name": "Photography",
    "description": "Landscape and nature photography",
    "color": "#22c55e",
    "icon": "mdi:camera",
    "metadata": { ... },
    "created_at": "2024-01-01T00:00:00Z",
    "modified_at": "2024-01-01T00:00:00Z"
  }
]

Note: Returns up to 10 results matching the query prefix.


GET /api/v1/interests/:id

Get a specific interest.

Scope: query

Response:

{
  "id": "interest-uuid",
  "name": "Photography",
  "description": "Landscape and nature photography",
  "color": "#22c55e",
  "icon": "mdi:camera",
  "metadata": {
    "started_date": "2024-01-15",
    "resources": [],
    "notes": "Learning composition and lighting"
  },
  "created_at": "2024-01-01T00:00:00Z",
  "modified_at": "2024-01-01T00:00:00Z"
}

PUT /api/v1/interests/:id

Update an interest.

Scope: manage_entries

Request Body:

{
  "name": "Photography",
  "description": "Updated description",
  "color": "#3b82f6",
  "icon": "mdi:camera-enhance",
  "metadata": {
    "started_date": "2024-01-15",
    "resources": [
      {
        "title": "Advanced Photography",
        "url": "https://example.com/advanced",
        "resource_type": "course",
        "notes": "Next level techniques"
      }
    ],
    "notes": "Progressing to advanced techniques"
  }
}

Response:

{
  "id": "interest-uuid",
  "name": "Photography",
  "description": "Updated description",
  "color": "#3b82f6",
  "icon": "mdi:camera-enhance",
  "metadata": { ... },
  "created_at": "2024-01-01T00:00:00Z",
  "modified_at": "2024-12-24T10:30:00Z"
}

DELETE /api/v1/interests/:id

Delete an interest.

Scope: manage_entries

Response: 204 No Content

Note: Deleting an interest will cascade and remove all entry-interest associations.


GET /api/v1/interests/:id/entries

Get entry IDs where an interest is mentioned.

Scope: query

Response:

[
  "550e8400-e29b-41d4-a716-446655440000",
  "550e8400-e29b-41d4-a716-446655440001"
]

Note: Returns an array of entry UUIDs that contain #hashtag references to this interest.


Media

GET /api/v1/media/:id

Serve original media file.

Scope: query

Response: Binary file with appropriate Content-Type

Note: For <img> tags, use query parameter auth:


GET /api/v1/media/:id/thumbnail

Serve thumbnail image (always JPEG, max 400x400).

Scope: query


GET /api/v1/media/:id/info

Get media metadata without the file.

Scope: query

Response:

{
  "id": "media-uuid",
  "entry_id": "entry-uuid",
  "format": "jpeg",
  "width": 1920,
  "height": 1080,
  "file_size": 456789,
  "created_at": "2024-12-24T10:30:00Z",
  "thumbnail_url": "/api/v1/media/media-uuid/thumbnail",
  "original_url": "/api/v1/media/media-uuid"
}

GET /api/v1/entries/:entry_id/media

List all media for an entry.

Scope: query


POST /api/v1/entries/:entry_id/media

Upload media files (multipart/form-data).

Scope: write

Content-Type: multipart/form-data

Form Fields:

Field Description
file or files Image file(s) to upload

Response:

{
  "attached": [{ "id": "...", ... }],
  "failed": []
}

POST /api/v1/entries/:entry_id/media/base64

Upload media as base64 (better for mobile Safari).

Scope: write

Request Body:

{
  "filename": "photo.jpg",
  "data": "base64_encoded_image_data..."
}

Max Size: 50MB per file


DELETE /api/v1/media/:id

Delete a media attachment.

Scope: write


Chat & Conversations

GET /api/v1/chat/conversations

List all conversations.

Scope: query

Query Parameters:

Parameter Type Default Description
limit int - Max conversations

Response:

[
  {
    "id": "conv-uuid",
    "title": "Planning vacation",
    "created_at": "2024-12-24T10:30:00Z",
    "modified_at": "2024-12-24T10:30:00Z",
    "message_count": 5
  }
]

POST /api/v1/chat/conversations

Create a new conversation.

Scope: manage_entries

Request Body:

{
  "title": "Vacation planning"
}

GET /api/v1/chat/conversations/:id

Get conversation with messages.

Scope: query

Response:

{
  "id": "conv-uuid",
  "title": "Planning vacation",
  "messages": [
    {
      "id": "msg-uuid",
      "role": "user",
      "content": "Where should I go?",
      "created_at": "2024-12-24T10:30:00Z",
      "sources": []
    },
    {
      "id": "msg-uuid-2",
      "role": "assistant",
      "content": "Based on your entries...",
      "sources": [
        {
          "entry_id": "entry-uuid",
          "date": "2024-06-15",
          "excerpt": "I really enjoyed..."
        }
      ]
    }
  ]
}

PATCH /api/v1/chat/conversations/:id

Update conversation title.

Scope: manage_entries


DELETE /api/v1/chat/conversations/:id

Delete a conversation.

Scope: manage_entries


POST /api/v1/chat/conversations/:id/messages

Send a message with streaming response (Server-Sent Events).

Scope: query

Request Body:

{
  "content": "What did I do last summer?",
  "use_rag": true
}

Response: Server-Sent Events stream

SSE Event Types:

Event Description
user_message User message saved
content_delta Token chunk from LLM
message_complete Generation finished
assistant_message Full assistant response
sources RAG sources used
error Error occurred

GET /api/v1/chat/conversations/search

Search conversations.

Scope: query

Query Parameters:

Parameter Type Default Description
q string Required Search query
type string "hybrid" "semantic", "text", or "hybrid"
limit int 10 Max results

GET /api/v1/chat/embedding-status

Get embedding status for chat messages.

Scope: query


POST /api/v1/chat/embed

Embed pending conversation messages.

Scope: manage_entries


Insights

GET /api/v1/insights/status

Get insights analysis status.

Scope: query

Response:

{
  "total_entries": 245,
  "analyzed_entries": 220,
  "unanalyzed_entries": 25,
  "coverage_percent": 89.8
}

GET /api/v1/insights/stats

Get aggregate text statistics.

Scope: query


GET /api/v1/insights/trends

Get text trends over time.

Scope: query


GET /api/v1/entries/:entry_id/insights

Get insights for a specific entry.

Scope: query

Response:

{
  "entry_id": "entry-uuid",
  "dominant_emotion": "joy",
  "emotion_scores": {
    "joy": 0.8,
    "sadness": 0.1,
    "anger": 0.05,
    "fear": 0.03,
    "surprise": 0.02
  },
  "word_count": 456,
  "analysis_timestamp": "2024-12-24T10:30:00Z"
}

Writing Coach

POST /api/v1/coach/analyze/:entry_id

Analyze entry with heuristics (fast, no LLM required).

Scope: query

Response:

{
  "entry_id": "entry-uuid",
  "feedback": [
    {
      "id": "feedback-uuid",
      "category": "emotion_depth",
      "title": "Explore your feelings",
      "suggestion": "How did these events make you feel?",
      "priority": "high",
      "highlight_start": 45,
      "highlight_end": 78,
      "acknowledged": false,
      "dismissed": false
    }
  ],
  "emotion_depth_score": 42.5
}

POST /api/v1/coach/analyze-llm/:entry_id

Analyze entry with LLM (richer feedback, requires loaded model).

Scope: query


GET /api/v1/entries/:entry_id/feedback

Get feedback for an entry.

Scope: query


PATCH /api/v1/coach/feedback/:feedback_id

Update feedback status.

Scope: manage_entries

Request Body:

{
  "acknowledged": true,
  "dismissed": false
}

GET /api/v1/coach/focus

Get active writing focus.

Scope: query


POST /api/v1/coach/focus

Set writing focus area.

Scope: manage_entries

Request Body:

{
  "focus_area": "similes",
  "scope": "week"
}

Focus Areas: emotional_depth, sensory_details, similes, metaphors, narrative_flow, character_depth, showing_not_telling, specificity


DELETE /api/v1/coach/focus

Clear active focus.

Scope: manage_entries


GET /api/v1/coach/focus/progress/:focus_area

Get progress on a focus area.

Scope: query


Life Story Prompts

GET /api/v1/prompts

List prompts with filtering.

Scope: query

Query Parameters:

Parameter Type Default Description
category string - Filter by category
include_dismissed bool false Include dismissed prompts
include_used bool false Include used prompts

GET /api/v1/prompts/random

Get a random available prompt.

Scope: query

Query Parameters:

Parameter Type Description
category string Optional category filter

GET /api/v1/prompts/:id

Get a specific prompt.

Scope: query


POST /api/v1/prompts/:id/dismiss

Dismiss a prompt.

Scope: manage_entries


POST /api/v1/prompts/:id/undismiss

Undismiss a prompt.

Scope: manage_entries


POST /api/v1/prompts/:id/used

Mark prompt as used with an entry.

Scope: manage_entries

Request Body:

{
  "entry_id": "entry-uuid"
}

GET /api/v1/prompts/stats

Get prompt usage statistics.

Scope: query


GET /api/v1/prompts/categories

Get all categories with counts.

Scope: query


POST /api/v1/prompts/reset-dismissed

Reset all dismissed prompts.

Scope: manage_entries


Photos

GET /api/v1/photos

Get paginated photos with various viewing modes.

Scope: query

Query Parameters:

Parameter Type Default Description
limit int 20 Results per page (max 100)
offset int 0 Pagination offset
mode string "chronological" View mode (see below)
shuffle_seed int - Seed for reproducible shuffles
start_date YYYY-MM-DD - Start date filter
end_date YYYY-MM-DD - End date filter
person_id UUID - Filter by person
emotion string - Filter by emotion

View Modes: chronological, shuffle, clustered, seasons, emotion, people, similar


GET /api/v1/photos/date-range

Get date range of all photos.

Scope: query


OpenAI-Compatible API

These endpoints provide compatibility with tools expecting OpenAI's API format.

GET /v1/models

List available models.

Scope: query

Response:

{
  "object": "list",
  "data": [
    {
      "id": "historicle-local",
      "object": "model",
      "created": 1734787200,
      "owned_by": "historicle"
    }
  ]
}

POST /v1/chat/completions

Generate chat completions with RAG support.

Scope: query

Request Body:

{
  "model": "historicle-local",
  "messages": [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "What did I do last summer?"}
  ],
  "stream": false,
  "temperature": 0.7,
  "max_tokens": 1024,
  "historicle_options": {
    "use_rag": true,
    "rag_top_k": 5,
    "date_range": {
      "start": "2024-06-01",
      "end": "2024-08-31"
    }
  }
}

historicle_options:

Field Type Default Description
use_rag bool true Enable RAG context retrieval
rag_top_k int 5 Number of entries to retrieve
date_range object - Optional date filtering

Response (non-streaming):

{
  "id": "chatcmpl-uuid",
  "object": "chat.completion",
  "created": 1734787200,
  "model": "historicle-local",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Based on your journal entries..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 150,
    "completion_tokens": 200,
    "total_tokens": 350
  },
  "historicle_sources": [
    {
      "entry_id": "entry-uuid",
      "date": "2024-07-15",
      "excerpt": "Went to the beach with family...",
      "relevance_score": 0.92
    }
  ]
}

Additional Information

Date/Time Formats

Format Example Usage
RFC 3339 2024-12-24T10:30:00Z API timestamps
Date only 2024-12-24 Date filters, history endpoints

Pagination

All list endpoints support pagination:

{
  "entries": [...],
  "total": 245,
  "limit": 20,
  "offset": 0
}
  • Default limit: 20
  • Maximum limit: 100
  • Use offset for pagination

Rate Limiting

Requests are rate-limited per API key. If exceeded:

{
  "error": {
    "message": "Rate limit exceeded",
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded"
  }
}

Server-Sent Events (SSE)

Streaming endpoints use SSE format:

event: content_delta
data: {"type":"content_delta","content":"Hello "}

event: content_delta
data: {"type":"content_delta","content":"world!"}

event: message_complete
data: {"type":"message_complete"}

CORS

CORS headers are configured for all origins. OPTIONS preflight requests don't require authentication.


Quick Start Examples

Create an Entry

curl -k -X POST \
  -H "Authorization: Bearer hist_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"content":"Today I learned about the Historicle API!"}' \
  https://10.0.0.217:11435/api/v1/entries

Search Entries

curl -k -X POST \
  -H "Authorization: Bearer hist_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"query":"vacation","semantic":true,"limit":5}' \
  https://10.0.0.217:11435/api/v1/entries/search

Chat with RAG

curl -k -X POST \
  -H "Authorization: Bearer hist_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "historicle-local",
    "messages": [{"role":"user","content":"What did I do last week?"}],
    "stream": false,
    "historicle_options": {"use_rag": true}
  }' \
  https://10.0.0.217:11435/v1/chat/completions

Upload Photo

curl -k -X POST \
  -H "Authorization: Bearer hist_your_key_here" \
  -F "file=@photo.jpg" \
  https://10.0.0.217:11435/api/v1/entries/ENTRY_ID/media

MCP Server (Claude Desktop Integration)

Historicle includes an MCP (Model Context Protocol) server that allows AI assistants like Claude Desktop to interact with your journal data directly.

Requires: Pro license

How It Works

The MCP server runs as a headless process using stdio transport (JSON-RPC over stdin/stdout). Claude Desktop launches it automatically when configured.

Setup for Claude Desktop

  1. Locate your Claude Desktop config file:

    ~/Library/Application Support/Claude/claude_desktop_config.json
  2. Add the Historicle MCP server configuration:

    {
      "mcpServers": {
        "historicle": {
          "command": "/Applications/Historicle.app/Contents/MacOS/historicle",
          "args": ["--mcp-stdio"]
        }
      }
    }
  3. Restart Claude Desktop

Running Manually (Testing)

/Applications/Historicle.app/Contents/MacOS/historicle --mcp-stdio

The server communicates via stdin/stdout using JSON-RPC 2.0.

Available MCP Tools

Tool Description
search_entries Semantic search across journal entries
list_entries List recent journal entries
get_entry Get a specific entry by ID
list_people List people in the journal
get_person Get details about a specific person
list_interests List interests/hashtags
get_interest Get details about a specific interest

Example Interactions

Once configured, you can ask Claude Desktop questions like:

  • "What have I written about recently?"
  • "Search my journal for entries about hiking"
  • "Who are the people mentioned in my journal?"
  • "What topics do I write about most?"

Claude will use the MCP tools to query your local Historicle database and provide answers based on your actual journal content.

Troubleshooting

"MCP server requires a Pro license"

  • Upgrade to Pro in Historicle Settings to enable MCP functionality

Server not connecting

  • Verify the path to the Historicle binary is correct
  • Check that Historicle is installed in /Applications
  • Ensure no other instance of Historicle MCP is running

Logs

  • MCP server logs go to stderr to keep stdout clean for JSON-RPC
  • Check Console.app or run manually in Terminal to see logs