@ilivemylife/graph-sdk
v1.0.9
Published
SDK and CLI for iLiveMyLife Knowledge Graph
Maintainers
Readme
@ilivemylife/graph-sdk
SDK for iLiveMyLife Knowledge Graph.
What is iLiveMyLife?
iLiveMyLife is your personal informational wallet — a unified platform to organize everything in your life.
Key Features
- Knowledge Graph — Structure your information as interconnected nodes, not just files and folders
- Cross-platform — Apps for iOS, Android, Web, Desktop (macOS, Windows, Linux)
- Real-time Sync — Changes sync instantly across all your devices
- Push Notifications — Stay informed with smart notifications
- Team Collaboration — Share nodes with team members, control privacy with tags (private/wallet/kyc/etc.)
- AI Assistants (Lifebot) — Built-in AI that understands your knowledge graph context
- Offline Support — Your data is synced on your device for offline access if not connected
- Powerful Tags System — Customize node behavior with tags (privacy, AI assistance, colors, markers, and more)
- Markers (Status System) — Track item status with customizable markers (like task states)
- Rich Content — Support for text, images, files, links, checklists, due dates, and more
- Robust API & SDK — Full-featured TypeScript SDK and GraphQL API for developers
- CLI Tool — Command-line interface for scripting and automation
- MCP Server — Integrate with AI assistants like Claude, Cursor, Windsurf via Model Context Protocol
Use Cases
- Personal knowledge management
- Team project coordination
- Task and goal tracking
- Note-taking with AI assistance
- Information organization for any domain
Get the app: https://iLiveMyLife.io
Prerequisites
- Node.js 18+ — download
- iLiveMyLife account — sign up at iLiveMyLife.io
Getting Started
1. Install
npm install -g @ilivemylife/graph-sdk2. Login
ilml login
ilml doctor # verify installationToken saved to ~/.ilivemylife/config.json. For per-project accounts, see Token Priority.
3. Add to AI tools (optional)
# Claude Code (global — available in all projects)
claude mcp add --scope user ilml -- npx -y @ilivemylife/graph-sdk
# Claude Code (current project only)
claude mcp add ilml -- npx -y @ilivemylife/graph-sdkFor Cursor, Windsurf, Claude Desktop — see MCP Setup.
Authentication Details
Config File
After ilml login, config is saved as JSON:
// ~/.ilivemylife/config.json
{
"token": "your-access-token",
"user": {
"id": "user-id",
"email": "[email protected]",
"displayName": "Your Name"
},
"rootItemId": "your-root-node-id"
}Token Priority
The SDK, CLI, and MCP server resolve tokens in this order (first found wins):
| Priority | Source | How to set |
|----------|--------|------------|
| 1 | Local config | ilml login --local → .ilivemylife/config.json in project dir |
| 2 | .env file | ILML_TOKEN=your-token in project dir |
| 3 | Global config | ilml login → ~/.ilivemylife/config.json |
| 4 | Environment variable | export ILML_TOKEN=your-token |
Use different accounts per project:
# Global account (default)
ilml login
# Project-specific account (overrides global)
cd my-project
ilml login --localOther Authentication Methods
Programmatic login (for bots and automations):
const response = await fetch('https://api.ilivemylife.io/api/v1/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: '[email protected]', password: '...' })
});
const token = response.headers.get('access-token');
const graph = createGraphClient({ token });Browser DevTools (manual):
- Open https://app.ilivemylife.io and log in
- Open DevTools (F12) → Network tab
- Click any GraphQL request → Headers tab
- Copy
access-tokenvalue
Finding Node IDs
Node IDs are visible in the URL when viewing a node:
https://app.ilivemylife.io/item/00001191f13c5c81-ee4ae8284f820001
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is the node IDOr get your root node ("My Life") programmatically:
const me = await graph.me();
console.log(me.rootItemId); // Your root node IDQuick Start
import { createGraphClient } from '@ilivemylife/graph-sdk';
// Create client (token from ilml login or env variable)
const graph = createGraphClient({
token: process.env.ILML_TOKEN
});
// Get your root node
const me = await graph.me();
const rootId = me.rootItemId;
// See what's in your graph
const items = await graph.items(rootId);
console.log('My Life:', items[0].title);
console.log('Children:', items.slice(1).map(i => i.title));
// Create a new node
const project = await graph.addItem(rootId, { title: 'My Project' });
// Add children to it
await graph.addItem(project.id, { title: 'First Task' });
await graph.addItem(project.id, { title: 'Second Task' });
// Ask AI about it (requires 'assist' tag on the node)
const reply = await graph.askLifebot(project.id, 'What tasks do I have?');
console.log(reply.content);For a complete walkthrough, run: node examples/getting-started.mjs
Features
- TypeScript — Full type definitions included
- Dual Format — Works with both ESM (
import) and CommonJS (require) - Typed Errors —
GraphError,LifebotTimeoutError,LifebotRateLimitError - Injectable Logger — Pass your own logger or use silent mode
- Real-time Subscriptions — Subscribe to message and item changes
Examples
See examples/ directory for complete usage examples:
- getting-started.mjs — Start here! Complete walkthrough (no NODE_ID needed)
- messenger-basics.mjs — Messages and Lifebot AI
- ask-lifebot.mjs — AI interactions with error handling
- manage-items.mjs — Create, edit, reorder items
- subscriptions.mjs — Real-time updates
- error-handling.mjs — Error handling patterns
API Reference
Creating a Client
import { createGraphClient } from '@ilivemylife/graph-sdk';
const graph = createGraphClient({
token: 'your-access-token', // Required
logger: console // Optional: enable logging
});Queries (Read Operations)
// Get node and its children
const items = await graph.items(nodeId);
// items[0] = node itself, items[1...n] = children
// Get messages
const messages = await graph.messages(nodeId, 20);
// Get change history
const history = await graph.itemHistory(nodeId);
// Get users with access
const users = await graph.itemUsers(nodeId);
// Get child count
const { count } = await graph.subItemCount(nodeId);
// Get node settings
const settings = await graph.itemSettings(nodeId);
// Edit node settings (AI provider, notifications, etc)
import { AI_PROVIDER_TYPES, TOGGLE_VALUES } from '@ilivemylife/graph-sdk';
await graph.editItemSettings({
itemId: nodeId,
artificialIntelligenceProvider: AI_PROVIDER_TYPES.openai, // switch AI to OpenAI
intelligence: TOGGLE_VALUES.enabled // use smart model
});
// Reset to app defaults (user's global settings)
await graph.editItemSettings({
itemId: nodeId,
artificialIntelligenceProvider: null, // null = use user's app default
intelligence: null
});
// Search messages
const found = await graph.searchMessages(nodeId, 'keyword');Mutations (Write Operations)
// Create item (all fields optional, node added to end of list by default)
const item = await graph.addItem(parentId, {
title: 'New Item',
description: 'Description',
tags: ['tag1', 'tag2'],
dueDate: '1735689600000' // timestamp string (ms)
});
// Create link/shortcut to another node
const link = await graph.addItem(parentId, {
refId: originalNodeId, // reference to original node
title: 'Custom Title', // override original title
description: 'Custom Desc' // override original description
});
// Edit item
await graph.editItem({
id: itemId,
title: 'Updated Title'
});
// Archive/unarchive
await graph.archiveItem(itemId);
await graph.unarchiveItem(itemId);
// Move item to different parent
await graph.moveItem(itemId, fromParentId, toParentId);
// Reorder within parent (positions are 1-based)
await graph.reorderChild(parentId, fromPosition, toPosition);
// Example: move child from position 4 to position 1
await graph.reorderChild(parentId, 4, 1);
// Move specific node to position (positions are 1-based)
await graph.setPosition(nodeId, parentId, position);
// Example: move node to position 2
await graph.setPosition(nodeId, parentId, 2);Messages
import { LIFEBOT_MESSAGE_TYPES, MESSAGE_TYPES } from '@ilivemylife/graph-sdk';
// Simple message (no AI)
await graph.addMessage(nodeId, 'Hello!', {
lifebot: LIFEBOT_MESSAGE_TYPES.off
});
// Message that triggers AI response
await graph.addMessage(nodeId, 'Help me with this', {
lifebot: LIFEBOT_MESSAGE_TYPES.on
});
// Reply to a message
await graph.addMessage(nodeId, 'Thanks!', {
type: MESSAGE_TYPES.reply,
refId: originalMessageId
});
// Edit/archive messages
await graph.editMessage({ id: msgId, content: 'Updated' });
await graph.archiveMessage(msgId);Real-time Subscriptions
import { MESSAGE_CHANGE_TYPES, ITEM_CHANGE_TYPES } from '@ilivemylife/graph-sdk';
// Subscribe to messages
const unsubscribeMessages = await graph.subscribeToMessages(nodeId, (change, message) => {
if (change === MESSAGE_CHANGE_TYPES.added) {
console.log('New message:', message.content);
} else if (change === MESSAGE_CHANGE_TYPES.edited) {
console.log('Message edited:', message.content);
} else if (change === MESSAGE_CHANGE_TYPES.deleted) {
console.log('Message deleted:', message.id);
}
});
// Subscribe to item changes
const unsubscribeItems = await graph.subscribeToItems(nodeId, (change, item) => {
if (change === ITEM_CHANGE_TYPES.added) {
console.log('New item:', item.title);
} else if (change === ITEM_CHANGE_TYPES.movedIn) {
console.log('Item moved here:', item.title);
} else if (change === ITEM_CHANGE_TYPES.reorder) {
console.log('Item reordered:', item.title);
}
});
// Stop listening
unsubscribeMessages();
unsubscribeItems();
// Wait for specific message
const msg = await graph.waitForMessage(nodeId,
(change, msg) => change === MESSAGE_CHANGE_TYPES.added && msg.createdBy === 'Lifebot',
30000 // timeout
);
// Wait for any reply after your message
const reply = await graph.waitForReply(nodeId, myMessageId);
// Wait for a reply that directly references your message (via refId)
const exactReply = await graph.waitForReply(nodeId, myMessageId, { exactMatch: true, timeout: 60000 });AI Interactions
import { LifebotTimeoutError, LifebotRateLimitError } from '@ilivemylife/graph-sdk';
try {
const response = await graph.askLifebot(nodeId, 'What is 2 + 2?', {
timeout: 60000 // 60 seconds
});
console.log(response.content);
} catch (error) {
if (error instanceof LifebotTimeoutError) {
console.error('AI did not respond in time');
} else if (error instanceof LifebotRateLimitError) {
console.error('Rate limit exceeded');
}
}What is Lifebot?
Lifebot is the AI assistant that lives inside your iLiveMyLife knowledge graph. It can:
- Answer questions about your data and context
- Search and find information across your nodes
- Create new nodes with titles and descriptions
- Organize information by creating nested structure
- Execute actions on your behalf
// Ask Lifebot to create a project with sub-tasks
await graph.askLifebot(nodeId,
'Create a node "Weekly Plan" with 3 tasks inside: Monday review, Wednesday sync, Friday summary'
);
// Lifebot will create the parent node AND all children!Enable Lifebot: Add assist tag to a node to enable Lifebot in that context.
Helper Methods
// Get single item
const item = await graph.getItem(nodeId);
// Resolve reference (shortcut) to actual node
const actual = await graph.resolveRef(nodeId);
// Get items with references resolved
const items = await graph.itemsResolved(nodeId);Cleanup
// Close all connections and free resources when done
graph.destroy();Call destroy() at the end of scripts to close WebSocket connections and let the process exit. Safe to call multiple times. Not needed for HTTP-only usage (queries/mutations without subscriptions).
Validation
import { isValidNodeId, parseNodeId, validateNodeId } from '@ilivemylife/graph-sdk';
// Check if string is valid node ID
isValidNodeId('00001191f13c5c81-ee4ae8284f820001') // true
isValidNodeId('invalid') // false
// Parse node ID from raw ID or full URL
parseNodeId('00001191f13c5c81-ee4ae8284f820001')
// → '00001191f13c5c81-ee4ae8284f820001'
parseNodeId('https://app.ilivemylife.io/item/00001191f13c5c81-ee4ae8284f820001')
// → '00001191f13c5c81-ee4ae8284f820001'
parseNodeId('invalid')
// → null
// Validate and throw error if invalid
validateNodeId(userInput); // throws GraphError if invalidREST API
// Login
const { user, accessToken } = await graph.login(email, password);
// Get current user
const me = await graph.me();Error Handling
import {
GraphError, // Base error
GraphNetworkError, // Network/connection issues
GraphAuthError, // Authentication failed
LifebotError, // AI error base
LifebotTimeoutError, // AI timeout
LifebotRateLimitError // AI rate limit
} from '@ilivemylife/graph-sdk';
try {
await graph.addItem(nodeId, { title: 'Test' });
} catch (error) {
if (error instanceof GraphAuthError) {
console.error('Check your token');
} else if (error instanceof GraphError) {
console.error('Operation failed:', error.code);
}
}Constants
import {
// Message options
MESSAGE_TYPES, // normal, reply, forward
LIFEBOT_MESSAGE_TYPES, // on, off
NOTIFY_MESSAGE_TYPES, // on, off, postpone
// Subscription change types
MESSAGE_CHANGE_TYPES, // added ('+1'), edited ('edit'), deleted ('-1')
ITEM_CHANGE_TYPES, // added ('+1'), edited ('edit'), deleted ('-1'), movedIn ('movedIn'), reorder ('reorder')
// Access and settings
ITEM_ACCESS_TYPES, // human, bot, request
AI_PROVIDER_TYPES, // openai, claude, gemini
TOGGLE_VALUES, // enabled, disabled (for intelligence, lifebotRootAccess)
NODE_SPECIAL_TYPES // user_settings, user_system, non_drop
} from '@ilivemylife/graph-sdk';
// Subscription change values:
// MESSAGE_CHANGE_TYPES.added === '+1'
// MESSAGE_CHANGE_TYPES.edited === 'edit'
// MESSAGE_CHANGE_TYPES.deleted === '-1'
//
// ITEM_CHANGE_TYPES.added === '+1'
// ITEM_CHANGE_TYPES.edited === 'edit'
// ITEM_CHANGE_TYPES.deleted === '-1'
// ITEM_CHANGE_TYPES.movedIn === 'movedIn'
// ITEM_CHANGE_TYPES.reorder === 'reorder'Tags & Markers
Tags control node behavior. Format: #tagname#value or just tagname.
Special Tags
| Tag | Description |
|-----|-------------|
| wallet | High privacy — entering the node requires access. Hidden from AI completely (invisible in search, context, and responses). Can be shared between users (e.g. corporate wallet between CEO and accountant) by granting access. Known limitation: currently wallet nodes are still visible (title, description) in parent's children list and in messenger link previews to users without access. This will be fixed — wallet nodes should be completely invisible to unauthorized users |
| private | Lower privacy — node itself is visible but entering (seeing children) requires access. Users with access can use AI to search inside if allowAIPrivateSearch setting is enabled |
| assist | Enables Lifebot AI in this node |
| #color#r,g,b,a | Node background color |
| #markerList#<listId> | Enables status dropdown for children |
| #marker#<statusId> | Sets item status from marker list |
Markers (Status System)
Markers let you track status of items (like task states). It's a pattern, not a built-in feature:
- Create a marker list — a node with status options as children (emoji titles)
- Enable on parent — add
#markerList#<listId>tag - Set status — add
#marker#<statusId>tag to items
// Enable default markers on a parent node
await graph.editItem({
id: parentId,
tags: ['#markerList#0000018190aaf813-a61a6f263e6a0000']
});
// Mark item as completed (default marker)
await graph.editItem({
id: taskId,
tags: ['#marker#0000018195a2d792-a61a6f263e6a0000'] // ☑️ Completed
});See CLAUDE.md for full marker documentation and default marker IDs.
CLI Usage
# Install globally
npm install -g @ilivemylife/graph-sdk
# Login (saves token to ~/.ilivemylife/config.json)
ilml login
# Queries (read operations) - all support --json for scripting
ilml items <nodeId> # List node and children (short)
ilml items <nodeId> --single # Node only, no children
ilml items <nodeId> --long # Full details (all fields)
ilml items <nodeId> --json # JSON output (for scripting)
ilml items <nodeId> --ids # IDs only (for piping)
ilml messages <nodeId> [count] # Show messages (short)
ilml messages <nodeId> --long # Full message details
ilml messages <nodeId> --json # JSON output
ilml itemHistory <nodeId> # Show change history
ilml itemHistory <nodeId> --json # JSON output
ilml itemUsers <nodeId> --json # Users with access
ilml subItemCount <nodeId> # Get children count
ilml itemSettings <nodeId> # Show node settings
ilml search <nodeId> "text" # Search messages
ilml tree <nodeId> [depth] # Show tree structure (truncated)
ilml tree <nodeId> --long # Full titles, no truncation
# Item mutations
ilml addItem <parentId> --title "Task" --desc "Description" --tags work,urgent
ilml addItem <parentId> --ref <nodeId> # Create link to another node
ilml editItem <nodeId> --title "New Title" --tags updated
ilml archiveItem <nodeId>
ilml unarchiveItem <nodeId>
ilml moveItem <nodeId> <fromParentId> <toParentId>
ilml reorderChild <parentId> <from> <to> # Reorder child (1-based positions)
ilml setPosition <nodeId> <parentId> <pos> # Move to position (1-based)
# Messaging
ilml send <nodeId> "message" # Send message (no AI)
ilml ask <nodeId> "question" # Ask AI and wait for response
ilml editMessage <msgId> "new content"
ilml archiveMessage <msgId>
# Management
ilml config # Show configuration
ilml me # Current user infoToken Configuration
Token is resolved in order:
.ilivemylife/config.jsonin current directory (or parent directories).envfile withILML_TOKENin current directory~/.ilivemylife/config.json(global, set byilml login)ILML_TOKENenvironment variable
This allows per-project tokens:
# Project A uses user A's token
project-a/.ilivemylife/config.json # via: ilml login --local
# Or use .env file
project-b/.env # ILML_TOKEN=xxxMCP Server (AI Assistant Integration)
MCP (Model Context Protocol) allows AI assistants to interact with external tools. This SDK includes an MCP server that exposes graph operations to Claude, Cursor, Windsurf and other MCP-compatible tools.
Setup
Prerequisites: Run ilml login first (see Getting Started).
Claude Code:
# Global (available in all projects)
claude mcp add --scope user ilml -- ilml-mcp
# Or current project only
claude mcp add ilml -- ilml-mcpIf you didn't install globally (npm install -g), use npx:
claude mcp add --scope user ilml -- npx -y @ilivemylife/graph-sdkOther AI tools — add to config file:
{
"mcpServers": {
"ilml": {
"command": "npx",
"args": ["-y", "@ilivemylife/graph-sdk"]
}
}
}Or if installed globally:
{
"mcpServers": {
"ilml": {
"command": "ilml-mcp"
}
}
}| AI Tool | Config Path |
|---------|------------|
| Claude Code | claude mcp add (recommended) or ~/.claude/settings.json |
| Claude Desktop | macOS: ~/Library/Application Support/Claude/claude_desktop_config.json |
| | Windows: %APPDATA%\Claude\claude_desktop_config.json |
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| IntelliJ IDEA | Settings → Tools → AI Assistant → Model Context Protocol (MCP) |
Token is resolved automatically: local config > .env > global config > ILML_TOKEN env var. Restart your AI tool after adding the config.
Available Tools
Read Operations (no confirmation needed):
graph_items— Get node and childrengraph_messages— Get messages from nodegraph_search_messages— Search messagesgraph_item_history— Get change historygraph_item_users— Get users with accessgraph_item_settings— Get node settingsgraph_me— Get current user infograph_info— Get documentation about graph features
Write Operations (require confirmation):
graph_add_item— Create new nodegraph_edit_item— Edit node (title, description, tags)graph_edit_settings— Edit node settings (AI provider, notifications)graph_archive_item/graph_unarchive_item— Archive/restoregraph_move_item— Move to different parentgraph_reorder_child/graph_set_position— Reordergraph_add_message— Send messagegraph_ask_lifebot— Ask AI and wait for response
Example Prompts
"Show me items in node abc123"
"Create a task called 'Review PR' under node xyz789"
"What messages are in my root node?"
"Ask Lifebot to summarize this project"
"Switch AI to OpenAI for node xyz789"
"Use cheaper AI model for this node to save costs"TypeScript
Full type definitions included:
import type {
// Data types
Item, Message, User, ItemSettings,
// Client types
GraphClient, GraphClientOptions,
AddItemOptions, EditItemInput, EditItemSettingsInput, AddMessageOptions,
// Subscription change types (for type-safe comparisons)
MessageChangeType, // '+1' | 'edit' | '-1'
ItemChangeType // '+1' | 'edit' | '-1' | 'movedIn' | 'reorder'
} from '@ilivemylife/graph-sdk';License
© 2026 Ilya Sorokin. All rights reserved.
This package is proprietary software. For licensing inquiries, business partnerships, or enterprise usage, please contact the author.
Author
Created by Ilya Sorokin — founder and developer of iLiveMyLife.
- LinkedIn: linkedin.com/in/ilyasorokin
- Email: [email protected]
- App: https://iLiveMyLife.io
