233 lines
11 KiB
Markdown
233 lines
11 KiB
Markdown
|
|
---
|
||
|
|
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/<listId>/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/<listId> \
|
||
|
|
| 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/<listId>/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/<noteId> | 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/<id>`
|
||
|
|
- Checklists: `http://10.0.0.212:3000/checklists/<id>`
|
||
|
|
- Category-filtered listing: `http://10.0.0.212:3000/?category=<url-encoded-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)
|