feat: implement dynamic Eleventy tiling blog, modular CSS, and agent customizations

- Add project foundation README.md and root AGENTS.md for pair programming
- Configure .agents/ rules and skills for Eleventy tiling and Obsidian publishing
- Decompose monolithic styles into modular tokens, reset, layout, and component CSS
- Implement Nunjucks layout inheritance (base.njk, post.njk, page.njk) and reusable partials
- Configure Eleventy 3 with markdown-it-anchor, syntax highlighting, and dynamic collections
- Migrate sample prototypes into dynamic dispatches lander, gateway, and Markdown posts
- Add multi-stage Dockerfile and clean-URL nginx.conf for production serving
This commit is contained in:
venus
2026-09-13 00:49:27 -05:00
parent c0f67e75a3
commit d8fb8a3699
37 changed files with 4361 additions and 7 deletions
+99
View File
@@ -0,0 +1,99 @@
---
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.
---
## 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": "reverse-engineering-iot-firmware",
"content": "---\ntitle: \"Reverse Engineering IoT Firmware\"\ndate: 2026-09-12\ntags: [\"#firmware\"]\n---\n\n## Content...",
"assets": [
{
"filename": "diagram.png",
"data": "<base64-encoded-image>"
}
]
}
```
- **Response:**
- `200 OK`: `{"status": "published", "path": "/posts/reverse-engineering-iot-firmware/"}`
- `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 `![screenshot](/assets/images/posts/screenshot.png)` 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 River Rooks 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 River Rooks 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/`.