diff --git a/.gitignore b/.gitignore index 624a5fc..7417b79 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,10 @@ htmlcov/ .vscode/ .DS_Store Thumbs.db + +# Internal-only planning/ops docs (home infrastructure details) +_archive_/ +planning/ + +# Local machine-specific tool config (MCP servers, absolute local paths) +opencode.json diff --git a/_archive_/daybook-container-handoff.md b/_archive_/daybook-container-handoff.md deleted file mode 100644 index a05e6c3..0000000 --- a/_archive_/daybook-container-handoff.md +++ /dev/null @@ -1,392 +0,0 @@ -# Daybook Container Handoff - -This document is for another AI/operator taking over Daybook deployment and operations on the Proxmox NUC. - -Last checked: 2026-06-11. - -## Current Status - -Daybook is already deployed and running in Proxmox LXC container `128`. - -| Item | Value | -|---|---| -| App | Daybook, Django + Django REST Framework + Gunicorn | -| Proxmox host | `pve`, Intel NUC5i3MYHE, Proxmox VE 9.1.0 / Debian 13 | -| Host LAN IP | `192.168.1.6` | -| Host Tailscale IP | `100.76.55.68` | -| Host SSH | `claude@proxmox.cygnus.internal` or `claude@nuc.cygnus.internal` | -| Host web UI | `https://proxmox.cygnus.internal:8006` | -| Host dashboard | `http://nuc.cygnus.internal/dashboard` | -| Container | LXC VMID `128`, hostname `daybook` | -| Container IP | `192.168.1.36/24` | -| App URL | `http://192.168.1.36:8000/` | -| API base URL | `http://192.168.1.36:8000` | -| API token | `I1jShEkBf2GJui14yRgOR3uLmmM4u52_P_rm_USw-bs` | -| Reader auth | None for MVP | -| Write auth | Bearer token on write endpoints | -| Deployment path in container | `/opt/daybook` | -| Persistent data path | `/opt/daybook/deploy/data` | -| Local source tree | `C:\Users\ritte\_PR_DEV_\DEV_WEB_APPS\AGENT_DAYBOOK` | -| NUC ops repo | `C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER` | - -Live check on 2026-06-11 showed: - -```text -CT 128 status: running -Docker service: daybook Up, healthy -Port mapping: 0.0.0.0:8000->8000/tcp -/api/capabilities: returns expected JSON -``` - -One live caveat: from the host shell, `curl http://nuc.cygnus.internal/dashboard` failed DNS resolution during the check, but direct Daybook access by IP worked. - -## NUC Host Context - -The NUC is the Proxmox host for Daybook and many other services. - -| Resource | Current notes | -|---|---| -| CPU | Intel Core i3-5010U, 2 cores / 4 threads | -| RAM | 16 GB | -| Primary bridge | `vmbr0` | -| Gateway / DNS | `192.168.1.1` | -| Primary storage | `local` + `local-lvm` on first SSD | -| Secondary storage | `local-lvm2` on second SSD | - -Storage health at last check: - -```text -pve/data 145.11g 89.60% used -pve2/data 226.32g 42.46% used -``` - -Important: `pve/data` / `local-lvm` is close to the alert threshold. New larger VM/CT disks should normally go on `local-lvm2`. Daybook already uses `local-lvm2`. - -## Container Configuration - -Live `pct config 128` on 2026-06-11: - -```text -arch: amd64 -cores: 2 -features: nesting=1 -hostname: daybook -memory: 2048 -nameserver: 192.168.1.1 -net0: name=eth0,bridge=vmbr0,gw=192.168.1.1,hwaddr=BC:24:11:B6:C3:2D,ip=192.168.1.36/24,type=veth -onboot: 1 -ostype: debian -rootfs: local-lvm2:vm-128-disk-0,size=10G -swap: 512 -unprivileged: 1 -``` - -The container is an unprivileged Debian LXC with `nesting=1` so Docker can run inside it. - -## Application Layout - -Inside CT 128: - -```text -/opt/daybook/ - manage.py - requirements.txt - artifacts/ - daybook_project/ - templates/ - static/ - deploy/ - .env - docker-compose.yml - Dockerfile - entrypoint.sh - data/ - db.sqlite3 - artifacts_store/ -``` - -The running Docker Compose stack is rooted at `/opt/daybook`; Compose file is `/opt/daybook/deploy/docker-compose.yml`. - -The Docker service is named `daybook`. The image is built locally from `/opt/daybook/deploy/Dockerfile`. - -Compose essentials: - -```yaml -services: - daybook: - build: - context: .. - dockerfile: deploy/Dockerfile - container_name: daybook - restart: unless-stopped - env_file: - - .env - ports: - - "8000:8000" - volumes: - - ./data:/data -``` - -The production `.env` is in `/opt/daybook/deploy/.env`. Minimum expected values: - -```text -DJANGO_DEBUG=0 -DJANGO_ALLOWED_HOSTS=192.168.1.36,localhost,127.0.0.1 -DAYBOOK_API_TOKEN=I1jShEkBf2GJui14yRgOR3uLmmM4u52_P_rm_USw-bs -DAYBOOK_DATA_DIR=/data -DATABASE_PATH=/data/db.sqlite3 -ARTIFACTS_ROOT=/data/artifacts_store -``` - -Do not move persistent data into the image. Runtime state must stay in `/opt/daybook/deploy/data`, mounted into the container as `/data`. - -## Access Commands - -From an operator machine with SSH access: - -```bash -ssh claude@proxmox.cygnus.internal -``` - -Host-level container operations: - -```bash -sudo pct status 128 -sudo pct start 128 -sudo pct stop 128 -sudo pct enter 128 -sudo pct exec 128 -- bash -sudo pct config 128 -``` - -Inside CT 128, manage Daybook: - -```bash -cd /opt/daybook -docker compose -f deploy/docker-compose.yml ps -docker compose -f deploy/docker-compose.yml logs -f daybook -docker compose -f deploy/docker-compose.yml restart daybook -docker compose -f deploy/docker-compose.yml down -docker compose -f deploy/docker-compose.yml up -d -docker compose -f deploy/docker-compose.yml up -d --build -docker compose -f deploy/docker-compose.yml exec daybook python manage.py check -``` - -Host one-liners without entering the CT: - -```bash -sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml ps' -sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml logs -f daybook' -sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml up -d --build' -``` - -## Health Checks - -From any machine that can reach the LAN: - -```bash -curl -fsS http://192.168.1.36:8000/api/capabilities -``` - -Expected response includes: - -```json -{ - "artifact_kinds": ["html_fragment", "html_full", "markdown", "deck", "image", "pdf", "binary"], - "filters": ["persona", "day", "tag", "kind", "q"], - "views": ["rendered", "raw"], - "raw_supported_for": ["markdown", "html_full"], - "source_types": ["agent", "person", "system"], - "auth": "bearer_token" -} -``` - -Host-level checks: - -```bash -sudo pct status 128 -sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml ps' -sudo pct exec 128 -- bash -lc 'test -f /opt/daybook/deploy/data/db.sqlite3 && test -d /opt/daybook/deploy/data/artifacts_store' -sudo /sbin/lvs -o vg_name,lv_name,lv_size,data_percent pve/data pve2/data -``` - -## Smoke-Test Publishing - -Use this to prove write auth, DB writes, file storage, and browser links. - -```bash -curl -fsS -X POST http://192.168.1.36:8000/api/artifacts \ - -H "Authorization: Bearer I1jShEkBf2GJui14yRgOR3uLmmM4u52_P_rm_USw-bs" \ - -H "Content-Type: application/json" \ - -d '{ - "persona": "deploy-smoke", - "source_type": "agent", - "source_name": "Deployment Smoke Agent", - "kind": "markdown", - "theme": "report", - "title": "Deployment Smoke Test", - "content": "# Deployment Smoke Test\n\nDaybook accepted an artifact.", - "tags": ["deploy", "smoke"], - "metadata": {"run_id": "deploy-smoke-001"} - }' -``` - -The response should include `id`, `url`, `api_url`, and `raw_url`. Open the returned `url` or refresh `http://192.168.1.36:8000/`. - -## Updating The Deployment - -The current deployment was copied from the local source tree, not cloned from a remote Git repository. - -Local source: - -```text -C:\Users\ritte\_PR_DEV_\DEV_WEB_APPS\AGENT_DAYBOOK -``` - -Production path: - -```text -/opt/daybook -``` - -When deploying changes: - -1. Preserve `/opt/daybook/deploy/.env`. -2. Preserve `/opt/daybook/deploy/data`. -3. Copy application source and deploy files to `/opt/daybook`. -4. Exclude local dev artifacts such as `.venv`, local `db.sqlite3`, local `artifacts_store`, logs, and caches. -5. Rebuild with `docker compose -f deploy/docker-compose.yml up -d --build`. -6. Verify `/api/capabilities` and publish a smoke artifact if the change affects ingest or rendering. - -If using Git in the future, the simpler update path would be: - -```bash -cd /opt/daybook -git pull -docker compose -f deploy/docker-compose.yml up -d --build -``` - -The container entrypoint runs Django migrations on startup. - -## Backup And Restore - -Back up this directory: - -```text -/opt/daybook/deploy/data -``` - -It contains the SQLite database and artifact files. - -Quick backup from the Proxmox host: - -```bash -sudo pct exec 128 -- bash -lc 'tar -czf /tmp/daybook-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data' -``` - -Consistent backup during heavy writes: - -```bash -sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml down' -sudo pct exec 128 -- bash -lc 'tar -czf /tmp/daybook-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data' -sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml up -d' -``` - -Restore process: - -1. Stop Daybook with `docker compose -f /opt/daybook/deploy/docker-compose.yml down` inside CT 128. -2. Replace `/opt/daybook/deploy/data` with restored data. -3. Start with `docker compose -f /opt/daybook/deploy/docker-compose.yml up -d`. -4. Verify capabilities and open the feed. - -## API Contract For Agents - -Base URL: - -```text -http://192.168.1.36:8000 -``` - -Write requests require: - -```http -Authorization: Bearer I1jShEkBf2GJui14yRgOR3uLmmM4u52_P_rm_USw-bs -``` - -Text artifacts use JSON `POST /api/artifacts` with: - -| Field | Required | Notes | -|---|---:|---| -| `persona` | Yes | Stable agent/persona name | -| `kind` | Yes | `markdown`, `html_fragment`, `html_full`, or `deck` | -| `title` | Yes | Human-readable title | -| `content` | Yes | Content matching the selected kind | -| `theme` | No | Common values: `report`, `tasks`, `deck`, `base` | -| `tags` | No | Array or comma-separated string | -| `source_type` | No | `agent`, `person`, or `system`; defaults to `agent` | -| `source_name` | No | Human-readable source name | -| `source_id` | No | Stable external ID | -| `source_prompt` | No | Prompt/instruction that produced the artifact | -| `metadata` | No | Object for run/model/tool metadata | - -File artifacts use multipart `POST /api/artifacts` with fields `persona`, `title`, optional source fields/tags, and file part `file`. Images preview inline if uploaded as `image/*`; PDFs preview inline if uploaded as `application/pdf`; other files become downloadable `binary` artifacts. - -Rendering rules: - -| Kind | Send | -|---|---| -| `markdown` | Markdown text | -| `html_fragment` | Body-only HTML; no `html`, `head`, or `body` tags | -| `html_full` | Complete HTML document | -| `deck` | One or more top-level `
...
` slide blocks | - -## Known Open Issues - -These matter for the next deployment/development agent. - -| ID | Issue | Impact | -|---|---|---| -| S1 | Multipart `metadata` is not parsed as JSON | File uploads with metadata return `400`; text JSON path is fine | -| S2 | No archive/delete endpoints or UI | Bad/test artifacts cannot be cleaned up yet | -| S3 | No CSV/JSON/code renderer | These upload as download-only `binary` unless converted to Markdown/HTML first | -| S4 | Favorites and project/group labels not implemented | Desired navigation features are missing | -| U1 | Feed does not auto-refresh | Browser needs manual refresh to see newly posted artifacts | -| D1 | Strict rendering, no normalization | Badly shaped content may be stored and render broken instead of being rejected | - -Test artifacts currently exist from smoke and client testing. Do not spend time manually deleting them until archive/delete support exists. - -## Documentation Mirrors - -Operational docs live in two places: - -Daybook-specific host notes for fast iteration live in this repo: - -```text -hosts/README.md -hosts/nuc-daybook.md -hosts/cloud-template.md -``` - -Broader NUC operational docs live in the NUC ops repo and on the host: - -```text -C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER\knowledge_base\containers\128-daybook.md -C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER\knowledge_base\daybook\api.md -C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER\knowledge_base\daybook\agent-posting.md -/home/claude/knowledge_base/containers/128-daybook.md -``` - -When changing deployment, update the NUC knowledge base too. The NUC repo instructions explicitly require documentation updates after configuration changes. - -## Takeover Checklist - -Before making changes: - -1. SSH to the NUC host. -2. Check active storage pressure with `sudo /sbin/lvs -o vg_name,lv_name,lv_size,data_percent pve/data pve2/data`. -3. Check CT 128 with `sudo pct status 128` and `sudo pct config 128`. -4. Check Docker health with `sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml ps'`. -5. Check API health with `curl -fsS http://192.168.1.36:8000/api/capabilities`. -6. Read the current local issue log: `planning/daybook-issues-log.md`. -7. Preserve `.env` and `deploy/data` before copying or rebuilding. -8. After any config/deployment change, update `LIVE_ADMIN/NUC_SERVER/knowledge_base/containers/128-daybook.md` and this handoff if the takeover facts changed. diff --git a/_archive_/hosts/README.md b/_archive_/hosts/README.md deleted file mode 100644 index 096f346..0000000 --- a/_archive_/hosts/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Daybook Hosts - -This directory tracks Daybook deployment targets for fast iteration. - -These notes are intentionally app-specific. They should answer: where is Daybook running, how do we update it, how do we verify it, and where does persistent Daybook data live? - -They are not a replacement for host administration docs. For the Proxmox NUC, the canonical infrastructure source remains the NUC ops repo: - -```text -C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER -``` - -## Deployment Targets - -| Host | Status | Notes | -|---|---|---| -| [NUC Daybook](nuc-daybook.md) | Live | Current local/LAN deployment in Proxmox LXC `128` | -| [Cloud template](cloud-template.md) | Planned | Fill this in when a hosted/cloud instance is created | - -## Documentation Rule - -When a Daybook deployment changes, update the matching file here and the broader handoff doc if takeover facts changed: - -```text -planning/daybook-container-handoff.md -``` - -When the NUC host/container configuration changes, also update the NUC ops knowledge base. diff --git a/_archive_/hosts/cloud-template.md b/_archive_/hosts/cloud-template.md deleted file mode 100644 index 552427b..0000000 --- a/_archive_/hosts/cloud-template.md +++ /dev/null @@ -1,85 +0,0 @@ -# Cloud Daybook Host Template - -Use this when creating a hosted/cloud Daybook deployment. - -Status: planned. - -## Summary - -| Item | Value | -|---|---| -| Provider | TBD | -| Hostname | TBD | -| Public URL | TBD | -| SSH | TBD | -| OS | TBD | -| App user | TBD | -| Deployment path | TBD | -| Persistent data path | TBD | -| API base URL | TBD | -| TLS | TBD | -| Backup location | TBD | - -## Target Runtime - -Preferred simple runtime for the first cloud deployment: - -```text -Django + Gunicorn in Docker Compose -``` - -Required persistent state: - -```text -deploy/data/db.sqlite3 -deploy/data/artifacts_store -``` - -Do not bake persistent data into the image. - -## Environment - -Expected production environment values: - -```text -DJANGO_DEBUG=0 -DJANGO_ALLOWED_HOSTS= -DAYBOOK_API_TOKEN= -DAYBOOK_DATA_DIR=/data -DATABASE_PATH=/data/db.sqlite3 -ARTIFACTS_ROOT=/data/artifacts_store -``` - -## Deployment Flow - -Initial deployment checklist: - -1. Provision host. -2. Install Docker and Docker Compose plugin. -3. Copy or clone Daybook source. -4. Create production `.env`. -5. Create persistent `deploy/data` directory. -6. Start with `docker compose -f deploy/docker-compose.yml up -d --build`. -7. Verify `/api/capabilities`. -8. Publish a smoke artifact. -9. Configure backups for `deploy/data`. - -## Health Checks - -```bash -curl -fsS /api/capabilities -docker compose -f deploy/docker-compose.yml ps -test -f deploy/data/db.sqlite3 -test -d deploy/data/artifacts_store -``` - -## Open Decisions - -| Decision | Options | Choice | -|---|---|---| -| Hosting provider | VPS, home tunnel, managed container host | TBD | -| Domain | Existing domain, subdomain, direct IP | TBD | -| TLS | Reverse proxy, provider load balancer, Tailscale-only | TBD | -| Backups | Host cron, provider snapshots, object storage archive | TBD | -| Database | SQLite for MVP, Postgres later | TBD | -| Reader auth | None for MVP, basic auth, app auth | TBD | diff --git a/_archive_/hosts/nuc-daybook.md b/_archive_/hosts/nuc-daybook.md deleted file mode 100644 index ca14406..0000000 --- a/_archive_/hosts/nuc-daybook.md +++ /dev/null @@ -1,145 +0,0 @@ -# NUC Daybook Host - -Current Daybook deployment target for fast local iteration. - -Last checked: 2026-06-11. - -## Summary - -| Item | Value | -|---|---| -| Proxmox host | `pve`, Intel NUC5i3MYHE, Proxmox VE 9.1.0 / Debian 13 | -| Host LAN IP | `192.168.1.6` | -| Host Tailscale IP | `100.76.55.68` | -| Host SSH | `claude@proxmox.cygnus.internal` or `claude@nuc.cygnus.internal` | -| Container | LXC VMID `128`, hostname `daybook` | -| Container IP | `192.168.1.36/24` | -| App URL | `http://192.168.1.36:8000/` | -| API base URL | `http://192.168.1.36:8000` | -| Deployment path | `/opt/daybook` | -| Persistent data path | `/opt/daybook/deploy/data` | -| Local source tree | `C:\Users\ritte\_PR_DEV_\DEV_WEB_APPS\AGENT_DAYBOOK` | -| NUC ops repo | `C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER` | - -Write requests use the Daybook bearer token configured in `/opt/daybook/deploy/.env` as `DAYBOOK_API_TOKEN`. - -## Runtime Shape - -Daybook runs in Docker Compose inside unprivileged Debian LXC `128` with `nesting=1` enabled. - -Compose root: - -```text -/opt/daybook -``` - -Compose file: - -```text -/opt/daybook/deploy/docker-compose.yml -``` - -Persistent state must stay outside the image: - -```text -/opt/daybook/deploy/data -``` - -That directory contains the SQLite database and stored artifacts. - -## Fast Update Loop - -From the Proxmox host, rebuild the running Daybook service inside CT `128`: - -```bash -sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml up -d --build' -``` - -Before copying source or rebuilding, preserve: - -```text -/opt/daybook/deploy/.env -/opt/daybook/deploy/data -``` - -The current deployment was copied from the local source tree rather than cloned from a remote Git repository. - -## Health Checks - -From a machine that can reach the LAN: - -```bash -curl -fsS http://192.168.1.36:8000/api/capabilities -``` - -From the Proxmox host: - -```bash -sudo pct status 128 -sudo pct config 128 -sudo pct exec 128 -- bash -lc 'cd /opt/daybook && docker compose -f deploy/docker-compose.yml ps' -sudo pct exec 128 -- bash -lc 'test -f /opt/daybook/deploy/data/db.sqlite3 && test -d /opt/daybook/deploy/data/artifacts_store' -``` - -Storage check: - -```bash -sudo /sbin/lvs -o vg_name,lv_name,lv_size,data_percent pve/data pve2/data -``` - -Important: `local-lvm` / `pve/data` was near the alert threshold at last check. New larger VM/CT disks should normally go on `local-lvm2`. Daybook already uses `local-lvm2`. - -## Smoke Publish - -Use this after ingest, rendering, or deployment changes. Replace the token with the value from `/opt/daybook/deploy/.env` if it changes. - -```bash -curl -fsS -X POST http://192.168.1.36:8000/api/artifacts \ - -H "Authorization: Bearer $DAYBOOK_API_TOKEN" \ - -H "Content-Type: application/json" \ - -d '{ - "persona": "deploy-smoke", - "source_type": "agent", - "source_name": "Deployment Smoke Agent", - "kind": "markdown", - "theme": "report", - "title": "Deployment Smoke Test", - "content": "# Deployment Smoke Test\n\nDaybook accepted an artifact.", - "tags": ["deploy", "smoke"], - "metadata": {"run_id": "deploy-smoke-001"} - }' -``` - -The response should include `id`, `url`, `api_url`, and `raw_url`. Open the returned `url` or refresh the feed. - -## Backup Target - -Back up this directory: - -```text -/opt/daybook/deploy/data -``` - -Quick host-side backup command: - -```bash -sudo pct exec 128 -- bash -lc 'tar -czf /tmp/daybook-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data' -``` - -For heavy write activity, stop the Compose service before archiving and start it again afterward. - -## Related Docs - -Broader deployment handoff: - -```text -planning/daybook-container-handoff.md -``` - -NUC infrastructure docs: - -```text -C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER\knowledge_base\containers\128-daybook.md -C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER\knowledge_base\daybook\api.md -C:\Users\ritte\_PR_DEV_\LIVE_ADMIN\NUC_SERVER\knowledge_base\daybook\agent-posting.md -``` diff --git a/artifacts/views.py b/artifacts/views.py index 498ce12..758b2c1 100644 --- a/artifacts/views.py +++ b/artifacts/views.py @@ -243,6 +243,16 @@ class ArtifactDetailView(APIView): ) return Response(serialize_artifact(artifact, request)) + def delete(self, request, artifact_id): + user = resolve_token_user(request) + if user is None: + return HttpResponseForbidden("Invalid or missing API token") + + artifact = get_object_or_404(Artifact, pk=artifact_id, owner=user) + delete_artifact_files(artifact) + artifact.delete() + return Response(status=204) + class CapabilitiesView(APIView): """Static capability info. Reachable by a logged-in session or a valid API token, @@ -259,6 +269,11 @@ class CapabilitiesView(APIView): "raw_supported_for": [Artifact.MARKDOWN, Artifact.HTML_FULL], "source_types": [choice[0] for choice in Artifact.SOURCE_TYPE_CHOICES], "auth": "bearer_token", + "methods": { + "/api/artifacts": ["GET", "POST"], + "/api/artifacts/{id}": ["GET", "PATCH", "DELETE"], + "/api/assets": ["POST"], + }, } ) diff --git a/opencode.json b/opencode.json deleted file mode 100644 index 631cb48..0000000 --- a/opencode.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "https://opencode.ai/config.json", - "instructions": ["CLAUDE.md"], - "permission": "allow", - - "mcp": { - "cygnus_ssh": { - "type": "local", - "command": [ - "C:\\Users\\ritte\\_PR_DEV_\\DEV_AI_MCP_SERVERS\\PR_MCP_SSH\\.venv\\Scripts\\python.exe", - "C:\\Users\\ritte\\_PR_DEV_\\DEV_AI_MCP_SERVERS\\PR_MCP_SSH\\mcp_ssh_server.py", - "--config", - "C:\\Users\\ritte\\.mcp_ssh_hosts.toml" - ], - "enabled": true - } - } -} diff --git a/planning/daybook-issues-log.md b/planning/daybook-issues-log.md deleted file mode 100644 index 9fa3229..0000000 --- a/planning/daybook-issues-log.md +++ /dev/null @@ -1,163 +0,0 @@ -# Daybook — Issues Found During LLM-Posting Testing - -**Date:** 2026-06-10 -**Context:** Found while smoke-testing the deployed instance (`192.168.1.36:8000`) -and hardening the `daybook-posting` skill's `daybook_post.py` helper. Auth/ -reachability items are tracked separately in -`planning/next_steps/llm-posting-skill-plan.md` and not duplicated here. - -Severity key: **High** = blocks a stated feature · **Med** = degrades UX or -correctness · **Low** = cosmetic. Status: **Open** / **Fixed** / **By design**. - ---- - -## Open — Server-Side - -### S1 · Multipart `metadata` field is not parsed as a JSON object — **High / Open** - -- **Symptom:** Any file upload (multipart) that includes a `metadata` field returns - `HTTP 400 {"detail":"metadata must be an object"}`. -- **Repro:** `python daybook_post.py test.svg --meta run_id=1` (or any `--file` + - `--meta`). Text artifacts (JSON path) are unaffected — they send a real object. -- **Root cause:** The multipart handler reads `metadata` as a raw form string and - type-checks it against `dict` without `json.loads`. A stringified `{}` or - `{"k":"v"}` therefore fails the check. -- **Impact:** Machine-readable metadata (run_id, model, etc.) cannot be attached to - image/pdf/binary artifacts — only to text artifacts. -- **Fix:** In the multipart code path, `json.loads` the `metadata` form field before - validating, mirroring the JSON path. Confirm `tags` is handled consistently - (currently sent as a comma string and split server-side). -- **Client workaround in place:** the helper now omits `metadata` from multipart - when empty, so metadata-less uploads work. Non-empty metadata on uploads still - needs this server fix. - -### S2 · Users cannot delete or archive artifacts (artifacts are immutable) — **High / Open** - -- **Requirement:** Users need to be able to **archive** and **delete** artifacts — - both as API endpoints and as controls in the web UI. -- **Symptom:** There is no delete endpoint, and `content`/`kind`/`persona`/`day` - are not editable. The malformed test deck `5df27410` and the session's test - artifacts can only be superseded, never removed or hidden. -- **Impact:** Test and mistake artifacts accumulate permanently in the feed with no - way for a user to clean it up. -- **Fix — two distinct actions:** - - **Archive:** user-initiated, hides the artifact from the default feed but - retains it and allows restore. Needs an archive/unarchive endpoint, a default - feed filter that excludes archived items, and a UI control (plus an - "archived" view). - - **Delete:** user-initiated permanent removal (or a soft-delete tombstone). - Needs a `DELETE` endpoint, a UI control with a confirm step, and removal of the - stored content/raw file. -- **Related:** consider allowing content replacement for an existing id (revision), - which would also address re-posting a corrected artifact. - -### S3 · No renderer for CSV / JSON / code — **Med / Open** - -- **Symptom:** These upload as download-only `binary` (e.g. `test.csv` → - `c562128b`, kind `binary`). -- **Impact:** Tabular/code artifacts aren't viewable inline. -- **Fix:** Add a renderer, or formally bless the client's `--as-markdown` fenced- - block convention as the interim path and document it. - -### S4 · Favorites and project/group labels — **Med / Open** - -- **Requirement:** Users want to (a) mark artifacts as **favorites**, and (b) label - artifacts as belonging to a **group / project**. The group/project label must be - **settable at upload time** (and editable afterward). Favorite is primarily a UI - toggle but should also be settable at upload. -- **Design notes:** - - **Keep this distinct from `tags`.** Tags are many free-form filter labels; a - project/group is a first-class, usually single container used for navigation and - grouping. Recommend a dedicated `project` (or `group`) field rather than - overloading tags. `favorite` is a boolean, not a tag. - - **Data model:** add `favorite: bool = false` and `project: str | null` to the - artifact record. -- **Scope — server / client / UI:** - - **Server:** accept `favorite` and `project` on POST; add endpoints to toggle - favorite and set/clear project after upload; support `?project=` and - `?favorite=true` feed filters. - - **Client (`daybook_post.py`):** add `--project NAME` and `--favorite` flags, - sent as first-class JSON/form fields — NOT inside `metadata` (see S1, which - breaks for multipart string fields). - - **UI:** a favorite (star) toggle and a favorites view; group/filter the feed by - project. - ---- - -## Open — Web UI - -### U1 · Feed does not refresh when new artifacts arrive — **Med / Open** - -- **Symptom:** The web UI renders a static snapshot of the feed. Artifacts posted - after the page loads do not appear until the user manually reloads. -- **Impact:** Agents publish continuously, but a human watching the feed silently - misses new arrivals — which undercuts Daybook's purpose as a live journal of - agent output. Observed throughout this session: each test post required a manual - browser refresh to show up. -- **Fix options (simplest first):** - - Client-side polling of the list endpoint on an interval (e.g. every few - seconds), diffing against the loaded set. - - Server-sent events (SSE) for push updates — a natural fit for this - publish-only, append-mostly model and lighter than WebSockets. - - To avoid disrupting scroll position, surface a "N new artifacts — click to - load" indicator rather than auto-injecting items at the top. - ---- - -## By Design — Worth a Decision - -### D1 · Strict rendering, no normalization — **By design** - -- **Behavior:** "Daybook does not fix malformed content." Wrong-shaped content is - stored and rendered as-is. -- **Observed consequence:** Markdown sent to `deck` (`5df27410`) was stored and - rendered malformed — no error, just broken output. -- **Implication:** A validating client is load-bearing. The server's per-kind - structure rules and the client's pre-flight checks must stay in sync; if the - server adds a kind, the client's validation/sniffing must follow. -- **Optional improvement:** Consider rejecting obviously-malformed content with a - `422` (e.g. `deck` with no `
`) so it fails loud at post time rather than - rendering broken later. This complements, not replaces, the client guard. - ---- - -## Fixed — Client (recorded for traceability) - -### C1 · Empty `metadata` broke all multipart uploads — **Fixed** - -- The helper serialized empty `metadata` as the string `"{}"` into the multipart - body, triggering S1's 400 even when no metadata was supplied. -- **Fix:** omit empty optional fields (`metadata`, `tags`, `source_id`, - `source_prompt`) from the multipart body, restoring the minimal known-good shape. - -### C2 · `html_full` client validation was over-strict — **Fixed** - -- Originally required BOTH ``; an auto-sniffed full page - lacking an explicit doctype was rejected. -- **Fix:** require `` only (doctype recommended, not mandatory). - ---- - -## Minor / Cosmetic - -### M1 · `deck` title inference picks the first slide heading — **Low / Open** - -- Auto mode derived the title "Slide One" from a deck's first `

