Getting Started
Welcome to MiloNotes
MiloNotes is a privacy-first Android note-taking app with on-device AI, Kanban boards, semantic search, and a full REST API. Your data never leaves your device.
What MiloNotes does
📚Notebook hierarchy — Notebooks → Sections → Sub-Sections → Notes, with a collapsible file tree
✍️Markdown editor — Mermaid diagrams, tables, Wikilinks, syntax highlighting, live preview
🗂️Kanban boards — drag-and-drop tasks linked to notes
🧠On-device AI — Gemini Nano (Pixel 9 / Galaxy S25), semantic search with RAG, memory system
🌐Access everywhere — LAN server, internet tunnel, Cloudflare BYOK, installable PWA
🔌REST API & MCP — full programmatic access with API key auth
Requirements
| Requirement | Minimum | Notes |
| Android | 8.0 (API 26) | All features except on-device AI |
| On-device AI | Android 15 (API 35) | Pixel 9 / Galaxy S25 class devices only |
| Storage | ~100 MB | More for attachments and AI models |
Getting Started
Installation
MiloNotes is available on the Google Play Store. iOS support is coming soon.
Google Play
Search for MiloNotes on the Google Play Store, or use the link on the homepage.
⚠️
MiloNotes requires Android 8.0 or later. On-device AI features require Android 15 and a supported device (Pixel 9 series or Samsung Galaxy S25 series).
Permissions
| Permission | Used for |
| Internet | Tunnel connection, external AI providers |
| Microphone | Voice transcription (optional) |
| Foreground Service | LAN web server, tunnel connection |
| Notifications | Server status, sync progress |
Getting Started
First Launch
When you open MiloNotes for the first time, you'll be taken through a short onboarding flow.
Onboarding
The 5-page onboarding explains the core concepts — notebooks, AI features, LAN/tunnel access, and the API. You can skip it at any time and revisit settings later.
Day View (home screen)
After onboarding, MiloNotes opens to the Day View — a calendar-integrated planner showing today's entries, your note activity, and an AI-generated daily summary.
Bottom navigation
| Tab | Description |
| 📅 Day View | Daily planner, calendar, AI summary |
| 📚 Notebooks | Book-cover grid; tap to open a notebook's file tree |
| 🦊 Milo | AI chat — ask questions grounded in your notes |
| 🗂️ Kanban | Task boards linked to notes |
| 🔍 Search | Full-text and semantic search |
| ⚙️ Settings | AI providers, server, tunnel, API keys, Git sync |
Features
Notebooks
Organise your notes in a familiar binder-style hierarchy. MiloNotes supports unlimited nesting depth — Notebooks → Sections → Sub-Sections → Notes.
The bookshelf
The Notebooks tab shows your notebooks as physical book covers in a 2-column grid. Each cover displays the notebook's color, emoji icon, name, and note count. Tap a cover to open its file tree.
File tree
Inside a notebook you see a collapsible file tree. Tap a folder to expand/collapse it. Tap a note to open it in the editor. Long-press for the context menu.
💡
Tip: Notes can live at any level of the hierarchy — directly in a notebook, or nested inside multiple sub-sections.
Creating structure
- Tap + (notebook icon) in the Notebooks screen to create a new notebook — choose a name, emoji, and color.
- Inside a notebook, use the Create New Folder button in the top bar to add a section.
- Long-press any folder to add a sub-section, rename, or delete it.
- Notes can be moved between notebooks and folders via long-press → Move.
Web UI (file explorer)
The web interface mirrors the mobile tree view — hover over any row to reveal New Note, New Folder, and ⋯ action buttons. Click a note to open it in the editor.
Features
Markdown Editor
MiloNotes uses a full Markdown editor with live preview, powered by CodeMirror 6 in the web UI and a native editor on Android.
Supported syntax
| Syntax | Example |
| Headings | # H1 ## H2 ### H3 |
| Bold / Italic | **bold** *italic* ***both*** |
| Lists | - item 1. item - [x] task |
| Code | `inline` ```lang block``` |
| Tables | GFM pipe tables |
| Links | [text](url) |
| Images |  |
| Blockquotes | > quote |
| Horizontal rule | --- |
Mermaid diagrams
Wrap Mermaid markup in a fenced code block with the mermaid language identifier:
```mermaid
flowchart LR
A[Start] --> B{Decision}
B -- Yes --> C[Do thing]
B -- No --> D[Skip]
```
Supported diagram types: flowchart, sequenceDiagram, gantt, mindmap, classDiagram, erDiagram.
Mindmaps
Use the mindmap or markmap language identifier — it routes to Mermaid's native mindmap renderer:
```mindmap
root((MiloNotes))
Features
Notebooks
Kanban
AI
Access
LAN
Tunnel
```
Wikilinks & autocomplete
Type [[ anywhere in the editor to open an autocomplete dropdown that searches your notes by title prefix. Select a note to insert a [[Note Title]] link. These links are rendered as clickable references and power the Knowledge Graph.
YAML front matter
Notes exported via Git sync include YAML front matter:
---
title: Wave-particle duality
tags: [physics, quantum]
created: 2026-03-20T10:00:00Z
updated: 2026-03-20T14:30:00Z
---
Features
Kanban Boards
Create drag-and-drop task boards to manage projects alongside your notes.
Structure
- Board — top-level container (e.g. "Sprint 1", "Personal Tasks")
- Column — a swimlane (e.g. "Backlog", "In Progress", "Done")
- Card — a task with title, description, due date, and priority
Creating a board
Tap the + button on the Kanban screen. Give the board a title. You can optionally link it to a note — the board will then appear as a linked resource inside that note.
Card properties
| Property | Description |
| Title | Required. Short description of the task. |
| Description | Optional longer text or Markdown notes. |
| Due date | YYYY-MM-DD format. Shown as a badge on the card. |
| Priority | low | medium | high |
| Linked note | Associates the card with a specific note. |
Moving cards
Drag cards between columns on mobile. In the web UI, use the Move option from the card context menu, or via the REST API.
Features
Knowledge Graph
Visualise the connections between your notes as an interactive force-directed graph.
How it works
Every [[Wikilink]] in your notes creates a directed edge in the graph. The Knowledge Graph screen renders all notes as nodes and all Wikilink relationships as edges, letting you explore how your knowledge is connected.
Using the graph
- Tap a node — opens the note in the editor
- Pinch to zoom — zoom in/out on the graph
- Drag — pan around the graph
- Node size — larger nodes have more incoming links (more referenced)
💡
The more Wikilinks you use in your notes, the more useful the graph becomes. Link related concepts liberally.
Features
Search
MiloNotes has two complementary search systems — full-text search and semantic (AI) search.
Full-text search (FTS4)
Powered by SQLite FTS4. Searches all note titles and content instantly. Results are ranked by relevance and shown with a highlighted snippet of the matching text.
Access via the Search tab or with the keyboard shortcut in the web UI.
Semantic search
Ask natural language questions — "what did I write about wave functions?" — and MiloNotes will find the most semantically relevant notes even if they don't contain those exact words.
Semantic search uses MediaPipe TextEmbedder (MiniLM TFLite model) to generate embeddings on-device. Embeddings are created in the background when notes are saved and on first launch for existing notes.
⚠️
Semantic search requires the app to be in the foreground to generate embeddings. On first launch, indexing happens progressively — all notes will be indexed within a few minutes of use.
RAG (Retrieval-Augmented Generation)
When you ask Milo AI a question, it automatically performs a semantic search to retrieve relevant notes and includes them as context for the AI response. This is how Milo can give answers grounded in your specific notes.
Features
Tags
Organise notes with coloured tags. MiloNotes also suggests tags automatically based on note content.
Creating tags
Tags are created globally in Settings → Tags or inline when editing a note. Each tag has a name and a hex colour.
Applying tags
Open any note → tap the tag icon in the toolbar → select tags from the list. Tags appear as coloured pills in note list views.
AI tag suggestions
After saving a note, MiloNotes analyses the content and suggests relevant tags. Suggested tags appear in a "Suggested" section in the tag panel. Tap Accept to apply or Dismiss to ignore.
Features
Day Planner
The Day View is a calendar-integrated daily planner that is the home screen of MiloNotes.
Calendar strip
A horizontal scrollable strip shows the current week. Tap any date to jump to that day's entries.
Day entries
Three types of quick entries:
| Type | Description |
| 📝 Note | Quick freeform text note for the day |
| ⏰ Reminder | A timed reminder shown in the calendar strip |
| ☑️ To-do | A checkable task item |
Note activity feed
Below your entries, MiloNotes shows which notes you opened or edited today — a passive log of your note activity per day.
AI daily summary
At the end of the day (or on demand), Milo AI generates a short summary of your day's entries and note activity. The summary is stored per-day and can be reviewed later.
Features
Attachments
Attach images and files to any note. Attachments are stored on your device and served by the built-in web server.
Attaching files
In the note editor, tap the Attach button in the toolbar. Choose an image from your gallery or files app. The file is saved to the app's private storage and a Markdown image reference is inserted at the cursor.
Supported types
Images: image/png, image/jpeg, image/gif, image/webp, image/svg+xml. Other binary files can be attached but are not rendered inline.
Uploading via API
Use the Attachments API to upload files programmatically. The API returns a URL (/api/attachments/{id}/file) you can embed in Markdown.
💡
Attachments are stored in the app's private directory. They are not included in Git sync, but are included in the ZIP export.
Features
Git Sync
Push all your notes to a Git repository as Markdown files. Works with GitHub, GitLab, Gitea, or any Git host.
Setup
- Go to Settings → Git Sync
- Enter your repository URL (HTTPS or SSH)
- Choose authentication: Personal Access Token or SSH key
- Set the branch (default:
main)
- Tap Sync Now to do a first clone/push
File structure
Notes are written as {notebook}/{section}/{note-title}.md with YAML front matter. A milo-settings.json file at the root stores notebook and tag metadata.
Auto-sync
Enable Auto-sync in Git settings to push changes automatically when your phone has a network connection. Uses WorkManager with a CONNECTED network constraint.
⚠️
SSH private keys and Personal Access Tokens are stored encrypted via the Android Keystore. They are never written to disk in plaintext.
Features
AI Features
MiloNotes has a layered AI system — on-device inference as the privacy-safe default, with optional external providers for more power.
On-device AI (Gemini Nano)
Devices running Android 15 with Gemini Nano available (Pixel 9 series, Samsung Galaxy S25 series) get fully offline AI:
- Chat with Milo about your notes
- Note summarisation
- Content rewriting and improvement
- Key points extraction
- AI-suggested tags
⚠️
On-device AI inference requires the app to be in the foreground. If you access the web UI while the app is backgrounded, AI endpoints return 503 Service Unavailable.
External AI providers
Connect any OpenAI-compatible API in Settings → AI Providers:
| Provider | Type | Base URL |
| Ollama | Local LLM | http://localhost:11434 |
| OpenAI | Cloud | https://api.openai.com/v1 |
| Anthropic | Cloud | https://api.anthropic.com |
| Google Gemini | Cloud | https://generativelanguage.googleapis.com/v1beta |
| Open WebUI | Self-hosted | Your Open WebUI URL |
| Any OpenAI-compatible | Any | Custom base URL |
Task routing
In Settings → AI Task Defaults, choose which provider handles each task type — chat, summarise, rewrite, key points, and embeddings — independently.
Memory system
Milo AI extracts key facts from your notes into a memory layer — a structured set of facts about you, your projects, and your knowledge. These memories persist across sessions and provide Milo with long-term context for personalised answers.
Browse and delete memories in Settings → Memories.
Semantic embeddings
Every note is indexed with a MediaPipe MiniLM TFLite embedding vector stored on-device. These power semantic search and RAG (Retrieval-Augmented Generation) — ensuring Milo's answers reference your actual notes.
Access & Connectivity
LAN Server
MiloNotes runs a built-in Ktor web server that serves the full React web app and REST API over your local Wi-Fi network.
Enabling
- Go to Settings → Web Server
- Toggle Enable LAN Server on
- The server starts immediately and shows the local URL (e.g.
http://192.168.1.42:8080)
Accessing the web UI
Open the displayed URL in any browser on the same Wi-Fi network. The web app is a full-featured React PWA — you can install it to your desktop or home screen for a native-like experience.
Port
Default port is 8080. This can be changed in Settings. Make sure no firewall on your phone blocks incoming connections on that port.
💡
The server runs as an Android Foreground Service. It stays active while MiloNotes is open or the notification is visible. AI features require the app to be in the foreground.
Access & Connectivity
Internet Tunnel
Access your notes from anywhere in the world via a personal HTTPS URL — no VPN, no port-forwarding, no router config.
How it works
MiloNotes opens a WebSocket connection to tunnel.milonotes.com. The relay server assigns you a permanent subdomain based on your API key and forwards incoming HTTP traffic back to your phone over the WebSocket using yamux multiplexing.
🔒
The relay only forwards raw encrypted bytes — it cannot read your note content. All data is end-to-end encrypted via TLS.
Your personal URL
Your URL is derived deterministically from your API key:
subdomain = "app" + first 8 hex chars of SHA-256(salt + apiKey)
URL = https://app{subdomain}.milonotes.com
The same device and API key always produce the same URL.
Enabling
- Enable the LAN Server first
- Go to Settings → Internet Tunnel
- Select MiloNotes Tunnel as the provider
- Toggle it on — your personal URL is displayed once connected
Access & Connectivity
Cloudflare Tunnel (BYOK)
Use your own Cloudflare account for the tunnel — bring your API token and get a custom hostname on your own domain.
Prerequisites
- A Cloudflare account with a domain managed there
- A Cloudflare API token with Zone:DNS:Edit and Account:Cloudflare Tunnel:Edit permissions
Setup
- Go to Settings → Internet Tunnel
- Select Cloudflare as the tunnel provider
- Enter your CF API Token, Account ID, Tunnel Name, and Hostname
- Tap Connect — MiloNotes downloads the
cloudflared binary for your device ABI and starts the tunnel
How it works
MiloNotes automatically:
- Creates (or reuses) a named Cloudflare tunnel via the API
- Configures a DNS CNAME to point your hostname at the tunnel
- Downloads and runs
cloudflared as a background process
REST API
API Overview & Authentication
MiloNotes exposes a full REST API at /api/v1/ with JSON request and response bodies.
Enabling the API
- Enable the LAN Server in Settings
- Go to Settings → Developer Access
- Toggle REST API on
Base URLs
| Context | Base URL |
| LAN | http://<device-ip>:8080/api/v1 |
| Internet tunnel | https://appXXXXXXXX.milonotes.com/api/v1 |
Authentication
All endpoints require an API key. Create one in Settings → API Keys. Keys are stored as SHA-256 hashes — the plaintext is only shown once at creation.
Pass the key in one of these headers:
X-Api-Key: your-api-key-here
# or
Authorization: Bearer your-api-key-here
Requests without a valid key receive 401 Unauthorized.
Interactive docs
Navigate to http://<device-ip>:8080/api in your browser for an interactive reference with try-it-out buttons for every endpoint.
Response format
All responses are JSON. Errors use this shape:
{ "error": "Unauthorized" }
{ "error": { "message": "Note not found", "type": "not_found" } }
Quick start
KEY="your-api-key"
BASE="http://192.168.1.42:8080/api/v1"
# List all notes
curl -H "X-Api-Key: $KEY" $BASE/notes
# Create a note
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-d '{"title":"Hello","content":"# Hello World"}' $BASE/notes
# Search
curl -H "X-Api-Key: $KEY" "$BASE/search?q=quantum"
REST API
Notes API
GET/api/v1/notes
List all non-trashed notes. Filter with query parameters.
| Param | Type | Description |
notebookId | string | Filter by notebook |
folderId | string | Filter by folder |
Returns: array of NoteDto
GET/api/v1/notes/search-title?q={prefix}
Fast title-prefix search (autocomplete). Returns: array of NoteDto.
GET/api/v1/notes/{id}
Get a single note. Returns: NoteDto. Errors: 404.
POST/api/v1/notes
Create a note. Returns 201 Created with NoteDto.
{
"title": "My Note", // required
"content": "# Markdown…", // optional
"notebookId": "nb-id", // optional
"folderId": "folder-id" // optional
}
PUT/api/v1/notes/{id}
Update a note. All fields are optional (patch semantics).
{
"title": "New Title",
"content": "Updated content",
"notebookId": "new-nb-id",
"folderId": "new-folder-id",
"isPinned": true
}
DELETE/api/v1/notes/{id}
Delete a note. Returns 204 No Content.
NoteDto schema
{
"id": "string",
"title": "string",
"content": "string", // Markdown
"notebookId": "string|null",
"folderId": "string|null",
"isPinned": false,
"wordCount": 42,
"aiSummary": "string|null",
"tags": [{ "id": "…", "name": "…", "color": "…" }],
"suggestedTags": [{ "id": "…", "name": "…", "color": "…" }],
"hasAttachments": false,
"createdAt": 1710000000000, // Unix ms
"updatedAt": 1710000000000
}
REST API
Notebooks API
GET/api/v1/notebooks
List all notebooks. Returns: array of NotebookDto.
GET/api/v1/notebooks/{id}
Get a single notebook. Errors: 404.
POST/api/v1/notebooks
Create a notebook. Returns 201 Created.
{ "name": "Physics", "color": "#6750A4", "icon": "⚛️" }
PUT/api/v1/notebooks/{id}
Update a notebook. All fields optional.
{ "name": "New Name", "color": "#FF5722", "icon": "🔥" }
DELETE/api/v1/notebooks/{id}
Delete a notebook. Returns 204 No Content.
NotebookDto schema
{
"id": "string",
"name": "string",
"color": "#6750A4",
"icon": "📓",
"sortOrder": 0,
"createdAt": 1710000000000,
"updatedAt": 1710000000000
}
REST API
Folders API
Folders represent sections and sub-sections within a notebook. They support infinite nesting via parentFolderId.
GET/api/v1/notebooks/{notebookId}/folders
Get root folders (or children of a parent) for a notebook.
| Param | Description |
parentId | If set, returns children of this folder instead of root folders |
GET/api/v1/notebooks/{notebookId}/folders/all
All folders in a notebook as a flat list — useful for building a tree client-side.
GET/api/v1/folders/{id}
Get a single folder.
POST/api/v1/notebooks/{notebookId}/folders
Create a folder inside a notebook. Returns 201 Created.
{ "name": "Chapter 1", "parentFolderId": "parent-id-or-null" }
PUT/api/v1/folders/{id}
Rename or move a folder.
{ "name": "New Name", "parentFolderId": "new-parent-or-null" }
DELETE/api/v1/folders/{id}
Delete a folder and its children. Returns 204 No Content.
FolderDto schema
{
"id": "string",
"name": "string",
"notebookId": "string",
"parentFolderId": "string|null",
"sortOrder": 0,
"createdAt": 1710000000000,
"updatedAt": 1710000000000
}
REST API
Tags API
GET/api/v1/tags
List all tags.
POST/api/v1/tags
Create a tag. Returns 201 Created.
{ "name": "important", "color": "#FF5722" }
DELETE/api/v1/tags/{id}
Delete a tag. Returns 204 No Content.
GET/api/v1/notes/{noteId}/tags
Get tags on a note.
PUT/api/v1/notes/{noteId}/tags
Replace all tags on a note.
{ "tagIds": ["tag-id-1", "tag-id-2"] }
POST/api/v1/notes/{noteId}/tags/{tagId}
Add a single tag to a note. Returns 204 No Content.
DELETE/api/v1/notes/{noteId}/tags/{tagId}
Remove a tag from a note. Returns 204 No Content.
POST/api/v1/notes/{noteId}/tags/suggestions/{tagId}/accept
Accept an AI-suggested tag. Returns 204 No Content.
DELETE/api/v1/notes/{noteId}/tags/suggestions/{tagId}
Dismiss an AI-suggested tag. Returns 204 No Content.
REST API
Kanban API
Boards
GET/api/v1/kanban/boards
POST/api/v1/kanban/boards
{ "title": "Sprint 1", "linkedNoteId": "note-id-or-null" }
GET/api/v1/kanban/boards/{boardId}
DELETE/api/v1/kanban/boards/{boardId}
Columns
GET/api/v1/kanban/boards/{boardId}/columns
POST/api/v1/kanban/boards/{boardId}/columns
{ "title": "In Progress", "color": "#6366f1", "sortOrder": 1 }
PUT/api/v1/kanban/columns/{columnId}
DELETE/api/v1/kanban/columns/{columnId}
Cards
GET/api/v1/kanban/boards/{boardId}/cards
POST/api/v1/kanban/boards/{boardId}/columns/{columnId}/cards
{
"title": "Fix login bug",
"description": "Details…",
"dueDate": "2026-04-01",
"priority": "high", // low | medium | high
"sortOrder": 0
}
PUT/api/v1/kanban/cards/{cardId}
Update any card field. Move to another column by setting columnId.
POST/api/v1/kanban/cards/{cardId}/move
{ "newColumnId": "column-id", "sortOrder": 2 }
DELETE/api/v1/kanban/cards/{cardId}
REST API
Attachments API
POST/api/v1/attachments/upload
Upload a file and attach it to a note. Uses multipart/form-data.
| Field | Type | Description |
noteId | string | ID of the note to attach to |
file | file | The file to upload |
curl -X POST -H "X-Api-Key: $KEY" \
-F "noteId=your-note-id" \
-F "file=@/path/to/image.png" \
$BASE/attachments/upload
Returns 201 Created with AttachmentDto including the url field to use in Markdown.
GET/api/v1/attachments/{id}/file
Download raw file bytes. Cached with Cache-Control: immutable.
GET/api/v1/attachments/note/{noteId}
List all attachments for a note.
DELETE/api/v1/attachments/{id}
Delete attachment — removes the DB record and the file on disk. Returns 204.
AttachmentDto schema
{
"id": "string",
"noteId": "string",
"fileName": "image.png",
"mimeType": "image/png",
"sizeBytes": 48210,
"url": "/api/attachments/id/file",
"createdAt": 1710000000000
}
REST API
Search API
GET/api/v1/search?q={query}
Full-text search across all notes using FTS4.
curl -H "X-Api-Key: $KEY" "$BASE/search?q=quantum+physics"
Returns an array of search results:
[
{
"note": { /* NoteDto */ },
"snippet": "…matching text excerpt with highlights…",
"score": 1.42
}
]
Results are sorted by relevance score descending. An empty query returns an empty array.
REST API
Chat Completions API
OpenAI-compatible chat completion endpoint. Routes through the AI provider configured in Settings and augments prompts with RAG context from your notes.
POST/api/v1/chat/completions
Request body
{
"model": "llama3.2", // model name for the provider
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Summarise my quantum physics notes." }
],
"stream": false, // true for SSE streaming
"temperature": 0.7, // optional
"max_tokens": 1024 // optional
}
💡
Set model to "provider-type:name:model" (e.g. "ollama:local:llama3.2") to target a specific provider. Otherwise the task default is used.
Non-streaming response
{
"id": "chatcmpl-xxxx",
"object": "chat.completion",
"created": 1710000000,
"model": "llama3.2",
"choices": [{
"index": 0,
"message": { "role": "assistant", "content": "Here is a summary…" },
"finish_reason": "stop"
}],
"usage": { "prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0 }
}
Streaming response ("stream": true)
Returns a Server-Sent Events stream. Each event is a JSON chunk:
data: {"id":"chatcmpl-x","object":"chat.completion.chunk","created":…,
"model":"llama3.2","choices":[{"index":0,"delta":{"content":"Here"},"finish_reason":null}]}
data: {"id":"chatcmpl-x","choices":[{"delta":{"content":" is"},"finish_reason":null}]}
data: [DONE]
Error responses
| Status | Meaning |
503 | No AI provider configured, or app is backgrounded (on-device AI requires foreground) |
500 | The AI provider returned an error |
REST API
Memo Wall API
Quick-capture sticky notes with checklists, colors, pinning, and tags.
GET/api/v1/memo-wall
List all memos, sorted pinned first then by updatedAt descending. Returns: array of MemoDto.
POST/api/v1/memo-wall
Create a memo. Returns 201 Created with MemoDto.
{
"title": "Shopping List", // required
"content": "Milk, eggs, bread", // required
"color": "#fff9c4", // optional
"isPinned": false // optional
}
GET/api/v1/memo-wall/{id}
Get a single memo with tags. Errors: 404.
PUT/api/v1/memo-wall/{id}
Update a memo. All fields optional (patch semantics).
{
"title": "Updated Title",
"content": "New content",
"color": "#c8e6c9",
"isPinned": true
}
DELETE/api/v1/memo-wall/{id}
Delete a memo. Returns 204 No Content.
PATCH/api/v1/memo-wall/{id}/toggle/{index}
Toggle a checklist item at the given index. The memo's content must be a JSON array of {text, checked} objects. The item at index has its checked boolean flipped.
PUT/api/v1/memo-wall/{id}/tags
Replace all tags on a memo.
{ "tagIds": ["tag-id-1", "tag-id-2"] }
GET/api/v1/memo-wall/{id}/tags
Get tag IDs for a memo. Returns: array of tag ID strings.
MemoDto schema
{
"id": "string",
"title": "Shopping List",
"content": "[{\"text\":\"Milk\",\"checked\":false}]",
"color": "#fff9c4",
"isPinned": true,
"createdAt": 1711000000000, // Unix ms
"updatedAt": 1711000000000,
"tags": ["tag-id-1"]
}
💡
Memo content can be plain text or a JSON array of checklist items. When it's a checklist, use the PATCH …/toggle/{index} endpoint to check/uncheck items.
REST API
Goals API
Track goals with milestones, due dates, priority levels, and linked notes.
Goals
GET/api/v1/goals
List all goals with embedded milestones. Returns: array of GoalDto.
POST/api/v1/goals
Create a goal. Returns 201 Created with GoalDto.
{
"title": "Launch v1.0", // required
"description": "Ship first release", // optional
"dueDate": "2026-04-15", // required (YYYY-MM-DD)
"priority": "high", // optional: low | medium | high
"linkedNoteId": "note-id-or-null", // optional
"color": "#6366f1" // optional
}
GET/api/v1/goals/{id}
Get a single goal with milestones. Errors: 404.
PUT/api/v1/goals/{id}
Update a goal. All fields optional (patch semantics).
{
"title": "Launch v2.0",
"description": "Updated description",
"dueDate": "2026-05-01",
"priority": "medium",
"status": "active", // active | completed | archived
"linkedNoteId": "new-note-id",
"color": "#22c55e"
}
DELETE/api/v1/goals/{id}
Delete a goal. All milestones are cascade-deleted. Returns 204 No Content.
GET/api/v1/goals/due/{date}
Get goals and milestones due on a specific date (YYYY-MM-DD).
Milestones
POST/api/v1/goals/{id}/milestones
Add a milestone to a goal. Returns 201 Created.
{
"title": "Beta testing", // required
"dueDate": "2026-04-01", // optional (YYYY-MM-DD)
"sortOrder": 0 // optional
}
PUT/api/v1/goals/{goalId}/milestones/{milestoneId}
Update a milestone. All fields optional.
DELETE/api/v1/goals/{goalId}/milestones/{milestoneId}
Delete a milestone. Returns 204 No Content.
PATCH/api/v1/goals/{goalId}/milestones/{milestoneId}/toggle
Toggle a milestone's completion status. Flips isCompleted between true and false.
GoalDto schema
{
"id": "string",
"title": "Launch v1.0",
"description": "Ship the first public release",
"dueDate": "2026-04-15",
"priority": "high", // low | medium | high
"status": "active", // active | completed | archived
"linkedNoteId": "string|null",
"color": "#6366f1",
"milestones": [
{
"id": "string",
"goalId": "string",
"title": "Beta testing",
"dueDate": "2026-04-01",
"isCompleted": true,
"sortOrder": 0,
"createdAt": 1711000000000
}
],
"createdAt": 1711000000000, // Unix ms
"updatedAt": 1711000000000
}
REST API
AI Learn API
Upload a file for Milo to read, analyze, and generate notes from. Supports PDFs, CSVs, images (OCR), and text files.
POST/api/v1/ai/learn
Upload a file via multipart/form-data. Returns a Server-Sent Events (SSE) stream as Milo processes the file and generates content.
| Field | Type | Description |
file | file | The file to process (PDF, CSV, image, or text file) |
Supported file types
| Type | Extensions | Processing |
| PDF | .pdf | Text extraction and analysis |
| CSV | .csv | Tabular data analysis |
| Images | .png, .jpg, .webp | OCR text extraction |
| Text | .txt, .md | Direct content analysis |
Example
curl -X POST -H "X-Api-Key: $KEY" \
-F "file=@/path/to/document.pdf" \
$BASE/ai/learn
SSE response
The response is a streaming event source. Each frame contains a JSON delta:
data: {"delta":"# Summary of document\n\n"}
data: {"delta":"The document covers…"}
data: {"delta":"…key findings include…"}
data: [DONE]
⚠️
AI Learn requires an AI provider to be configured and the app to be in the foreground. Returns 503 if no provider is available.
REST API
Chat History API
Manage AI chat conversation history. Conversations are stored locally and can be listed, retrieved, or deleted.
GET/api/v1/chat/history
List all chat conversations. Returns an array of conversation summaries ordered by most recent.
GET/api/v1/chat/history/{conversationId}
Get all messages in a specific conversation.
DELETE/api/v1/chat/history/{conversationId}
Delete a conversation and all its messages. Returns 204 No Content.
DELETE/api/v1/chat/history
Delete all chat history. Returns 204 No Content.
REST API
Memories API
The memory system extracts key facts from conversations and stores them as persistent memories. These memories are used to provide context-aware AI responses over time.
GET/api/v1/ai/memories
List all stored memories.
DELETE/api/v1/ai/memories/{id}
Delete a specific memory. Returns 204 No Content.
POST/api/v1/ai/memories/consolidate
Trigger memory consolidation — the AI reviews all memories and merges duplicates, removes outdated entries, and flattens the memory store. Returns a summary of changes.
POST/api/v1/ai/memories/import
Import memories from other AI providers (ChatGPT, Claude, etc.). Accepts a text blob and auto-flattens into individual memory entries.
{ "content": "User prefers dark mode.\nUser is a physics student.\n..." }
MemoryDto schema
{
"id": "string",
"content": "User prefers dark mode for all applications",
"source": "conversation", // conversation | import
"createdAt": 1711000000000,
"updatedAt": 1711000000000
}
REST API
Feature Toggles API
Control which modules are enabled in the app. Users can enable or disable features like Kanban, Goals, Memo Wall, Pomodoro Timer, and Knowledge Graph.
GET/api/v1/settings/features
Get the current state of all feature toggles.
{
"kanban": true,
"goals": true,
"memoWall": true,
"pomodoro": true,
"knowledgeGraph": true,
"dayPlanner": true,
"gitSync": false,
"aiChat": true
}
PUT/api/v1/settings/features
Update feature toggles. Only include the features you want to change.
{ "pomodoro": false, "gitSync": true }
MCP Server
MCP Server Overview
MiloNotes implements the Model Context Protocol (MCP) — allowing AI assistants like Claude, Cursor, and other MCP-compatible clients to read and manage your notes directly.
What is MCP?
The Model Context Protocol is an open standard that lets AI tools connect to external data sources and services. When an AI client connects to the MiloNotes MCP server, it gets tools it can call to list notes, create notes, search, and more — turning Milo into an active context source for any AI assistant.
Protocol details
| Detail | Value |
| Transport | HTTP (JSON-RPC 2.0) |
| Protocol version | 2024-11-05 |
| Endpoint | /mcp |
| Authentication | X-Api-Key header |
| Discovery | GET /mcp returns server info |
| RPC | POST /mcp handles all method calls |
MCP URLs
| Context | URL |
| LAN | http://<device-ip>:8080/mcp |
| Internet tunnel | https://appXXXXXXXX.milonotes.com/mcp |
MCP Server
MCP Server Setup
Enabling the MCP server
- Enable the LAN Server in Settings
- Go to Settings → Developer Access
- Toggle MCP Server on
- Create an API Key in Settings → API Keys if you haven't already
Verify the server is running
curl http://192.168.1.42:8080/mcp
# Returns:
{
"name": "MiloNotes",
"version": "1.0.0",
"protocolVersion": "2024-11-05",
"transport": "http",
"endpoint": "/mcp"
}
Making a JSON-RPC call
curl -X POST http://192.168.1.42:8080/mcp \
-H "X-Api-Key: your-key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}'
MCP Server
Connecting Claude Desktop
Configuration file
Find your Claude Desktop config file:
| OS | Path |
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
Add MiloNotes
Add the following to the mcpServers object:
{
"mcpServers": {
"milonotes": {
"url": "http://192.168.1.42:8080/mcp",
"headers": {
"X-Api-Key": "your-api-key-here"
}
}
}
}
💡
For remote access, replace the LAN URL with your tunnel URL: https://appXXXXXXXX.milonotes.com/mcp
Restart Claude Desktop
After saving the config, restart Claude Desktop. You should see MiloNotes listed in the MCP tools panel (hammer icon). Claude can now use your notes as context automatically.
Example prompts
- "Search my notes for anything about quantum mechanics"
- "Create a note called 'Meeting 2026-04-01' with these bullet points…"
- "List my notebooks and find the one about computer science"
- "Create a Kanban card in my Dev board to refactor the auth module"
MCP Server
Connecting Cursor
Via Cursor settings UI
- Open Cursor → Settings → MCP
- Click Add Server
- Fill in the fields:
- Name: MiloNotes
- URL:
http://192.168.1.42:8080/mcp
- Headers:
X-Api-Key: your-api-key-here
- Click Save
Via .cursor/mcp.json
Alternatively, add to your project's .cursor/mcp.json:
{
"mcpServers": {
"milonotes": {
"url": "http://192.168.1.42:8080/mcp",
"headers": {
"X-Api-Key": "your-api-key-here"
}
}
}
}
Cursor will now include MiloNotes tools in its AI context. You can ask Cursor to look up your notes when working on code — e.g. "Check my notes for the API design I documented last week."
MCP Server
Available MCP Tools
MiloNotes exposes the following tools via tools/list and tools/call.
Memo Wall tools
Goals tools
Memory tools
Error codes
| Code | Meaning |
-32700 | Parse error — malformed JSON |
-32601 | Method not found |
-32603 | Internal error (note not found, missing required argument, AI unavailable) |