roam-research-mcp 2.4.0 → 2.4.3

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 CHANGED
@@ -87,6 +87,8 @@ docker run -p 3000:3000 -p 8088:8088 --env-file .env roam-research-mcp
87
87
 
88
88
  A standalone command-line tool for interacting with Roam Research directly, without running the MCP server. Provides eight subcommands: `get`, `search`, `save`, `refs`, `update`, `batch`, `rename`, and `status`.
89
89
 
90
+ All content creation, update, and retrieval commands support **standard input (stdin) piping**, allowing for powerful automation workflows (e.g., `cat notes.md | roam save`, `roam search "query" | roam get`).
91
+
90
92
  ### Installation
91
93
 
92
94
  After building the project, make the command globally available:
@@ -441,7 +443,7 @@ The server provides powerful tools for interacting with Roam Research:
441
443
  12. `roam_search_by_status`: Search for blocks with a specific status (TODO/DONE) across all pages or within a specific page.
442
444
  13. `roam_search_by_date`: Search for blocks or pages based on creation or modification dates.
443
445
  14. `roam_search_for_tag`: Search for blocks containing a specific tag and optionally filter by blocks that also contain another tag nearby or exclude blocks with a specific tag. This tool supports pagination via the `limit` and `offset` parameters.
444
- 15. `roam_remember`: Add a memory or piece of information to remember. Supports optional `heading` parameter to nest under a specific heading on the daily page (created if missing), or `parent_uid` to nest under a specific block. (Internally uses `roam_process_batch_actions`.)
446
+ 15. `roam_remember`: Add a memory or piece of information to remember. Supports optional `heading` parameter to nest under a specific heading on the daily page (created if missing), or `parent_uid` to nest under a specific block. Use `include_memories_tag: false` to omit the MEMORIES_TAG. (Internally uses `roam_process_batch_actions`.)
445
447
  16. `roam_recall`: Retrieve all stored memories.
446
448
  17. `roam_datomic_query`: Execute a custom Datomic query on the Roam graph for advanced data retrieval beyond the available search tools. Now supports client-side regex filtering for enhanced post-query processing. Optimal for complex filtering (including regex), highly complex boolean logic, arbitrary sorting criteria, and proximity search.
447
449
  18. `roam_markdown_cheatsheet`: Provides the content of the Roam Markdown Cheatsheet resource, optionally concatenated with custom instructions if `CUSTOM_INSTRUCTIONS_PATH` environment variable is set.
@@ -1,128 +1,78 @@
1
- # Roam Markdown Cheatsheet — Generic Foundation v2.0.1
1
+ # Roam Markdown Cheatsheet v2.1.0
2
2
 
3
- > ⚠️ **MODEL DIRECTIVE**: Always consult this cheatsheet BEFORE making any Roam tool calls. Syntax errors in Roam are unforgiving.
3
+ ## Core Syntax
4
4
 
5
- ---
6
-
7
- ## Quick Reference: Core Syntax
8
-
9
- ### Text Formatting
10
- | Style | Syntax | Example |
11
- |-------|--------|---------|
12
- | Bold | `**text**` | **bold text** |
13
- | Italic | `__text__` | __italic text__ |
14
- | Highlight | `^^text^^` | ^^highlighted^^ |
15
- | Strikethrough | `~~text~~` | ~~struck~~ |
16
- | Inline code | `` `code` `` | `code` |
17
- | LaTeX | `$$E=mc^2$$` | rendered math |
5
+ ### Formatting
6
+ `**bold**` · `__italic__` · `^^highlight^^` · `~~strike~~` · `` `code` `` · `$$LaTeX$$`
18
7
 
19
8
  ### Links & References
