113 lines
4.6 KiB
Markdown
113 lines
4.6 KiB
Markdown
---
|
|
name: obsidian-sync
|
|
description: >-
|
|
Use this skill when designing, building, or troubleshooting the Obsidian vault publishing integration, the server upload API, note normalization (wikilinks, callouts, frontmatter), or the custom Obsidian plugin.
|
|
---
|
|
|
|
# Obsidian Vault Publishing & Sync Skill
|
|
|
|
This skill guides the agent in implementing the custom Obsidian plugin and server-side ingestion workflow for publishing blog posts directly from an Obsidian vault.
|
|
|
|
> [!IMPORTANT]
|
|
> **User Content Sovereignty:** User-authored content, post titles, tags, and formatting are the highest level of truth. The sync and normalization pipelines must preserve user-authored text verbatim and never overwrite or mutate user writing without explicit instruction.
|
|
|
|
---
|
|
|
|
## 1. System Architecture
|
|
|
|
```text
|
|
+-------------------+ +-----------------------+
|
|
| Obsidian Vault | | Blog Server |
|
|
| | | |
|
|
| [Active Markdown] | POST /api/posts | /api/posts Endpoint |
|
|
| + | -------------------> | + |
|
|
| Custom Plugin | (Payload: JSON/MD) | Frontmatter Validator |
|
|
+-------------------+ | + |
|
|
| Wikilink Normalizer |
|
|
| + |
|
|
+-------------------+ | Write to `src/posts/` |
|
|
| Self-Hosted | CouchDB Sync | + |
|
|
| LiveSync Server | ===================> | 11ty Build Trigger |
|
|
+-------------------+ +-----------------------+
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Ingestion API Specification
|
|
|
|
### Endpoint: `POST /api/posts`
|
|
- **Headers:**
|
|
- `Content-Type: application/json`
|
|
- `Authorization: Bearer <API_SECRET>`
|
|
- **Request Body:**
|
|
```json
|
|
{
|
|
"slug": "sample-post",
|
|
"content": "---\ntitle: \"Sample Post Title\"\ndate: 2026-09-12\ntags: [\"#tag1\"]\n---\n\n## Content...",
|
|
"assets": [
|
|
{
|
|
"filename": "diagram.png",
|
|
"data": "<base64-encoded-image>"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
- **Response:**
|
|
- `200 OK`: `{"status": "published", "path": "/posts/sample-post/"}`
|
|
- `400 Bad Request`: `{"error": "Missing required frontmatter: title, date"}`
|
|
|
|
---
|
|
|
|
## 3. Obsidian Markdown Normalization Rules
|
|
|
|
1. **Frontmatter Invariants:**
|
|
- Must contain `title`, `date`, `tags` (array), and optional `excerpt`, `readingTime`, `draft`.
|
|
2. **Wikilinks Translation:**
|
|
- `[[article-slug]]` $\rightarrow$ `[article-slug](/posts/article-slug/)`
|
|
- `[[article-slug|Custom Label]]` $\rightarrow$ `[Custom Label](/posts/article-slug/)`
|
|
3. **Callout Translation:**
|
|
- Obsidian callouts:
|
|
```markdown
|
|
> [!NOTE]
|
|
> Informational notice
|
|
```
|
|
Must be rendered with corresponding terminal alert styling.
|
|
4. **Internal Attachments:**
|
|
- `![[screenshot.png]]` $\rightarrow$ translated to `` and written to `src/assets/images/posts/`.
|
|
|
|
---
|
|
|
|
## 4. Custom Obsidian Plugin Development
|
|
|
|
The Obsidian plugin runs inside Obsidian desktop/mobile and interacts with the Obsidian API:
|
|
1. Registers a ribbon icon (e.g. `send` or `terminal`) and a command: `Publish Current Note to Blog`.
|
|
2. Reads the active file:
|
|
```typescript
|
|
const activeFile = this.app.workspace.getActiveFile();
|
|
const content = await this.app.vault.read(activeFile);
|
|
```
|
|
3. Parses frontmatter using Obsidian's metadata cache:
|
|
```typescript
|
|
const cache = this.app.metadataCache.getFileCache(activeFile);
|
|
```
|
|
4. Sends the HTTP payload to the configured blog server URL with the Bearer token.
|
|
5. Displays an Obsidian `Notice('Published successfully to Blog!')`.
|
|
|
|
---
|
|
|
|
## 5. Self-Hosted LiveSync Compatibility
|
|
|
|
If using CouchDB-based self-hosted LiveSync:
|
|
- A local watcher or CouchDB change listener daemon can be configured to detect updates to notes marked with `published: true` or in a dedicated `Blog/` folder.
|
|
- When an update event fires, the daemon pulls the latest revision from the CouchDB database, runs the normalization pipeline, and saves it to `src/posts/`.
|
|
|
|
---
|
|
|
|
## 6. Validation & Verification
|
|
|
|
Always write automated test cases in `test/ingestion-api.test.js` before modifying or adding any functional synchronization or endpoint code:
|
|
- **Mandatory Adversarial Testing:** Include adversarial tests covering unauthorized tokens, invalid/missing frontmatter schemas, path traversals in slugs, and malformed base64 asset payloads.
|
|
- **Pre-Presentation Verification:** Run `npm test` and ensure all test cases pass before presenting the final output.
|
|
|
|
|