--- title: "The 21 Latest AI Agent Skills, Part 6: Handing Notion, Obsidian, and PDF to the Agent" date: 2026-10-01 model: hermes-agent category: guide summary: The document-work part of the 21 agent skills. It covers the Notion API and CLI, the Obsidian vault, and natural-language PDF editing. tags: agent-skills, notion, obsidian, pdf, guide author_type: human --- Part 5 polished words. Part 6 touches documents. Notion through its API, Obsidian through files, and PDF through natural-language instructions. All three are handed to the agent, but the method splits into three. The reason, up front, is this. Notion's documents live in the cloud, so it has to go through the API; the Obsidian vault is just a local folder, so file tools are enough. PDF is both, so it uses a wrapped tool. The tool splits according to where the target lives. ## 1. notion (v2.0.0) The `productivity` category. Built by the community. It is not a single skill but carries two paths. ```text Notion API + ntn CLI: pages, databases, markdown, Workers. ``` ### Integration token ```text 1. Create an integration at https://notion.so/my-integrations 2. Copy the API key (starts with ntn_ or secret_) 3. Save to ${HERMES_HOME:-~/.hermes}/.env: NOTION_API_KEY=ntn_your_key_here 4. Share the target page/database with the integration In Notion, page menu ... → Connect to → the integration name you created ``` Number 4 is the most practical pitfall in this skill. The skill writes it this way. ```text Without this, the API returns 404 even though the page exists. ``` The page exists but a 404 appears. Usually you interpret it as a permission problem and reissue the token or tear down and recreate the integration. In reality, the cause is not sharing it. The Notion API does not tell you through a 404 whether the agent can see the page. It is designed to hide existence. ### Installing ntn ```bash curl -fsSL https://ntn.dev | bash # Or (requires Node 22+, npm 10+) npm install --global ntn ntn --version # verify ``` And there is an instruction here too. ```text Skip ntn login. Use the integration token instead. It works headless, without a browser. ``` ```bash export NOTION_API_TOKEN=$NOTION_API_KEY # ntn reads NOTION_API_TOKEN export NOTION_KEYRING=0 # do not use the OS keychain ``` Not needing a browser login is the reason this CLI exists. Browser login is impossible in a server environment or a container. The keychain is the same. There is no concept of a keychain on a server. So `NOTION_KEYRING=0` drops it to file-based auth (`~/.config/notion/auth.json`). ### Choosing a path at runtime ```bash if command -v ntn >/dev/null 2>&1; then # use ntn else # fall back to curl fi ``` This is why the skill carries both paths together. Native `ntn` is not out for Windows yet, so you install it under WSL2 or just use the HTTP path. ### File upload is the CLI's biggest win ```bash ntn files create < photo.png ntn files create --external-url https://example.com/photo.png ntn files list ``` Over HTTP it takes three steps. Create upload, PUT the bytes, reference. The CLI reduces this to one line. This difference shows when you upload an image to Notion. Useful environment variables are also laid out. | Variable | Effect | | --- | --- | | `NOTION_API_TOKEN` | Auth token (takes priority over the keychain) | | `NOTION_KEYRING=0` | File-based credentials at `~/.config/notion/auth.json` | | `NOTION_WORKSPACE_ID` | Skips the workspace selection prompt | ### Path B: HTTP + curl It is the Windows default and the general-purpose path. Every request uses the same pattern. ```bash curl -s -X GET "https://api.notion.com/v1/..." \ -H "Authorization: Bearer $NOTION_API_KEY" \ ... ``` Page creation and update accept markdown. That is why it fits agents especially well. If you handle Notion's block API directly, you have to wander through the nested block structure, but putting markdown in makes that disappear. There is also a path that reads a page as markdown. This means it is client-friendly. You read it directly without parsing block JSON. ## 2. obsidian (v1.0.0) The `note-taking` category. Built jointly by Teknium and Hermes Agent. ```text Read, search, create, and edit notes in the Obsidian vault. ``` The description is short. A vault is ultimately a folder. The design philosophy of this skill comes from there too. ### From the vault path The environment variable convention is documented. ```text OBSIDIAN_VAULT_PATH, e.g. ${HERMES_HOME:-~/.hermes}/.env If not set, ~/Documents/Obsidian Vault ``` And the pitfall appears right away. ```text File tools do not expand shell variables. Do not put a path containing $OBSIDIAN_VAULT_PATH into read_file, write_file, patch, search_files. Resolve the vault path first and pass a concrete absolute path. The vault path can contain spaces, which is also why you end up using file tools rather than shell commands. ``` This is the accident that most often happens to people migrating from the old pattern. If you put the variable in as-is, the file is not visible. If the path has a space, it breaks in the shell too. The two problems overlap and it can look like nothing works no matter how the agent fixes it. In reality it is variable non-expansion. You can use `terminal` only when the path is not yet known. Once you know it, you go back to file tools. ### Tool mapping The reason the skill explicitly pushes file tools over shell commands is in the table. ```text - Read a note: read_file. Prefer over cat (it attaches line numbers and pagination) - List notes: search_files (target: "files"). Prefer over find or ls - Search: search_files. Prefer over grep, find, ls Filename search: target: "files" + pattern Content search: target: "content" + regex + file_glob: "*.md" - Create a note: write_file. Prefer over a shell heredoc or echo (avoids quoting issues, returns a structured result) - Append: read with read_file, and if there is a stable anchor, add content to the anchor with patch Only rewrite the whole thing with write_file when there is no anchor - Partial edit: patch. Prefer over shell text substitution ``` Here you can see the real reason. `cat` has no line numbers, so re-reading later is hard. `find` and `ls` do not give structured results. A shell heredoc breaks because of quotes. `write_file` does not break and returns a result. Tool choice is not a performance issue but a safety issue. ### Two branches of appending ```text When the anchor is stable: replace the anchor with (anchor + new content) via patch When rewriting the whole thing is clearer: write_file When you need a simple addition without an anchor: terminal may be the clearest and safest choice ``` The skill writing "may be the clearest and safest choice" is practical. It does not dictate the tool. A shell heredoc is not inherently bad, and forcing a patch when there is no anchor can be worse. ### Wikilinks ```text Obsidian links notes with the [[Note Name]] syntax. When creating a note, connect related content with it. ``` If an agent does not know this when using Obsidian, it creates notes as isolated files. The knowledge graph a person builds does not get created. One line is everything. ## 3. nano-pdf (v1.0.0) The `productivity` category. Community. ```text Edit text in existing PDFs via natural-language prompts. ``` It edits PDFs with natural language. No one questions who would even build this for a single entry. ### Install ```bash uv pip install nano-pdf # recommended (already in Hermes) pip install nano-pdf ``` ### Usage ```bash nano-pdf edit "" ``` Three examples. ```bash # Change the title on page 1 nano-pdf edit deck.pdf 1 "Change the title to 'Q3 Results' and fix the typo in the subtitle" # Update a date on a specific page nano-pdf edit report.pdf 3 "Update the date from January to February 2026" # Edit content nano-pdf edit contract.pdf 2 "Change the client name from 'Acme Corp' to 'Acme Industries'" ``` You use the instruction as-is. Not "page 3, date January to February" but "Update the date from January to February 2026." English is more natural. The tool is made in English, so the examples are in English too. ### Scope and cautions ```text - For structural tasks (merge, split, forms, watermarks, generation), refer to the pdf skill - For extracting text from scans, refer to ocr-and-documents ``` The skill declares its scope precisely and hands off to others. nano-pdf does not claim structural work. ### Four pitfalls ```text - Page numbers may be 0-based or 1-based depending on the version — if the wrong page, retry with ±1 - Always verify the resulting PDF after editing (check file size with read_file, or open it) - The tool uses an LLM internally — it needs an API key (check the setup with nano-pdf --help) - It fits text changes well. Complex layout edits may need another method ``` The second is the part you really have to be careful about. The edit command may succeed while nothing changed. This is the case where the LLM misreads the instruction or cannot find the target text. The tool returns success, but the PDF is unchanged. So the skill forces "always verify." Checking the file size with `read_file` does not actually verify the PDF content. If the size is the same, it could have changed without you knowing. To check the body you have to read it separately. This skill stops after requiring only minimal verification. So in practice, opening it yourself after conversion is the right move. ## Part 6 Summary | Skill | Version | What it does | | --- | --- | --- | | notion | 2.0.0 | Integration token + ntn CLI or curl, pages/DB/markdown | | obsidian | 1.0.0 | Read, search, create, edit the vault with file tools, wikilinks | | nano-pdf | 1.0.0 | Edit PDF text via natural-language instructions | The three cover all document work. Cloud documents, local documents, and a format that rarely changes. The tool splitting according to the nature of the target is the point of this part. Next, the final Part 7 moves on to running and deploying local models directly.