20
- | Type | Syntax | Notes |
21
- |------|--------|-------|
22
- | Page reference | `[[Page Name]]` | Creates/links to page |
23
- | Block reference | `((block-uid))` | Embeds block content inline |
24
- | Block embed | `{{[[embed]]: ((block-uid))}}` | Full block embed with children |
25
- | External link | `[text](URL)` | Standard markdown |
26
- | Aliased page ref | `[display text]([[Actual Page]])` | Shows custom text, links to page |
27
- | Aliased block ref | `[display text](<((block-uid))>)` | Links to specific block |
28
- | Image embed | `![alt text](URL)` | Inline image |
29
-
30
- ### Tags & Hashtags
31
- | Type | Syntax | When to Use |
32
- |------|--------|-------------|
33
- | Single word | `#tag` | Simple categorization |
34
- | Multi-word | `#[[multiple words]]` | Phrases, compound concepts |
35
- | Hyphenated | `#self-esteem` | Naturally hyphenated terms |
36
-
37
- ⚠️ **CRITICAL**: Never concatenate multi-word tags. `#knowledgemanagement` ≠ `#[[knowledge management]]`
38
-
39
- ⚠️ **CRITICAL**: Never use `#` to mean "number" (e.g., `#1`, `#2`). In Roam, `#` **always** creates a hashtag. Write `Step 1`, `No. 1`, or just spell out the number instead.
9
+ - **Page ref:** `[[Page Name]]` creates/links to page
10
+ - **Block ref:** `((block-uid))` — embeds block content inline
11
+ - **Block embed:** `{{[[embed]]: ((block-uid))}}` full block with children
12
+ - **External:** `[text](URL)`
13
+ - **Aliased page:** `[display text]([[Actual Page]])`
14
+ - **Aliased block:** `[display text](<((block-uid))>)` note the angle brackets
15
+ - **Image:** `![alt](URL)`
16
+
17
+ ### Tags
18
+ - Single word: `#tag`
19
+ - Multi-word: `#[[multiple words]]`
20
+ - Hyphenated: `#self-esteem`
21
+
22
+ ⚠️ Never concatenate: `#knowledgemanagement` `#[[knowledge management]]`
23
+ ⚠️ `#` always creates tags write `Step 1` not `#1`
40
24
 
41
25
  ### Dates
42
- - **Always use ordinal format**: `[[January 1st, 2025]]`, `[[December 23rd, 2024]]`
43
- - Ordinals: 1st, 2nd, 3rd, 4th–20th, 21st, 22nd, 23rd, 24th–30th, 31st
26
+ Always ordinal format: `[[January 1st, 2025]]`, `[[December 23rd, 2024]]`
44
27
 
45
- ### Task Management
46
- | Status | Syntax |
47
- |--------|--------|
48
- | Todo | `{{[[TODO]]}} task description` |
49
- | Done | `{{[[DONE]]}} task description` |
28
+ ### Tasks
29
+ - Todo: `{{[[TODO]]}} task`
30
+ - Done: `{{[[DONE]]}} task`
50
31
 
51
- ### Attributes (Properties)
32
+ ### Attributes
52
33
  ```
53
34
  Type:: Book
54
35
  Author:: [[Person Name]]
55
36
  Rating:: 4/5
56
- Source:: https://example.com
57
37
  ```
58
38
 
59
- **Purpose**: Attributes create structured metadata that is **queryable across your entire graph**. The attribute name becomes a page reference, so only use `::` when the attribute is a reusable property that applies to multiple pages or concepts.
60
-
61
- **When to USE attributes:**
62
- | Attribute | Why It's Good |
63
- |-----------|---------------|
64
- | `Type:: Book` | Reusable across all media you consume |
65
- | `Author:: [[Person]]` | Links to author page, queryable |
66
- | `Status:: In Progress` | Standard project states, queryable |
67
- | `Source:: URL` | Consistent sourcing across notes |
68
- | `Date:: [[January 1st, 2025]]` | Enables date-based queries |
69
-
70
- **When NOT to use attributes:**
71
- | ❌ Wrong | ✅ Use Instead | Why |
72
- |----------|----------------|-----|
73
- | `Step 1:: Do this thing` | `**Step 1:** Do this thing` | Step numbers are page-specific, not queryable concepts |
74
- | `Note:: Some observation` | Just write the text, or use `#note` | One-off labels don't need attribute syntax |
75
- | `Summary:: The main point` | `**Summary:** The main point` | Section headers are formatting, not metadata |
76
- | `Definition:: Some text` | `Term:: Definition` | Only use for actual definitions you want to query |
77
- | `Implementation Tier 3 (Societal Restructuring):: Some text` | `**Implementation Tier 3 (Societal Restructuring):** Some text` | Label is specific to current concept |
39
+ **Use `::` when:** queryable across graph (Type, Author, Status, Source, Date)
40
+ **Use bold instead when:** page-specific labels (Step 1, Summary, Note)
78
41
 
79
- ⚠️ **The Test**: Ask yourself: "Will I ever query for all blocks with this attribute across my graph?" If no, use **bold formatting** (`**Label:**`) instead of `::` syntax.
80
-
81
- NOTE: Never combine bold markdown formatting with `::`. Roam formats attributes in bold by default. ✅ `<attribute>::` ❌ `**<attribute>**::`
82
-
83
- ---
42
+ ⚠️ Test: "Will I query all blocks with this attribute?" If no use `**Label:**` instead
43
+ ⚠️ Never `**Attr**::` — Roam auto-bolds attributes
84
44
 
