@ilivemylife/graph-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,725 @@
1
+ # @ilivemylife/graph-sdk
2
+
3
+ SDK for [iLiveMyLife](https://iLiveMyLife.io) Knowledge Graph.
4
+
5
+ ## What is iLiveMyLife?
6
+
7
+ **iLiveMyLife** is your personal **informational wallet** — a unified platform to organize everything in your life.
8
+
9
+ ### Key Features
10
+
11
+ - **Knowledge Graph** — Structure your information as interconnected nodes, not just files and folders
12
+ - **Cross-platform** — Apps for iOS, Android, Web, Desktop (macOS, Windows, Linux)
13
+ - **Real-time Sync** — Changes sync instantly across all your devices
14
+ - **Push Notifications** — Stay informed with smart notifications
15
+ - **Team Collaboration** — Share nodes with team members, control privacy with tags (private/wallet/kyc/etc.)
16
+ - **AI Assistants (Lifebot)** — Built-in AI that understands your knowledge graph context
17
+ - **Offline Support** — Your data is synced on your device for offline access if not connected
18
+ - **Powerful Tags System** — Customize node behavior with tags (privacy, AI assistance, colors, markers, and more)
19
+ - **Markers (Status System)** — Track item status with customizable markers (like task states)
20
+ - **Rich Content** — Support for text, images, files, links, checklists, due dates, and more
21
+ - **Robust API & SDK** — Full-featured TypeScript SDK and GraphQL API for developers
22
+ - **CLI Tool** — Command-line interface for scripting and automation
23
+ - **MCP Server** — Integrate with AI assistants like Claude, Cursor, Windsurf via Model Context Protocol
24
+
25
+ ### Use Cases
26
+
27
+ - Personal knowledge management
28
+ - Team project coordination
29
+ - Task and goal tracking
30
+ - Note-taking with AI assistance
31
+ - Information organization for any domain
32
+
33
+ **Get the app:** [https://iLiveMyLife.io](https://iLiveMyLife.io)
34
+
35
+ ---
36
+
37
+ ## Prerequisites
38
+
39
+ - **Node.js 18+** — [download](https://nodejs.org/)
40
+ - **iLiveMyLife account** — sign up at [iLiveMyLife.io](https://iLiveMyLife.io)
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ npm install @ilivemylife/graph-sdk
46
+ ```
47
+
48
+ ## Authentication
49
+
50
+ You need an access token to use the SDK.
51
+
52
+ **Option 1: CLI Login (recommended)**
53
+ ```bash
54
+ npx ilml login
55
+ # Prompts for email and password in terminal
56
+ # Token saved to ~/.ilivemylife/config.json
57
+ # After this, CLI commands work automatically
58
+ # For SDK, pass token explicitly: createGraphClient({ token })
59
+ ```
60
+
61
+ **Option 2: Programmatic login (for bots and automations)**
62
+ ```javascript
63
+ const response = await fetch('https://api.ilivemylife.io/api/v1/login', {
64
+ method: 'POST',
65
+ headers: { 'Content-Type': 'application/json' },
66
+ body: JSON.stringify({ email: 'you@example.com', password: '...' })
67
+ });
68
+ const token = response.headers.get('access-token');
69
+
70
+ const graph = createGraphClient({ token });
71
+ ```
72
+
73
+ **Option 3: Browser DevTools (manual)**
74
+ 1. Open https://app.ilivemylife.io and log in
75
+ 2. Open DevTools (F12) → Network tab
76
+ 3. Make any action (refresh page, open a node)
77
+ 4. Click any GraphQL request → Headers tab
78
+ 5. Copy `access-token` value, use it as: `createGraphClient({ token: 'copied-value' })`
79
+
80
+ ### Config File
81
+
82
+ After `ilml login`, config is saved as JSON:
83
+
84
+ ```json
85
+ // ~/.ilivemylife/config.json
86
+ {
87
+ "token": "your-access-token",
88
+ "user": {
89
+ "id": "user-id",
90
+ "email": "you@example.com",
91
+ "displayName": "Your Name"
92
+ },
93
+ "rootItemId": "your-root-node-id"
94
+ }
95
+ ```
96
+
97
+ - `token` — access token for API requests
98
+ - `user` — your account info (cached for display in CLI)
99
+ - `rootItemId` — your "My Life" root node ID
100
+
101
+ ### Token Priority
102
+
103
+ The SDK and CLI resolve tokens in this order (first found wins):
104
+
105
+ | Priority | Source | How to set |
106
+ |----------|--------|------------|
107
+ | 1 | Local config | `ilml login --local` → `.ilivemylife/config.json` in project dir |
108
+ | 2 | `.env` file | Create `.env` with `ILML_TOKEN=your-token` in project dir |
109
+ | 3 | Global config | `ilml login` → `~/.ilivemylife/config.json` |
110
+ | 4 | Environment variable | `export ILML_TOKEN=your-token` |
111
+
112
+ This lets you use different accounts per project:
113
+ ```bash
114
+ # Global account (default)
115
+ ilml login
116
+
117
+ # Project-specific account (overrides global)
118
+ cd my-project
119
+ ilml login --local
120
+
121
+ # Or via .env file
122
+ echo "ILML_TOKEN=project-specific-token" > .env
123
+ ```
124
+
125
+ ## Finding Node IDs
126
+
127
+ Node IDs are visible in the URL when viewing a node:
128
+ ```
129
+ https://app.ilivemylife.io/item/00001191f13c5c81-ee4ae8284f820001
130
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
131
+ This is the node ID
132
+ ```
133
+
134
+ Or get your root node ("My Life") programmatically:
135
+ ```javascript
136
+ const me = await graph.me();
137
+ console.log(me.rootItemId); // Your root node ID
138
+ ```
139
+
140
+ ## Quick Start
141
+
142
+ ```javascript
143
+ import { createGraphClient } from '@ilivemylife/graph-sdk';
144
+
145
+ // Create client (token from ilml login or env variable)
146
+ const graph = createGraphClient({
147
+ token: process.env.ILML_TOKEN
148
+ });
149
+
150
+ // Get your root node
151
+ const me = await graph.me();
152
+ const rootId = me.rootItemId;
153
+
154
+ // See what's in your graph
155
+ const items = await graph.items(rootId);
156
+ console.log('My Life:', items[0].title);
157
+ console.log('Children:', items.slice(1).map(i => i.title));
158
+
159
+ // Create a new node
160
+ const project = await graph.addItem(rootId, { title: 'My Project' });
161
+
162
+ // Add children to it
163
+ await graph.addItem(project.id, { title: 'First Task' });
164
+ await graph.addItem(project.id, { title: 'Second Task' });
165
+
166
+ // Ask AI about it (requires 'assist' tag on the node)
167
+ const reply = await graph.askLifebot(project.id, 'What tasks do I have?');
168
+ console.log(reply.content);
169
+ ```
170
+
171
+ For a complete walkthrough, run: `node examples/getting-started.mjs`
172
+
173
+ ## Features
174
+
175
+ - **TypeScript** — Full type definitions included
176
+ - **Dual Format** — Works with both ESM (`import`) and CommonJS (`require`)
177
+ - **Typed Errors** — `GraphError`, `LifebotTimeoutError`, `LifebotRateLimitError`
178
+ - **Injectable Logger** — Pass your own logger or use silent mode
179
+ - **Real-time Subscriptions** — Subscribe to message and item changes
180
+
181
+ ## Examples
182
+
183
+ See [examples/](./examples/) directory for complete usage examples:
184
+
185
+ - [getting-started.mjs](./examples/getting-started.mjs) — **Start here!** Complete walkthrough (no NODE_ID needed)
186
+ - [messenger-basics.mjs](./examples/messenger-basics.mjs) — Messages and Lifebot AI
187
+ - [ask-lifebot.mjs](./examples/ask-lifebot.mjs) — AI interactions with error handling
188
+ - [manage-items.mjs](./examples/manage-items.mjs) — Create, edit, reorder items
189
+ - [subscriptions.mjs](./examples/subscriptions.mjs) — Real-time updates
190
+ - [error-handling.mjs](./examples/error-handling.mjs) — Error handling patterns
191
+
192
+ ---
193
+
194
+ ## API Reference
195
+
196
+ ### Creating a Client
197
+
198
+ ```javascript
199
+ import { createGraphClient } from '@ilivemylife/graph-sdk';
200
+
201
+ const graph = createGraphClient({
202
+ token: 'your-access-token', // Required
203
+ logger: console // Optional: enable logging
204
+ });
205
+ ```
206
+
207
+ ### Queries (Read Operations)
208
+
209
+ ```javascript
210
+ // Get node and its children
211
+ const items = await graph.items(nodeId);
212
+ // items[0] = node itself, items[1...n] = children
213
+
214
+ // Get messages
215
+ const messages = await graph.messages(nodeId, 20);
216
+
217
+ // Get change history
218
+ const history = await graph.itemHistory(nodeId);
219
+
220
+ // Get users with access
221
+ const users = await graph.itemUsers(nodeId);
222
+
223
+ // Get child count
224
+ const { count } = await graph.subItemCount(nodeId);
225
+
226
+ // Get node settings
227
+ const settings = await graph.itemSettings(nodeId);
228
+
229
+ // Search messages
230
+ const found = await graph.searchMessages(nodeId, 'keyword');
231
+ ```
232
+
233
+ ### Mutations (Write Operations)
234
+
235
+ ```javascript
236
+ // Create item (all fields optional, node added to end of list by default)
237
+ const item = await graph.addItem(parentId, {
238
+ title: 'New Item',
239
+ description: 'Description',
240
+ tags: ['tag1', 'tag2'],
241
+ dueDate: '1735689600000' // timestamp string (ms)
242
+ });
243
+
244
+ // Create link/shortcut to another node
245
+ const link = await graph.addItem(parentId, {
246
+ refId: originalNodeId, // reference to original node
247
+ title: 'Custom Title', // override original title
248
+ description: 'Custom Desc' // override original description
249
+ });
250
+
251
+ // Edit item
252
+ await graph.editItem({
253
+ id: itemId,
254
+ title: 'Updated Title'
255
+ });
256
+
257
+ // Archive/unarchive
258
+ await graph.archiveItem(itemId);
259
+ await graph.unarchiveItem(itemId);
260
+
261
+ // Move item to different parent
262
+ await graph.moveItem(itemId, fromParentId, toParentId);
263
+
264
+ // Reorder within parent (positions are 1-based)
265
+ await graph.reorderChild(parentId, fromPosition, toPosition);
266
+ // Example: move child from position 4 to position 1
267
+ await graph.reorderChild(parentId, 4, 1);
268
+
269
+ // Move specific node to position (positions are 1-based)
270
+ await graph.setPosition(nodeId, parentId, position);
271
+ // Example: move node to position 2
272
+ await graph.setPosition(nodeId, parentId, 2);
273
+ ```
274
+
275
+ ### Messages
276
+
277
+ ```javascript
278
+ import { LIFEBOT_MESSAGE_TYPES, MESSAGE_TYPES } from '@ilivemylife/graph-sdk';
279
+
280
+ // Simple message (no AI)
281
+ await graph.addMessage(nodeId, 'Hello!', {
282
+ lifebot: LIFEBOT_MESSAGE_TYPES.off
283
+ });
284
+
285
+ // Message that triggers AI response
286
+ await graph.addMessage(nodeId, 'Help me with this', {
287
+ lifebot: LIFEBOT_MESSAGE_TYPES.on
288
+ });
289
+
290
+ // Reply to a message
291
+ await graph.addMessage(nodeId, 'Thanks!', {
292
+ type: MESSAGE_TYPES.reply,
293
+ refId: originalMessageId
294
+ });
295
+
296
+ // Edit/archive messages
297
+ await graph.editMessage({ id: msgId, content: 'Updated' });
298
+ await graph.archiveMessage(msgId);
299
+ ```
300
+
301
+ ### Real-time Subscriptions
302
+
303
+ ```javascript
304
+ import { MESSAGE_CHANGE_TYPES, ITEM_CHANGE_TYPES } from '@ilivemylife/graph-sdk';
305
+
306
+ // Subscribe to messages
307
+ const unsubscribeMessages = await graph.subscribeToMessages(nodeId, (change, message) => {
308
+ if (change === MESSAGE_CHANGE_TYPES.added) {
309
+ console.log('New message:', message.content);
310
+ } else if (change === MESSAGE_CHANGE_TYPES.edited) {
311
+ console.log('Message edited:', message.content);
312
+ } else if (change === MESSAGE_CHANGE_TYPES.deleted) {
313
+ console.log('Message deleted:', message.id);
314
+ }
315
+ });
316
+
317
+ // Subscribe to item changes
318
+ const unsubscribeItems = await graph.subscribeToItems(nodeId, (change, item) => {
319
+ if (change === ITEM_CHANGE_TYPES.added) {
320
+ console.log('New item:', item.title);
321
+ } else if (change === ITEM_CHANGE_TYPES.movedIn) {
322
+ console.log('Item moved here:', item.title);
323
+ } else if (change === ITEM_CHANGE_TYPES.reorder) {
324
+ console.log('Item reordered:', item.title);
325
+ }
326
+ });
327
+
328
+ // Stop listening
329
+ unsubscribeMessages();
330
+ unsubscribeItems();
331
+
332
+ // Wait for specific message
333
+ const msg = await graph.waitForMessage(nodeId,
334
+ (change, msg) => change === MESSAGE_CHANGE_TYPES.added && msg.createdBy === 'Lifebot',
335
+ 30000 // timeout
336
+ );
337
+
338
+ // Wait for any reply after your message
339
+ const reply = await graph.waitForReply(nodeId, myMessageId);
340
+
341
+ // Wait for a reply that directly references your message (via refId)
342
+ const exactReply = await graph.waitForReply(nodeId, myMessageId, { exactMatch: true, timeout: 60000 });
343
+ ```
344
+
345
+ ### AI Interactions
346
+
347
+ ```javascript
348
+ import { LifebotTimeoutError, LifebotRateLimitError } from '@ilivemylife/graph-sdk';
349
+
350
+ try {
351
+ const response = await graph.askLifebot(nodeId, 'What is 2 + 2?', {
352
+ timeout: 60000 // 60 seconds
353
+ });
354
+ console.log(response.content);
355
+ } catch (error) {
356
+ if (error instanceof LifebotTimeoutError) {
357
+ console.error('AI did not respond in time');
358
+ } else if (error instanceof LifebotRateLimitError) {
359
+ console.error('Rate limit exceeded');
360
+ }
361
+ }
362
+ ```
363
+
364
+ **What is Lifebot?**
365
+
366
+ Lifebot is the AI assistant that lives inside your iLiveMyLife knowledge graph. It can:
367
+ - Answer questions about your data and context
368
+ - Search and find information across your nodes
369
+ - **Create new nodes** with titles and descriptions
370
+ - **Organize information** by creating nested structure
371
+ - Execute actions on your behalf
372
+
373
+ ```javascript
374
+ // Ask Lifebot to create a project with sub-tasks
375
+ await graph.askLifebot(nodeId,
376
+ 'Create a node "Weekly Plan" with 3 tasks inside: Monday review, Wednesday sync, Friday summary'
377
+ );
378
+ // Lifebot will create the parent node AND all children!
379
+ ```
380
+
381
+ **Enable Lifebot:** Add `assist` tag to a node to enable Lifebot in that context.
382
+
383
+ ### Helper Methods
384
+
385
+ ```javascript
386
+ // Get single item
387
+ const item = await graph.getItem(nodeId);
388
+
389
+ // Resolve reference (shortcut) to actual node
390
+ const actual = await graph.resolveRef(nodeId);
391
+
392
+ // Get items with references resolved
393
+ const items = await graph.itemsResolved(nodeId);
394
+ ```
395
+
396
+ ### Cleanup
397
+
398
+ ```javascript
399
+ // Close all connections and free resources when done
400
+ graph.destroy();
401
+ ```
402
+
403
+ 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).
404
+
405
+ ### Validation
406
+
407
+ ```javascript
408
+ import { isValidNodeId, parseNodeId, validateNodeId } from '@ilivemylife/graph-sdk';
409
+
410
+ // Check if string is valid node ID
411
+ isValidNodeId('00001191f13c5c81-ee4ae8284f820001') // true
412
+ isValidNodeId('invalid') // false
413
+
414
+ // Parse node ID from raw ID or full URL
415
+ parseNodeId('00001191f13c5c81-ee4ae8284f820001')
416
+ // → '00001191f13c5c81-ee4ae8284f820001'
417
+
418
+ parseNodeId('https://app.ilivemylife.io/item/00001191f13c5c81-ee4ae8284f820001')
419
+ // → '00001191f13c5c81-ee4ae8284f820001'
420
+
421
+ parseNodeId('invalid')
422
+ // → null
423
+
424
+ // Validate and throw error if invalid
425
+ validateNodeId(userInput); // throws GraphError if invalid
426
+ ```
427
+
428
+ ### REST API
429
+
430
+ ```javascript
431
+ // Login
432
+ const { user, accessToken } = await graph.login(email, password);
433
+
434
+ // Get current user
435
+ const me = await graph.me();
436
+ ```
437
+
438
+ ---
439
+
440
+ ## Error Handling
441
+
442
+ ```javascript
443
+ import {
444
+ GraphError, // Base error
445
+ GraphNetworkError, // Network/connection issues
446
+ GraphAuthError, // Authentication failed
447
+ LifebotError, // AI error base
448
+ LifebotTimeoutError, // AI timeout
449
+ LifebotRateLimitError // AI rate limit
450
+ } from '@ilivemylife/graph-sdk';
451
+
452
+ try {
453
+ await graph.addItem(nodeId, { title: 'Test' });
454
+ } catch (error) {
455
+ if (error instanceof GraphAuthError) {
456
+ console.error('Check your token');
457
+ } else if (error instanceof GraphError) {
458
+ console.error('Operation failed:', error.code);
459
+ }
460
+ }
461
+ ```
462
+
463
+ ---
464
+
465
+ ## Constants
466
+
467
+ ```javascript
468
+ import {
469
+ // Message options
470
+ MESSAGE_TYPES, // normal, reply, forward
471
+ LIFEBOT_MESSAGE_TYPES, // on, off
472
+ NOTIFY_MESSAGE_TYPES, // on, off, postpone
473
+
474
+ // Subscription change types
475
+ MESSAGE_CHANGE_TYPES, // added ('+1'), edited ('edit'), deleted ('-1')
476
+ ITEM_CHANGE_TYPES, // added ('+1'), edited ('edit'), deleted ('-1'), movedIn ('movedIn'), reorder ('reorder')
477
+
478
+ // Access and settings
479
+ ITEM_ACCESS_TYPES, // human, bot, request
480
+ AI_PROVIDER_TYPES, // openai, claude, gemini
481
+ NODE_SPECIAL_TYPES // user_settings, user_system, non_drop
482
+ } from '@ilivemylife/graph-sdk';
483
+
484
+ // Subscription change values:
485
+ // MESSAGE_CHANGE_TYPES.added === '+1'
486
+ // MESSAGE_CHANGE_TYPES.edited === 'edit'
487
+ // MESSAGE_CHANGE_TYPES.deleted === '-1'
488
+ //
489
+ // ITEM_CHANGE_TYPES.added === '+1'
490
+ // ITEM_CHANGE_TYPES.edited === 'edit'
491
+ // ITEM_CHANGE_TYPES.deleted === '-1'
492
+ // ITEM_CHANGE_TYPES.movedIn === 'movedIn'
493
+ // ITEM_CHANGE_TYPES.reorder === 'reorder'
494
+ ```
495
+
496
+ ---
497
+
498
+ ## Tags & Markers
499
+
500
+ Tags control node behavior. Format: `#tagname#value` or just `tagname`.
501
+
502
+ ### Special Tags
503
+
504
+ | Tag | Description |
505
+ |-----|-------------|
506
+ | `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 |
507
+ | `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 |
508
+ | `assist` | Enables Lifebot AI in this node |
509
+ | `#color#r,g,b,a` | Node background color |
510
+ | `#markerList#<listId>` | Enables status dropdown for children |
511
+ | `#marker#<statusId>` | Sets item status from marker list |
512
+
513
+ ### Markers (Status System)
514
+
515
+ Markers let you track status of items (like task states). It's a pattern, not a built-in feature:
516
+
517
+ 1. **Create a marker list** — a node with status options as children (emoji titles)
518
+ 2. **Enable on parent** — add `#markerList#<listId>` tag
519
+ 3. **Set status** — add `#marker#<statusId>` tag to items
520
+
521
+ ```javascript
522
+ // Enable default markers on a parent node
523
+ await graph.editItem({
524
+ id: parentId,
525
+ tags: ['#markerList#0000018190aaf813-a61a6f263e6a0000']
526
+ });
527
+
528
+ // Mark item as completed (default marker)
529
+ await graph.editItem({
530
+ id: taskId,
531
+ tags: ['#marker#0000018195a2d792-a61a6f263e6a0000'] // ☑️ Completed
532
+ });
533
+ ```
534
+
535
+ See `CLAUDE.md` for full marker documentation and default marker IDs.
536
+
537
+ ---
538
+
539
+ ## CLI Usage
540
+
541
+ ```bash
542
+ # Install globally
543
+ npm install -g @ilivemylife/graph-sdk
544
+
545
+ # Login (saves token to ~/.ilivemylife/config.json)
546
+ ilml login
547
+
548
+ # Queries (read operations) - all support --json for scripting
549
+ ilml items <nodeId> # List node and children (short)
550
+ ilml items <nodeId> --single # Node only, no children
551
+ ilml items <nodeId> --long # Full details (all fields)
552
+ ilml items <nodeId> --json # JSON output (for scripting)
553
+ ilml items <nodeId> --ids # IDs only (for piping)
554
+ ilml messages <nodeId> [count] # Show messages (short)
555
+ ilml messages <nodeId> --long # Full message details
556
+ ilml messages <nodeId> --json # JSON output
557
+ ilml itemHistory <nodeId> # Show change history
558
+ ilml itemHistory <nodeId> --json # JSON output
559
+ ilml itemUsers <nodeId> --json # Users with access
560
+ ilml subItemCount <nodeId> # Get children count
561
+ ilml itemSettings <nodeId> # Show node settings
562
+ ilml search <nodeId> "text" # Search messages
563
+ ilml tree <nodeId> [depth] # Show tree structure (truncated)
564
+ ilml tree <nodeId> --long # Full titles, no truncation
565
+
566
+ # Item mutations
567
+ ilml addItem <parentId> --title "Task" --desc "Description" --tags work,urgent
568
+ ilml addItem <parentId> --ref <nodeId> # Create link to another node
569
+ ilml editItem <nodeId> --title "New Title" --tags updated
570
+ ilml archiveItem <nodeId>
571
+ ilml unarchiveItem <nodeId>
572
+ ilml moveItem <nodeId> <fromParentId> <toParentId>
573
+ ilml reorderChild <parentId> <from> <to> # Reorder child (1-based positions)
574
+ ilml setPosition <nodeId> <parentId> <pos> # Move to position (1-based)
575
+
576
+ # Messaging
577
+ ilml send <nodeId> "message" # Send message (no AI)
578
+ ilml ask <nodeId> "question" # Ask AI and wait for response
579
+ ilml editMessage <msgId> "new content"
580
+ ilml archiveMessage <msgId>
581
+
582
+ # Management
583
+ ilml config # Show configuration
584
+ ilml me # Current user info
585
+ ```
586
+
587
+ ### Token Configuration
588
+
589
+ Token is resolved in order:
590
+ 1. `.ilivemylife/config.json` in current directory (or parent directories)
591
+ 2. `.env` file with `ILML_TOKEN` in current directory
592
+ 3. `~/.ilivemylife/config.json` (global, set by `ilml login`)
593
+ 4. `ILML_TOKEN` environment variable
594
+
595
+ This allows per-project tokens:
596
+ ```bash
597
+ # Project A uses user A's token
598
+ project-a/.ilivemylife/config.json # via: ilml login --local
599
+
600
+ # Or use .env file
601
+ project-b/.env # ILML_TOKEN=xxx
602
+ ```
603
+
604
+ ---
605
+
606
+ ## MCP Server (AI Assistant Integration)
607
+ [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) 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.
608
+
609
+ ### Setup
610
+
611
+ **Claude Code (quick):**
612
+ ```bash
613
+ claude mcp add --env ILML_TOKEN=your-token ilml -- ilml-mcp
614
+ ```
615
+
616
+ **Claude Code (manual)** — add to `~/.claude/settings.json`:
617
+
618
+ ```json
619
+ {
620
+ "mcpServers": {
621
+ "ilml": {
622
+ "command": "ilml-mcp",
623
+ "env": { "ILML_TOKEN": "your-token" }
624
+ }
625
+ }
626
+ }
627
+ ```
628
+
629
+ **Other AI tools** — same JSON content, different config file:
630
+
631
+ | AI Tool | Config Path |
632
+ |---------|------------|
633
+ | Claude Code | `~/.claude/settings.json` or `claude mcp add` |
634
+ | Claude Desktop | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` |
635
+ | | Windows: `%APPDATA%\Claude\claude_desktop_config.json` |
636
+ | Cursor | `~/.cursor/mcp.json` |
637
+ | Windsurf | `~/.codeium/windsurf/mcp_config.json` |
638
+
639
+ Restart your AI tool after adding the config.
640
+
641
+ ### Available Tools
642
+
643
+ **Read Operations** (no confirmation needed):
644
+ - `graph_items` — Get node and children
645
+ - `graph_messages` — Get messages from node
646
+ - `graph_search_messages` — Search messages
647
+ - `graph_item_history` — Get change history
648
+ - `graph_item_users` — Get users with access
649
+ - `graph_item_settings` — Get node settings
650
+ - `graph_me` — Get current user info
651
+ - `graph_info` — Get documentation about graph features
652
+
653
+ **Write Operations** (require confirmation):
654
+ - `graph_add_item` — Create new node
655
+ - `graph_edit_item` — Edit node (title, description, tags)
656
+ - `graph_archive_item` / `graph_unarchive_item` — Archive/restore
657
+ - `graph_move_item` — Move to different parent
658
+ - `graph_reorder_child` / `graph_set_position` — Reorder
659
+ - `graph_add_message` — Send message
660
+ - `graph_ask_lifebot` — Ask AI and wait for response
661
+
662
+ ### Example Prompts
663
+
664
+ ```
665
+ "Show me items in node abc123"
666
+ "Create a task called 'Review PR' under node xyz789"
667
+ "What messages are in my root node?"
668
+ "Ask Lifebot to summarize this project"
669
+ ```
670
+
671
+ ---
672
+
673
+ ## TypeScript
674
+
675
+ Full type definitions included:
676
+
677
+ ```typescript
678
+ import type {
679
+ // Data types
680
+ Item, Message, User, ItemSettings,
681
+
682
+ // Client types
683
+ GraphClient, GraphClientOptions,
684
+ AddItemOptions, EditItemInput, AddMessageOptions,
685
+
686
+ // Subscription change types (for type-safe comparisons)
687
+ MessageChangeType, // '+1' | 'edit' | '-1'
688
+ ItemChangeType // '+1' | 'edit' | '-1' | 'movedIn' | 'reorder'
689
+ } from '@ilivemylife/graph-sdk';
690
+ ```
691
+
692
+ ---
693
+
694
+ ## Publishing New Versions
695
+
696
+ ```bash
697
+ # First time: login to npm
698
+ npm login
699
+
700
+ # First publish
701
+ npm publish --access public
702
+
703
+ # Update versions:
704
+ npm run release:patch # 1.0.0 → 1.0.1 (bug fixes)
705
+ npm run release:minor # 1.0.0 → 1.1.0 (new features)
706
+ npm run release:major # 1.0.0 → 2.0.0 (breaking changes)
707
+ ```
708
+
709
+ ---
710
+
711
+ ## License
712
+
713
+ © 2026 Ilya Sorokin. All rights reserved.
714
+
715
+ This package is proprietary software. For licensing inquiries, business partnerships, or enterprise usage, please contact the author.
716
+
717
+ ---
718
+
719
+ ## Author
720
+
721
+ Created by **Ilya Sorokin** — founder and developer of iLiveMyLife.
722
+
723
+ - **LinkedIn:** [linkedin.com/in/ilyasorokin](https://www.linkedin.com/in/ilyasorokin/)
724
+ - **Email:** info@ilivemylife.io
725
+ - **App:** [https://iLiveMyLife.io](https://iLiveMyLife.io)