Organize Notes with Gemini CLI

For a visual learner like me, maintaining note organization in a system like Obsidian is a significant challenge. Being able to “visualize the map” in my mind is a crucial step.

In Obsidian, a common and effective method is creating Maps of Content (MOCs) to serve as curated indexes for specific topics. However, keeping MOCs updated whenever new notes are added is quite difficult. Recently, I leveraged the capabilities of Gemini CLI to automatically generate various MOC overview lists from existing notes.

The Challenge: Manual MOC Creation is Tedious

My notes are scattered across different folders, each focused on a specific topic (in the beginning, at least), such as Command Line, HTML & DOM Elements, JavaScript Performance, etc. Manually creating and updating MOCs for these topics is time-consuming, error-prone, and often falls behind.

The goal was to achieve automation through the following steps:

  1. Identify relevant notes based on their folder location or Obsidian Properties.
  2. Generate a new MOC file based on an existing MOC file format.
  3. Populate the MOC with links to relevant notes, categorized for easy navigation.

The Solution: A Collaborative Workflow with Gemini CLI

I established a workflow that utilizes Gemini CLI’s capabilities to read files, understand their content, and generate new files based on a template.

1. Defining the MOC Template

I found or created a template for MOCs, stored in a gemini.md file, with the following structure:

  • Header: The main title of the MOC.
  • Subsections: Thematic blocks to group related notes.
  • Link Format: Using the [[wikilink]] format for easy navigation in Obsidian.
  • Dataview Query: A dataview query at the end to dynamically list all notes related to the topic.

2. The Generation Process

With the template in place, generating an MOC for a specific topic became straightforward:

  1. Specify the Source: Inform Gemini CLI which notes to use as the source, either from a specific folder (e.g., /Command Line/) or files matching certain criteria (e.g., topic: frontend/performance).
  2. Specify the Destination: Provide the path for the new MOC file (e.g., /MOC/202505071648 &CommandLine.md).
  3. Gemini Reads and Analyzes: The CLI reads all specified source notes, analyzing their content and metadata.
  4. Gemini Generates the MOC: Based on the analysis and template, the CLI generates the new MOC file.

3. Handling Updates and Edge Cases

Some minor issues arose during the process, such as:

  • Content Append vs Replace: I needed to explicitly specify that new content should be appended to an existing MOC file rather than overwriting it. This had to be clearly stated in the instructions. For example, in gemini.md: “Finally, append the consolidated content to the specified existing file instead of replacing it.”
  • Dataview Errors: When a dataview query didn’t produce the expected output. One approach is to discuss and guide Gemini CLI through iterative questioning to identify and fix syntax errors. Another approach is to fix manually if the errors can be spooted easily.

Conclusion

The task of organizing notes with Gemini CLI went smoothly. Before this, keeping notes organized was a tedious and error-prone manual process. This experience highlighted the value of using large language models as interactive assistants for knowledge management tasks.

╭────────────────────────────────────╮
│                                    │
│  Agent powering down. Goodbye!     │
│                                    │
│                                    │
│  Cumulative Stats (12 Turns)       │
│                                    │
│  Input Tokens           1,980,421  │
│  Output Tokens             12,719  │
│  Thoughts Tokens           11,317  │
│  ────────────────────────────────  │
│  Total Tokens           2,004,457  │
│                                    │
│  Total duration (API)      5m 16s  │
│  Total duration (wall)  1h 36m 3s  │
│                                    │
╰────────────────────────────────────╯

Example instructions

Please refer to the MOC file format and writing style I provided to organize my notes.

The example MOC is in this file under "### Example MOC." 
Please follow the example's structure, heading levels, link format (using `[[note name]]`), and include a brief summary after each item.

Based on different data sources, follow the corresponding instructions (Approach 1, Approach 2, etc.).

## Approach 1 - Files from Directory

Please organize all Markdown notes (filenames `*.md`) in the `/HTML & DOM Elements/` folder and its subfolders, creating a similar MOC structure based on their content relevance.

Finally, append the organized content (instead of overwriting) to an existing file: `/MOC/202504162142 &HTML and DOM Elements`.

Source folder: `/HTML & DOM Elements/`  
Destination file: `/MOC/202504162142 &HTML and DOM Elements`

## Approach 2 - Files from Topic Field

Please organize Markdown notes (filenames `*.md`) in my folders and their subfolders where:  
- The "type" field is "note"  
- The "topic" field starts with "frontend/performance"  

Create a similar MOC structure based on their content relevance.

Finally, append the organized content (instead of overwriting) to an existing file: `/MOC/202505311831 &JavaScript Performance`.

Source: "type" field is "note" and "topic" field starts with "frontend/performance"  
Destination file: `/MOC/202505311831 &JavaScript Performance`

## Example MOC

Source folder: /DOM Events/  
Destination file: /MOC/&DOM Events.md

# 📌 DOM Events Overview

One of the core capabilities of JavaScript in manipulating the DOM is "event listening." Below is a summary of common categories, event flow logic, and application scenarios.

---

## 🧭 Event Handling Basics

- [[DOM]]: What is the DOM? When can it be manipulated?
- [[document\.ready]] vs [[window\.onload]]:  
  - Which triggers earlier?  
  - Basic syntax for addEventListener (needs a note card).

---

## 📦 Event Objects and Common Properties

| Topic                          | Note Links                           |
|-------------------------------|--------------------------------------|
| Event Source and Target       | [[e.target vs e.currentTarget]] |
| Mouse Coordinate Info         | [[Mouse event - offsetX]], [[e\.pageX and e\.pageY]] |
| Keyboard and Modifier Keys    | [[e\.target\.key]], [[shiftKey event]] |

---

## 🔁 Event Flow and Control

- [[202408251911 Event Capture & Bubble]]: Event capturing and bubbling mechanisms.
- [[202408251147 Event Propagation]]: How events pass from parent to child and back.
- [[202408251910 stopPropagation vs stopImmediatePropagation]]: Differences in stopping event propagation.

---

## 🎯 Event Delegation

- [[Event Delegation]]: Using bubbling to save resources and handle dynamic content.  
- Example use case: How to attach a single listener for clicking a delete button in a todo list?

---

## 🖱 Mouse and Touch Events

| Type         | Notes                           |
|--------------|---------------------------------|
| Mouse Events | [[mouseout vs mouseleave]], [[Mouse event - offsetX]] |
| Touch Events | [[Touch events]] |

---

## ⌨️ Keyboard Events

- [[keyup and keydown]]
- [[e\.target\.key]]
- [[shiftKey event]]

📌 Suggested addition: When was `keypress` deprecated? Compare with `keydown/keyup`.

---

## 🔤 Form and Input Events

- [[Input event]]
- [[Input vs Change]]

📌 Suggestion: Add a chart comparing event trigger differences for common input fields.

---

## 📼 Media and Animation Events

| Type         | Notes                           |
|--------------|---------------------------------|
| Animation    | [[transitionend]] |
| Media Playback | [[play and ended]] |

---

## 🚀 Performance and Event Frequency Control

- [[Throttle Use Cases]]: How to limit high-frequency events like `scroll`, `input`, `resize`, etc.  
- Suggested addition: Differences between `debounce` vs `throttle`.

---

## 🧩 Index

```text
// dataview
table topic, tags, file.path
where contains(topic, "web-apis/browser-events")
  and (contains(file.path, "Notes") or contains(file.path, "DOM Event") or contains(file.path, "Browser"))