85
45
  ## Block Structures
86
46
 
87
- ### Bullet Points
88
- - Use `-` (dash) followed by space
89
- - Nested bullets: indent with tab or spaces
47
+ ### Bullets
90
48
  ```
91
- - Parent item
92
- - Child item
93
- - Grandchild item
49
+ - Parent
50
+ - Child
51
+ - Grandchild
94
52
  ```
95
53
 
96
54
  ### Code Blocks
97
55
  ````
98
56
  ```javascript
99
- const example = () => {
100
- return "syntax highlighted";
101
- }
57
+ const x = 1;
102
58
  ```
103
59
  ````
104
60
 
105
61
  ### Queries
106
62
  ```
107
63
  {{[[query]]: {and: [[tag1]] [[tag2]]}}}
108
- {{[[query]]: {or: [[optionA]] [[optionB]]}}}
109
- {{[[query]]: {not: [[exclude-this]]}}}
64
+ {{[[query]]: {or: [[A]] [[B]]}}}
65
+ {{[[query]]: {not: [[exclude]]}}}
110
66
  {{[[query]]: {between: [[January 1st, 2025]] [[January 31st, 2025]]}}}
111
67
  ```
112
68
 
113
69
  ### Calculator
114
- ```
115
- {{[[calc]]: 2 + 2}}
116
- {{[[calc]]: 100 * 0.15}}
117
- ```
118
-
119
- ---
70
+ `{{[[calc]]: 2 + 2}}`
120
71
 
121
72
  ## Complex Structures
122
73
 
123
74
  ### Tables
124
- Tables use nested indentation. Each column header/cell nests ONE LEVEL DEEPER than previous.
125
-
75
+ Each column nests ONE LEVEL DEEPER than previous:
126
76
  ```
127
77
  {{[[table]]}}
128
78
  - Header 1
@@ -131,235 +81,114 @@ Tables use nested indentation. Each column header/cell nests ONE LEVEL DEEPER th
131
81
  - Row 1 Label
132
82
  - Cell 1.1
133
83
  - Cell 1.2
134
- - Cell 1.3
135
84
  - Row 2 Label
136
85
  - Cell 2.1
137
86
  - Cell 2.2
138
- - Cell 2.3
139
87
  ```
88
+ Keep tables ≤5 columns.
140
89
 
141
- **Rules:**
142
- - `{{[[table]]}}` is level 1
143
- - First header/row-label at level 2
144
- - Each subsequent column nests +1 level deeper
145
- - Keep tables ≤5 columns for readability
146
-
147
- ### Kanban Boards
90
+ ### Kanban
148
91
  ```
149
92
  {{[[kanban]]}}
150
- - Column 1 Title
151
- - Card 1 content
152
- - Card 2 content
153
- - Column 2 Title
154
- - Card 3 content
93
+ - Column 1
94
+ - Card 1
95
+ - Card 2
96
+ - Column 2
97
+ - Card 3
155
98
  ```
156
99
 