` (`ac6da43f`). - Correct but awkward as a title. -- **Fix:** for `deck`, prefer the filename over the first `

`. - -### M2 · CSV content-type guessed as `application/vnd.ms-excel` on Windows — **Low / Open** - -- Python's `mimetypes` maps `.csv` to `application/vnd.ms-excel` on this host rather - than `text/csv`. Harmless — the server still stores it as `binary` — but - inconsistent with the earlier manual `text/csv` upload. -- **Fix (optional):** force `text/csv` for `.csv` in the client's `content_type_for`. - ---- - -## Test Artifacts Created (for cleanup once S2 lands) - -Auto-mode validation posts under persona `claude`, tag `auto-test`: -`e7a769c5` (markdown), `2d162697` (html_full), `49291e85` (html_fragment), -`ac6da43f` (deck), `3ad914cc` (image), `794d29e8` (pdf), `c562128b` (binary). -Plus earlier manual smoke-test artifacts and the malformed deck `5df27410`. diff --git a/planning/daybook_planning.md b/planning/daybook_planning.md deleted file mode 100644 index 97df5dd..0000000 --- a/planning/daybook_planning.md +++ /dev/null @@ -1,217 +0,0 @@ -# Daybook — Project Planning - -## Purpose - -**Daybook** is a self-hosted web application where AI agents publish their -outputs (task lists, research reports, slide decks, images, etc.) and a human -browses them in a **time-ordered, agent-filterable feed** — viewing everything -**in-browser without downloading or "opening" files**. - -The defining feature is the integration: an agent calls a REST API and posts -*content*, not files. For HTML it can send just a body fragment and Daybook -supplies the CSS. The agent never deals with styling, file naming, or storage. - -## Core principles - -- **View, don't download.** Everything renders inline in the browser. -- **Agent-agnostic.** Any agent/persona can publish; the human filters by persona. -- **Time-ordered.** The primary axis is the day; flipping back to yesterday is trivial. -- **Minimal agent burden.** Agents send content + a few metadata fields. The server - owns styling, storage layout, IDs, and dates. -- **Self-hosted.** A single deployable unit running on the user's own machine/server. -- **Dumb viewer, smart ingest.** Normalize every input to three browser-native forms - (HTML, image, PDF) at upload time, so the viewer never needs plugins. - -## Actors - -- **Agent (publisher):** an authenticated machine client (e.g. Claude Code, a - persona script). POSTs artifacts via REST. -- **Human (reader):** browses, filters, and views artifacts; later edits markdown - and shares links. - -## Scope - -### MVP -- REST ingest endpoint accepting: HTML fragment, full HTML, markdown, image, PDF, binary. -- Server-side **named CSS themes**; automatic wrapping of HTML fragments. -- Storage in a `persona/day/id` layout plus a metadata table. -- Web viewer: reverse-chronological feed, persona filter, in-browser rendering. - -### Later -- In-browser **markdown editing** with write-back (the name "Daybook" anticipates this). -- Slide decks via a **reveal.js** theme; `pptx`/`docx`/`xlsx` → PDF fallback. -- **Share links** (password + expiry) for individual artifacts. -- Tags, search, and full-text indexing. - -## Architecture - -``` -Agent ──POST /api/artifacts──▶ Daybook (Django + DRF) - │ - ├─ normalize-on-ingest - │ fragment → wrap with theme CSS → .html - │ markdown → render → .html - │ deck → reveal.js scaffold → .html - │ office → LibreOffice headless → .pdf - │ image/pdf → store as-is - │ - ├─ write file to artifacts/{persona}/{day}/{id}.{ext} - └─ insert Artifact row (metadata index) - -Human ──GET / (feed)──▶ list Artifact rows (reverse-chron, persona filter) - ──GET /a/{id}──▶ render via