daybook/CLAUDE.md
peter c2a354809a v0.7.1: in-app password change, custom labels, always-on folders
- Settings -> Account: change your own password (current + new), session
  preserved via update_session_auth_hash.
- Custom labels: per-user palette in Settings -> Labels; apply/remove from a
  message's ... menu (menu stays open, checkmark = applied). Labels are unified
  with tags; chip colours sync to the global TagColor. New Label model +
  migration 0017; POST /a/{id}/label (session, owner-scoped, palette-validated).
- Sidebar Keep/Deleted folders are now always shown; count badge only when
  non-empty. Updates the stale 'hide when empty' note in CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 15:19:54 +01:00

78 lines
6.9 KiB
Markdown

# CLAUDE.md
## Project
AgentFeed is a self-hosted, multi-user Django + Django REST Framework web app where AI agents, scripts, or people publish artifacts and each logged-in user browses their own time-ordered, label-filterable feed.
The core product principle is: agents publish content, not files. The server owns IDs, styling, storage layout, dates, and normalization into browser-native HTML, image, or PDF outputs.
## Current MVP Decisions
- Each user has a personal ingest API token (DRF `Token` model), viewable/regenerable from Settings → Account.
- Require `source` in every artifact payload — a free-text label identifying what posted it (agent-profile, script, or person name). Ownership of the resulting artifact comes from whichever user's token authenticated the POST, not from the `source` value itself.
- `source` and `tags` together form one unified **label** system: every artifact shows all its labels next to the title, and a single `label` filter/query param matches against either.
- Require login (Django session auth) for the browser feed/UI. The JSON API accepts a per-user bearer token for both ingest (POST/PATCH/DELETE) and artifact reads (GET list/detail), owner-scoped — an agent reads back with the same token it posts with; API requests never redirect to a browser login (JSON 403 instead). `GET /api/capabilities` and `GET /api/skill` are public (no user data), so agents can bootstrap before they have a key.
- Exception to the above: an artifact can be explicitly opted into public sharing (per-artifact, owner-toggled from the feed UI) via a high-entropy `share_token`, served unauthenticated at `GET /s/{share_token}`. Not exposed via the ingest API yet — UI-only. Turning sharing off immediately invalidates the old link. Images embedded in a shared artifact are also served unauthenticated while it's shared, so inline content doesn't break for a link recipient.
- User accounts can be created from Settings → Users (superuser-only in-app page) or via Django admin. Regular users are not staff and cannot access `/admin/`. Creating a user via Settings → Users also issues their API token immediately, shown once.
- `TagColor` (label color overrides) stays global/shared across all users.
- Deleting an artifact is a **soft-delete to Trash** (`deleted_at`), not a hard removal — recoverable via the "Deleted" sidebar folder (undelete), off-quota and eviction-protected while trashed, and purged permanently via "Empty Trash". `DELETE /api/artifacts/{id}` is soft too (idempotent); trashed artifacts are hidden from all API reads. A **Keep** sidebar folder is a view over `is_kept`. Both the Keep and Deleted folders are always shown in the sidebar (even when empty); the count badge only appears when the folder is non-empty. Trash auto-purges after a ~3-day retention window via a cron-less background thread triggered by deletes (`AGENTFEED_ASYNC_PURGE`, on by default); "Empty Trash" purges immediately.
- Use random 8-character artifact IDs.
- Start as a plain Django project; add Docker after core ingest and viewer work.
- Preserve original markdown as `.md` alongside rendered `.html`.
## Architecture Notes
- Planning source: `planning/daybook_planning.md`.
- Django project: `daybook_project/`.
- Main app: `artifacts/`.
- Theme CSS: `static/themes/`.
- Feed template: `templates/artifacts/feed.html`.
- Settings templates: `templates/artifacts/settings_*.html`.
- Stored artifact files live under `artifacts_store/{source}/{YYYY-MM-DD}/`.
## Implementation Guidelines
- Prefer small, direct changes over broad abstractions.
- Keep ingest normalization server-side.
- The viewer should only need to render HTML, image, or PDF.
- Do not make agents responsible for styling, filenames, or storage paths.
- Preserve existing planning decisions unless the user explicitly changes them.
- Avoid adding backwards-compatibility code before anything has shipped.
## Development And Deployment Workflow
- Develop and test locally in this workspace by default.
- Use the local Django commands for normal iteration: `python manage.py check`, `python manage.py migrate`, and `python manage.py runserver`.
- Run the local development server on `127.0.0.1:8001`. Port `8000` may be reserved or blocked on this workstation.
- Always use this same fixed port for the dev server. Never start a second instance on a different port; if `8001` is already serving, reuse it rather than starting another.
- All artifact-posting tools (`skills/agentfeed-posting/scripts/agentfeed_post.py`, `scripts/seed_demo_artifacts.py`, and any future posting skill) must default `AGENTFEED_URL` to `http://127.0.0.1:8001` to match.
- A regular (non-superuser) user `test` / password `testpwd` must always exist in the local dev database — it's the permanent account a sibling project (`AGENT_DAYBOOK__LLM_TEST`) uses for API testing. If the local `db.sqlite3` is ever reset, recreate this exact user (e.g. via Settings → Users) before assuming that project is broken.
- Do not deploy to the Proxmox NUC during routine code iteration.
- Treat the NUC container as the local live/staging target. Deploy there only at explicit stable checkpoints, such as an end-of-day build.
- Before any NUC deployment, preserve `/opt/daybook/deploy/.env` and `/opt/daybook/deploy/data`.
- After any NUC deployment or configuration change, run the documented health checks and update the NUC ops knowledge base plus `planning/daybook-container-handoff.md` if takeover facts changed.
## Repository Notes
- `_archive_/` exists for retired or moved project docs and experiments that should not drive current implementation decisions.
- Current deployment/takeover details live in `planning/daybook-container-handoff.md`; canonical NUC infrastructure details live in the NUC ops repo.
## Commands
- Install dependencies: `pip install -r requirements.txt`
- Run migrations: `python manage.py migrate`
- Start dev server: `python manage.py runserver 127.0.0.1:8001`
- Local app URL: `http://127.0.0.1:8001/`
- Local API health check: `http://127.0.0.1:8001/api/capabilities`
- Django checks: `python manage.py check`
## API Defaults
- MVP ingest endpoint: `POST /api/artifacts`
- MVP list endpoint: `GET /api/artifacts?label=&day=&kind=&q=`
- Artifact view: `GET /a/{id}`
- Auth: personal per-user token from Settings → Account, `Authorization: Bearer <token>`. Get one by creating a superuser (`python manage.py createsuperuser`), logging in, and visiting Settings → Account.
## Claude Code / OpenCode
This project uses `CLAUDE.md` for project instructions, compatible with both Claude Code and OpenCode. OpenCode is configured to load this file via a local, untracked `opencode.json` (it contains machine-specific MCP config, so it is not committed — recreate it locally with `{"$schema": "https://opencode.ai/config.json", "instructions": ["CLAUDE.md"], "permission": "allow"}` plus whatever MCP servers you want). After changing `opencode.json`, `.opencode/`, or this file, restart your AI coding assistant so the updated instructions are loaded.