157
- ### Mermaid Diagrams
100
+ ### Mermaid
158
101
  ```
159
102
  {{[[mermaid]]}}
160
103
  - graph TD
161
104
  - A[Start] --> B{Decision}
162
105
  - B -->|Yes| C[Action]
163
- - B -->|No| D[Alternative]
164
- ```
165
-
166
- ### Hiccup (Custom HTML)
167
- `:hiccup [:iframe {:width "600" :height "400" :src "https://example.com"}]`
168
-
169
- `:hiccup [:div {:style {:color "red"}} "Custom styled content"]`
170
-
171
- ---
172
-
173
- ## Anti-Patterns — DON'T DO THIS
174
-
175
- | ❌ Wrong | ✅ Correct | Why |
176
- |----------|-----------|-----|
177
- | `Step 1:: Do this` | `**Step 1:** Do this` | `::` creates queryable attributes; use bold for page-specific labels |
178
- | `#multiplewords` | `#[[multiple words]]` | Concatenated tags create dead references |
179
- | `#1`, `#2`, `#3` | `Step 1`, `No. 1`, or spell out | `#` always creates hashtags, never means "number" |
180
- | `[[january 1, 2025]]` | `[[January 1st, 2025]]` | Must use ordinal format with proper capitalization |
181
- | `[text](((block-uid)))` | `[text](<((block-uid))>)` | Block ref links need angle bracket wrapper |
182
- | `{{embed: ((uid))}}` | `{{[[embed]]: ((uid))}}` | Embed requires double brackets around keyword |
183
- | Deeply nested tables (6+ cols) | Max 4-5 columns | Becomes unreadable/unmanageable |
184
- | `- *bullet` | `- bullet` | Use dash, not asterisk for bullets |
185
- | `[[TODO]] task` | `{{[[TODO]]}} task` | TODO needs double curly braces |
186
-
187
- ---
188
-
189
- ## Tool Selection Decision Tree
190
-
191
- ```
192
- CREATING CONTENT IN ROAM:
193
-
194
- ┌─ Is this a NEW standalone page with structure?
195
- │ └─ YES → roam_create_page (with content array)
196
-
197
- ├─ Adding content to EXISTING page/block?
198
- │ ├─ Simple outline structure → roam_create_outline
199
- │ │ (provide page_title_uid and/or block_text_uid)
200
- │ │
201
- │ └─ Complex/nested markdown → roam_import_markdown
202
- │ (for deeply nested content, tables, etc.)
203
-
204
- ├─ Replacing/revising ENTIRE page content?
205
- │ └─ roam_update_page_markdown
206
- │ (fetches page internally, computes smart diff, preserves UIDs)
207
-
208
- ├─ Need to CREATE, UPDATE, MOVE, or DELETE individual blocks?
209
- │ └─ roam_process_batch_actions
210
- │ (fine-grained control, UID placeholders for parent refs)
211
-
212
- ├─ Creating a TABLE?
213
- │ └─ roam_create_table
214
- │ (handles complex nested structure automatically)
215
-
216
- ├─ Adding a memory/note to remember?
217
- │ └─ roam_remember (auto-tags with MEMORIES_TAG)
218
-
219
- ├─ Adding TODO items to today?
220
- │ └─ roam_add_todo (creates individual TODO blocks)
221
-
222
- └─ SEARCHING/READING:
223
- ├─ Find by tag → roam_search_for_tag
224
- ├─ Find by text → roam_search_by_text
225
- ├─ Find by date range → roam_search_by_date
226
- ├─ Find by status → roam_search_by_status
227
- ├─ Find block/page references → roam_search_block_refs
228
- ├─ Find pages modified today → roam_find_pages_modified_today
229
- ├─ Get page content → roam_fetch_page_by_title
230
- ├─ Get block + children → roam_fetch_block_with_children
231
- ├─ Recall memories → roam_recall
232
- └─ Complex queries → roam_datomic_query
233
106
  ```
234
107
 
235
- ---
236
-
237
- ## API Efficiency Guidelines (Rate Limit Avoidance)
238
-
239
- The Roam API has rate limits. Follow these guidelines to minimize API calls:
240
-
241
- ### Tool Efficiency Ranking (Best to Worst)
242
- 1. **`roam_update_page_markdown`** - Single call: fetches, diffs, and updates (MOST EFFICIENT for revisions)
243
- 2. **`roam_process_batch_actions`** - Single API call for multiple operations
244
- 3. **`roam_create_page`** - Batches content with page creation
245
- 4. **`roam_create_outline` / `roam_import_markdown`** - Include verification queries (use for smaller operations)
246
- 5. **Multiple sequential tool calls** - Each call = multiple API requests (AVOID)
247
-
248
- ### Best Practices for Intensive Operations
249
-
250
- #### When Updating/Revising a Page:
251
- 1. **Preferred**: Use `roam_update_page_markdown` — it fetches, diffs, and updates in one call
252
- 2. **Alternative** (for fine-grained control): Fetch once with `roam_fetch_page_by_title`, then execute ALL changes in a SINGLE `roam_process_batch_actions` call
253
- 3. Do NOT fetch-modify-fetch-modify in a loop
108
+ ### Hiccup
109
+ `:hiccup [:iframe {:width "600" :height "400" :src "URL"}]`
254
110
 
255
- #### When Creating Large Content:
256
- - For 10+ blocks: Use `roam_process_batch_actions` with nested structure
257
- - For simple outlines (<10 blocks): `roam_create_outline` is fine
111
+ ## Anti-Patterns
258
112
 
