--- name: jotty description: "Talk to the Jotty (jotty.page) self-hosted notes + checklists app via its REST API. Use for Zoe's homework notes, reading logs, study checklists, and todos. Default to the openz instance at 10.0.0.212:3000 with the openz API key." version: 1.0.0 author: Hermes Agent (openz profile) --- # Jotty (jotty.page) — openz profile Jotty is a self-hosted, file-based notes + checklists app. This skill covers the REST API only — not the web UI. Source: https://github.com/fccview/jotty/blob/main/howto/API.md **openz instance:** - Base URL: `http://10.0.0.212:3000` - API key: `ck_ca2d142ec7d2adc2574e4aa73ecef3b0` (owner: `Zoe`) - App version confirmed live: `1.25.1` - Web UI: `http://10.0.0.212:3000/` **Auth header (all non-public endpoints):** ``` x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0 ``` **Two important gotchas before doing anything:** 1. **Port is 3000, not 80.** Health check on `10.0.0.212` (no port) returns nothing. Always use `:3000`. 2. **No CLI flag for the key** — it lives in the `x-api-key` header. If you `curl` and forget it, you get `401`. --- ## Quick verification (do this first when in doubt) ```bash curl -s -m 5 http://10.0.0.212:3000/api/health # → {"status":"healthy","version":"1.25.1","timestamp":"..."} curl -s -m 5 -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ http://10.0.0.212:3000/api/summary # → {"summary":{"username":"Zoe","notes":{...},"checklists":{...},...}} ``` If the health check returns a version, the instance is up. If `/api/summary` returns Zoe's username, the key is valid. If either fails, stop and tell the user — don't try to read/write with a broken instance. --- ## Endpoint reference (CRUD + tasks + admin) All endpoints below are `http://10.0.0.212:3000` + the path. All require the `x-api-key` header except `/api/health`. ### Notes | Method | Path | Purpose | |---|---|---| | GET | `/api/notes` | List all notes. Query: `category`, `q` (search title/content) | | GET | `/api/notes/{noteId}` | Get one note | | POST | `/api/notes` | Create. Body: `{title, content, category?}` | | PUT | `/api/notes/{noteId}` | Update. Body: `{title, content, category, originalCategory?}` | | DELETE | `/api/notes/{noteId}` | Delete | ### Checklists (regular + task type) | Method | Path | Purpose | |---|---|---| | GET | `/api/checklists` | List. Query: `category`, `type=simple\|task`, `q` | | POST | `/api/checklists` | Create. Body: `{title, category?, type?: "simple"\|"task"}` | | PUT | `/api/checklists/{listId}` | Update title/category | | DELETE | `/api/checklists/{listId}` | Delete whole list | | POST | `/api/checklists/{listId}/items` | Add item. Body: `{text, parentIndex?}` (regular) or `{text, status, time, parentIndex?}` (task) | | PATCH | `/api/checklists/{listId}/items/{itemIndex}` | Update fields: `text, description, priority, score, startDate, targetDate, estimatedTime`. Omitted fields are left unchanged. | | PUT | `/api/checklists/{listId}/items/{itemIndex}/check` | Mark complete (supports nested `0.1.2` style paths) | | PUT | `/api/checklists/{listId}/items/{itemIndex}/uncheck` | Mark incomplete | | DELETE | `/api/checklists/{listId}/items/{itemIndex}` | Delete item (nested paths supported) | ### Task checklists (Kanban) — `/api/tasks/*` | Method | Path | Purpose | |---|---|---| | GET | `/api/tasks` | List task checklists. Query: `category`, `status`, `q` | | GET | `/api/tasks/{taskId}` | Get one task | | POST | `/api/tasks` | Create. Body: `{title, category?, statuses?: [{id,label,color?,order}]}` | | PUT | `/api/tasks/{taskId}` | Update title/category | | DELETE | `/api/tasks/{taskId}` | Delete | | GET | `/api/tasks/{taskId}/statuses` | List Kanban columns | | POST | `/api/tasks/{taskId}/statuses` | Add column. Body: `{id, label, color?, order?}` | | PUT | `/api/tasks/{taskId}/statuses/{statusId}` | Update column | | DELETE | `/api/tasks/{taskId}/statuses/{statusId}` | Delete column (items fall to first available) | | POST | `/api/tasks/{taskId}/items` | Add task item. Body: `{text, status?, parentIndex?}` | | GET | `/api/tasks/{taskId}/items/{itemIndex}` | Get one item (includes nested children) | | PUT | `/api/tasks/{taskId}/items/{itemIndex}/status` | Move to column. Body: `{status}` | | DELETE | `/api/tasks/{taskId}/items/{itemIndex}` | Delete task item | ### Meta endpoints | Method | Path | Purpose | |---|---|---| | GET | `/api/health` | **Public.** `{status, version, timestamp}` | | GET | `/api/summary` | Stats: note/checklist counts, completion rates, category breakdowns | | GET | `/api/categories` | List categories with counts. Excludes archived. | | GET | `/api/user/{username}` | User info (full if self/admin, public otherwise) | | GET | `/api/tasks` | Already covered above (task checklists) | ### Admin / exports / logs | Method | Path | Purpose | |---|---|---| | POST | `/api/admin/rebuild-index` | Admin only. Body: `{username}` — rebuilds internal link index | | POST | `/api/exports` | Initiate export. Body: `{type: "all_checklists_notes"\|"user_checklists_notes"\|"all_users_data"\|"whole_data_folder", username?}` | | GET | `/api/exports` | Get export progress + download URL | | GET | `/api/logs` | Audit logs. Query: `username?, action?, category?, level?, startDate?, endDate?, success?, limit?, offset?` | | POST | `/api/logs/export` | Export logs. Body: `{format: "json"\|"csv", filters?: {...}}` | | GET | `/api/logs/stats` | Admin only — aggregated log stats | | POST | `/api/logs/cleanup` | Admin only — delete logs older than retention | The `ck_ca2d142ec7d2adc2574e4aa73ecef3b0` key is **not** an admin key — `/api/logs/stats`, `/api/logs/cleanup`, `/api/admin/rebuild-index` will return 403 if attempted. --- ## Working with this API — patterns that work ### 1. Read-then-write for updates Items are identified by **0-based index** within their parent. Indices shift when items are added/removed, so the safe pattern is: ``` GET /api/checklists/{id} → find current index for "Feed chickens" → PUT /items/{idx}/check ``` Never cache an index across operations. ### 2. Nested items use dot-path indices - `"0"` — first top-level item - `"0.1"` — second child of first item - `"2.0.1"` — first child of grandchild 0 of top-level item 2 Same path syntax works for `/check`, `/uncheck`, `DELETE`, and `parentIndex` on create. ### 3. Categories are auto-created on first use If you POST a note with `category: "Marine Biology"` and that category doesn't exist, Jotty creates it. The `/api/categories` endpoint then reflects the new tree. No need to pre-register. ### 4. Note content is markdown Jotty renders GitHub-flavored markdown. Pass markdown in the `content` field. For writing-heavy workflows (book reports, study notes), prefer this over checklists. ### 5. Search is exact-token, not fuzzy `?q=meeting` matches titles and item text containing "meeting" as a substring. For broader discovery, fetch the list and filter client-side. --- ## Common recipes for Zoe (openz profile) ### Save a quick note ```bash curl -X POST -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ -H "Content-Type: application/json" \ -d '{"title":"Marine Biology - Coral Reefs","content":"# Notes\n\n- Reefs cover <1% of ocean floor\n- ...","category":"School/Marine Bio"}' \ http://10.0.0.212:3000/api/notes ``` Capture the returned `id` for future updates. ### Add a homework item to an existing checklist ```bash # 1. Find list curl -s -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ http://10.0.0.212:3000/api/checklists | jq '.checklists[] | {id,title,items_count: (.items|length)}' # 2. Append item (use id from step 1) curl -X POST -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ -H "Content-Type: application/json" \ -d '{"text":"Read chapter 4 by Friday"}' \ http://10.0.0.212:3000/api/checklists//items ``` ### Check off a todo ```bash # Get current index (may have shifted since last read) curl -s -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ http://10.0.0.212:3000/api/checklists/ \ | jq '.checklists.items // .items | to_entries[] | select(.value.text=="Read chapter 4 by Friday") | .key' # Then mark complete (use the index above, e.g. "3") curl -X PUT -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ http://10.0.0.212:3000/api/checklists//items/3/check ``` ### Find a note by title ```bash curl -s -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ "http://10.0.0.212:3000/api/notes?q=coral" | jq '.notes[] | {id,title,category}' ``` ### Read a specific note's content ```bash curl -s -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ http://10.0.0.212:3000/api/notes/ | jq -r '.notes.content // .content' ``` ### Daily / weekly status for Zoe ```bash curl -s -H "x-api-key: ck_ca2d142ec7d2adc2574e4aa73ecef3b0" \ http://10.0.0.212:3000/api/summary ``` --- ## Error handling HTTP codes Jotty returns: - `200` — success - `400` — bad request (malformed body, missing required field) - `401` — missing or invalid `x-api-key` - `403` — admin-only endpoint hit with non-admin key - `404` — UUID not found / wrong category - `500` — server error Error body: `{"error": "message"}`. The `404`s are common when an item index is stale or `originalCategory` was wrong on update — re-GET the resource and retry with current values. --- ## Agent behavior (openz profile) When Zoe mentions something worth remembering — a homework plan, reading log, book idea, recurring task, follow-up, or anything that would benefit from being written down — **suggest** adding it as a Jotty note or checklist item. Offer the suggestion in chat; do not auto-write without asking. After creating a note or checklist, always provide the URL link so Zoe can open it directly: - Notes: `http://10.0.0.212:3000/notes/` - Checklists: `http://10.0.0.212:3000/checklists/` - Category-filtered listing: `http://10.0.0.212:3000/?category=` --- ## What this skill is NOT - **Not a web UI driver.** Use the API only. The web UI is at `http://10.0.0.212:3000/` for Zoe's browser/PWA. - **Not shared across profiles.** The instance is openz-specific. Don't reference this URL from open1 or other profiles. - **Not for large files / attachments.** Jotty stores notes as markdown text. For images/binary, host them elsewhere and link. - **Not an admin tool.** The `ck_ca2d142...` key is Zoe's user key. Admin operations (rebuild-index, log stats) will 403. --- ## Reference files - `references/api-endpoints.md` — full endpoint table copied from upstream docs (kept here in case GitHub rate-limits) - `references/live-state.md` — snapshot of Zoe's account as of first run (1 note "Zoe Test Note", 2 checklists "To-do" and "ToDo for Zoe", all in Uncategorized)