diff --git a/AGENTS.md b/CLAUDE.md similarity index 90% rename from AGENTS.md rename to CLAUDE.md index f3a95e3..a8a2c83 100644 --- a/AGENTS.md +++ b/CLAUDE.md @@ -1,4 +1,4 @@ -# AGENTS.md +# CLAUDE.md ## Project @@ -64,6 +64,6 @@ The core product principle is: agents publish content, not files. The server own - Artifact view: `GET /a/{id}` - Development token: `Authorization: Bearer dev-token` -## OpenCode +## Claude Code / OpenCode -This project is initialized with `opencode.json`, which loads this file as project instructions. After changing `opencode.json`, `.opencode/`, or this file, restart OpenCode so the updated instructions are loaded. +This project uses `CLAUDE.md` for project instructions, compatible with both Claude Code and OpenCode. The `opencode.json` configuration file loads this file. After changing `opencode.json`, `.opencode/`, or this file, restart your AI coding assistant so the updated instructions are loaded. diff --git a/_archive_/daybook-container-handoff.md b/_archive_/daybook-container-handoff.md new file mode 100644 index 0000000..a05e6c3 --- /dev/null +++ b/_archive_/daybook-container-handoff.md @@ -0,0 +1,392 @@ +# 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/opencode.json b/opencode.json index 1ec6f3f..631cb48 100644 --- a/opencode.json +++ b/opencode.json @@ -1,5 +1,18 @@ { "$schema": "https://opencode.ai/config.json", - "instructions": ["AGENTS.md"], - "permission": "allow" + "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_planning.md b/planning/daybook_planning.md index 93fc1b9..97df5dd 100644 --- a/planning/daybook_planning.md +++ b/planning/daybook_planning.md @@ -204,6 +204,7 @@ index over them, not the source of truth for content. - Webhooks or "latest artifact" endpoints for chaining agents. - Retention/archival policies per persona. - Multi-user reader auth with per-persona visibility. +- **Interactive questions artifact type:** agents send JSON with multiple-choice questions; viewer renders an interactive form; user selections are sent back to the agent via message queue, email, or API callback. Use cases: agent feedback loops, preference gathering, approval workflows. ## Open questions / decisions diff --git a/planning/light_theme.png b/planning/light_theme.png new file mode 100644 index 0000000..f6bdcaf Binary files /dev/null and b/planning/light_theme.png differ