259
- #### UID Caching:
260
- - Save UIDs from previous operations - don't re-query for them
261
- - Use `page_uid` instead of `page_title` when available (avoids lookup query)
262
- - Use `block_uid` instead of `block_text_uid` when you have it
263
-
264
- #### UID Placeholders for Nested Blocks:
265
- When using `roam_process_batch_actions` to create nested blocks, use **placeholder tokens** instead of generating UIDs yourself. The server generates proper random UIDs and returns a mapping.
266
-
267
- **Syntax:** `{{uid:name}}` where `name` is any identifier you choose.
268
-
269
- **Example:**
113
+ | Wrong | ✅ Correct |
114
+ |----------|-----------|
115
+ | `#multiplewords` | `#[[multiple words]]` |
116
+ | `#1`, `#2` | `Step 1`, `No. 1` |
117
+ | `[[january 1, 2025]]` | `[[January 1st, 2025]]` |
118
+ | `[text](((uid)))` | `[text](<((uid))>)` |
119
+ | `{{embed: ((uid))}}` | `{{[[embed]]: ((uid))}}` |
120
+ | `[[TODO]] task` | `{{[[TODO]]}} task` |
121
+ | `- *bullet` | `- bullet` |
122
+ | `* bullet` | `- bullet` |
123
+ | `**Attr**:: val` | `Attr:: val` |
124
+
125
+ ## Tool Selection
126
+
127
+ ```
128
+ CREATING:
129
+ ├─ New page + structure → roam_create_page
130
+ ├─ Add to existing page/block:
131
+ │ ├─ Simple outline → roam_create_outline
132
+ │ └─ Complex markdown → roam_import_markdown
133
+ ├─ Revise entire page → roam_update_page_markdown
134
+ ├─ Fine-grained CRUD → roam_process_batch_actions
135
+ ├─ Table → roam_create_table
136
+ ├─ Memory → roam_remember
137
+ └─ Todos → roam_add_todo
138
+
139
+ SEARCHING:
140
+ ├─ By tag → roam_search_for_tag
141
+ ├─ By text → roam_search_by_text
142
+ ├─ By date → roam_search_by_date
143
+ ├─ By status → roam_search_by_status
144
+ ├─ Block refs → roam_search_block_refs
145
+ ├─ Modified today → roam_find_pages_modified_today
146
+ ├─ Page content → roam_fetch_page_by_title
147
+ ├─ Block + children → roam_fetch_block_with_children
148
+ ├─ Memories → roam_recall
149
+ └─ Complex → roam_datomic_query
150
+ ```
151
+
152
+ ## API Efficiency
153
+
154
+ **Ranking (best → worst):**
155
+ 1. `roam_update_page_markdown` — single call: fetch + diff + update
156
+ 2. `roam_process_batch_actions` — batch multiple ops
157
+ 3. `roam_create_page` — batches content with creation
158
+ 4. `roam_create_outline` / `roam_import_markdown` — includes verification
159
+ 5. Multiple sequential calls — avoid
160
+
161
+ **Best practices:**
162
+ - Use `roam_update_page_markdown` for revisions (handles everything)
163
+ - For 10+ blocks: `roam_process_batch_actions`
164
+ - Cache UIDs — use `page_uid` over `page_title` when available
165
+ - Never fetch-modify-fetch-modify in loops
166
+
167
+ ### UID Placeholders
168
+ Use `{{uid:name}}` for parent refs in batch actions:
270
169
  ```json
271
170
  [
272
- { "action": "create-block", "uid": "{{uid:parent}}", "string": "Parent Block", "location": { "parent-uid": "pageUid123", "order": 0 } },
273
- { "action": "create-block", "string": "Child Block", "location": { "parent-uid": "{{uid:parent}}", "order": 0 } }
171
+ {"action": "create-block", "uid": "{{uid:parent}}", "string": "Parent", "location": {"parent-uid": "pageUid", "order": 0}},
172
+ {"action": "create-block", "string": "Child", "location": {"parent-uid": "{{uid:parent}}", "order": 0}}
274
173
  ]
275
174
  ```
276
-
277
- **Response includes UID mapping:**
278
- ```json
279
- {
280
- "success": true,
281
- "uid_map": {
282
- "parent": "Xk7mN2pQ9"
283
- }
284
- }
285
- ```
286
-
287
- **Why placeholders?** LLMs are not reliable random generators. The server uses cryptographically secure randomness to generate proper 9-character Roam UIDs.
288
-
289
- ### Example: Efficient Page Revision
290
-
291
- **Instead of:**
292
- ```
293
- 1. roam_fetch_page_by_title → get content
294
- 2. roam_create_outline → add section 1
295
- 3. roam_create_outline → add section 2
296
- 4. roam_import_markdown → add more content
297
- ```
298
-
299
- **Do this:**
300
- ```
301
- 1. roam_update_page_markdown → single call handles fetch, diff, and updates
302
- ```
303
-
304
- **Alternative** (when you need fine-grained control):
305
- ```
306
- 1. roam_fetch_page_by_title → get page UID and content
307
- 2. roam_process_batch_actions → ALL creates/updates in one call
308
- ```
309
-
310
- ---
175
+ Server returns `{"uid_map": {"parent": "Xk7mN2pQ9"}}`.
311
176
 
312
177
  ## Structural Defaults
313
178
 
314
- When unsure how to structure output:
179
+ - **Hierarchy:** 2-4 levels preferred, rarely exceed 5
180
+ - **Blocks:** One idea per block
181
+ - **Page refs vs tags:** `[[Page]]` for expandable concepts, `#tag` for filtering
182
+ - **Embed vs ref:** `((uid))` inline, `{{[[embed]]: ((uid))}}` with children, `[text](<((uid))>)` link only
183
+ - **No empty blocks or `---` dividers** — use hierarchy for visual separation
315
184
 
316
- 1. **Hierarchy depth**: Prefer 2-4 levels; rarely exceed 5
317
- 2. **Block length**: Keep blocks atomic — one idea per block
318
- 3. **Page refs vs hashtags**:
319
- - `[[Page]]` for concepts you'll expand into full pages
320
- - `#tag` for categorization/filtering
321
- 4. **When to embed vs reference**:
322
- - `((uid))` — inline reference (shows content)
323
- - `{{[[embed]]: ((uid))}}` — full block with children
324
- - `[text](<((uid))>)` — clickable link only
185
+ ## Output Conventions
325
186
 
326
- ---
327
- ## Visual Separation — Hierarchy First, Separators Never
328
-
329
- Empty blocks and decorative dividers create clutter. Roam's outliner structure provides all the visual separation you need.
330
-
331
- | ❌ Avoid | ✅ Instead |
332
- |----------|-----------|
333
- | Blank blocks | Let hierarchy create space — child blocks are visually indented |
334
- | `---` dividers | Use a **heading block** to signal section breaks |
335
- | Decorative lines `───` | Nest content under a parent block as a structural container |
336
-
337
- **Principle**: If you feel the urge to add visual breathing room, you probably need *better structure*, not more blocks. Promote a block to a heading, or reorganize into parent/child relationships.
338
-
339
- **The test**: If you'd delete it during cleanup, don't create it.
340
-
341
- ---
342
-
343
- ## Output Format Conventions
344
-
345
- ### Quotes
346
- ```
347
- <quote text> —[[Author Name]] #quote #[[relevant topic]]
348
- ```
349
-
350
- ### Definitions
351
- ```
352
- Term:: Definition text #definition #[[domain]]
353
- ```
354
-
355
- ### Questions for Future
356
- ```
357
- {{[[TODO]]}} Research: <question> #[[open questions]]
358
- ```
187
+ **Quote:** `<text> —[[Author]] #quote`
188
+ **Definition:** `Term:: definition #definition`
189
+ **Open question:** `{{[[TODO]]}} Research: <question> #[[open questions]]`
359
190
 
360
191
  ---
361
-
362
- *End of Generic Foundation — Personalization section follows during user setup.*
363
192
  # Roam Preferences — Personalization Layer
364
193
 
365
194
  > This section contains YOUR specific conventions, tagging philosophy, and graph-specific rules. Customize to match your workflow.
@@ -6,14 +6,7 @@ import { printDebug, exitWithError } from '../utils/output.js';
6
6
  import { resolveGraph } from '../utils/graph.js';
7
7
  import { collectPageTitles, resolveAllPages, resolveDailyPageUid, needsDailyPage, createResolutionContext, getDailyPageTitle } from '../batch/resolver.js';
8
8
  import { translateAllCommands } from '../batch/translator.js';
9
- /** Read all input from stdin */
10
- async function readStdin() {
11
- const chunks = [];
12
- for await (const chunk of process.stdin) {
13
- chunks.push(chunk);
14
- }
15
- return Buffer.concat(chunks).toString('utf-8');
16
- }
9
+ import { readStdin } from '../utils/input.js';
17
10
  // Required params per command type
18
11
  const REQUIRED_PARAMS = {
19
12
  todo: ['text'],