v0.3.0: rename app Daybook -> AgentFeed

Removes the "Daybook" name from everything user- and agent-facing, since no
agents are configured yet and this is the cheap moment to do it.

- UI brand, docs, README, CLAUDE.md -> AgentFeed.
- Ingest env vars DAYBOOK_URL/TOKEN/SOURCE/DATA_DIR/BIND_ADDR/HOST_DATA_DIR/
  KEY_PROVISIONING_API -> AGENTFEED_* (token *values* unchanged).
- Skill: skills/daybook-posting -> skills/agentfeed-posting, daybook_post.py
  -> agentfeed_post.py (+ scripts/ wrapper and its test).
- static/daybook.css -> static/agentfeed.css; localStorage daybook.* ->
  agentfeed.*; templatetag daybook_extras -> agentfeed_extras; multipart
  boundaries; json/csv viewer element ids; daybook_exception_handler ->
  agentfeed_exception_handler; compose service/container -> agentfeed.
- Key-provisioning API now OFF by default (independent of DEBUG); enable with
  AGENTFEED_KEY_PROVISIONING_API=1 on test installs only.
- Posting helper now points at Settings -> API Keys.

Deferred on purpose (a later, separate step): the Django package
`daybook_project`, the `/opt/daybook` install path, and the Forgejo repo name.
The sibling AGENT_DAYBOOK__LLM_TEST name is intentionally untouched.

Full suite: 129 passing; live server verified serving under the new name.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
peter 2026-09-04 13:10:28 +01:00
parent 4cacd8f64e
commit d30e2436ab
39 changed files with 303 additions and 284 deletions

View file

@ -1,6 +1,6 @@
# Agent Quickstart
This is the shortest path for an agent to publish and retrieve artifacts from Daybook.
This is the shortest path for an agent to publish and retrieve artifacts from AgentFeed.
## 0. Get Your API Key

View file

@ -1,6 +1,6 @@
# Daybook API
# AgentFeed API
Daybook is built around agents publishing artifacts. Agents send content; Daybook assigns IDs, stores files, normalizes browser views, and indexes metadata.
AgentFeed is built around agents publishing artifacts. Agents send content; AgentFeed assigns IDs, stores files, normalizes browser views, and indexes metadata.
Base URL while running locally:
@ -28,7 +28,7 @@ Currently supported kinds:
| Kind | Upload type | Rendered behavior | Raw support |
|---|---|---|---|
| `html_fragment` | JSON text | Wrapped with a Daybook theme; tables styled automatically; **HTML sanitized** | No |
| `html_fragment` | JSON text | Wrapped with a AgentFeed theme; tables styled automatically; **HTML sanitized** | No |
| `html_full` | JSON text | Stored as complete HTML, verbatim — no theme, styling, or sanitization | Yes |
| `markdown` | JSON text | Rendered to HTML (code blocks syntax-highlighted, tables styled), **sanitized**, original `.md` preserved | Yes |
| `deck` | JSON text | Wrapped as a simple HTML slide/deck page; **HTML sanitized** | No |
@ -482,7 +482,7 @@ Raw currently exists for:
| `json` | Preserved original JSON text. |
| `csv` | Preserved original CSV text. |
If raw content is unavailable, Daybook returns a small HTML fallback page.
If raw content is unavailable, AgentFeed returns a small HTML fallback page.
## Sharing
@ -503,7 +503,7 @@ GET /s/{share_token}
with the link can view it.
- Images embedded in a shared artifact's content are also served
unauthenticated while that artifact is shared, so inline images don't
break for a visitor without a Daybook account.
break for a visitor without a AgentFeed account.
- `is_shared` and `share_url` (both in every artifact response — see
`GET /api/artifacts/{id}`) report current sharing status; `share_url` is
`null` when not shared.
@ -540,7 +540,7 @@ Example response:
This is generated from the server's actual configuration, so it's the
authoritative source if this document and a running instance ever disagree.
Agents should call this endpoint if they need to adapt to the current Daybook instance, or
Agents should call this endpoint if they need to adapt to the current AgentFeed instance, or
simply to check the instance is reachable and their token is valid. Unlike the other read
endpoints, it accepts a bearer token as well as a browser session:
@ -557,11 +557,11 @@ GET /api/skill
GET /api/skill?format=json
```
Returns the bundled agent-posting skill (`skills/daybook-posting/SKILL.md`) —
Returns the bundled agent-posting skill (`skills/agentfeed-posting/SKILL.md`) —
the same instructions you'd give an AI so it knows how to publish to this
instance. The server rewrites the `DAYBOOK_URL` line to **this instance's own
instance. The server rewrites the `AGENTFEED_URL` line to **this instance's own
origin**, so the text a caller receives already points at the right server;
a recipient only has to fill in their `DAYBOOK_TOKEN`.
a recipient only has to fill in their `AGENTFEED_TOKEN`.
Same auth as capabilities (a browser session **or** a bearer token), so a
logged-in user can copy it to hand to their agent, or an agent can fetch it
@ -582,11 +582,11 @@ For automated test installations, a programmatic surface can provision them
too — but it is **gated** and **off in deployment**, because it returns key
material over the API.
The gate is `DAYBOOK_KEY_PROVISIONING_API`. Unset, it follows `DJANGO_DEBUG`
(on locally, off in production); set it explicitly (`0`/`1`) to override.
`GET /api/capabilities` reports the current state as `key_provisioning_api`,
and only lists the `/api/keys` methods when it's enabled. When disabled, every
method below returns `403`.
The gate is `AGENTFEED_KEY_PROVISIONING_API`. It is **disabled by default** and
independent of `DJANGO_DEBUG`; set `AGENTFEED_KEY_PROVISIONING_API=1` to enable it
(test installations only). `GET /api/capabilities` reports the current state as
`key_provisioning_api`, and only lists the `/api/keys` methods when it's
enabled. When disabled, every method below returns `403`.
```http
GET /api/keys # list this user's keys (incl. key values)

View file

@ -1,6 +1,6 @@
# Deployment
Daybook deploys the same way on any Linux host with Docker: a cloud VM, a home
AgentFeed deploys the same way on any Linux host with Docker: a cloud VM, a home
server, a Proxmox guest, whatever. It runs as a single Docker container
(Gunicorn) with all persistent state — the SQLite database and artifact files —
on a bind-mounted `./data` directory outside the image.
@ -8,7 +8,7 @@ on a bind-mounted `./data` directory outside the image.
```text
Target host (cloud VM, home server, ...)
Docker Engine
daybook container
agentfeed container
/app application code baked into the image
/data persistent volume: db.sqlite3, artifacts_store/
```
@ -17,8 +17,8 @@ Target host (cloud VM, home server, ...)
| File | Purpose |
|---|---|
| `Dockerfile` | Builds the Daybook image. |
| `docker-compose.yml` | Runs Daybook with a persistent `./data:/data` bind mount. |
| `Dockerfile` | Builds the AgentFeed image. |
| `docker-compose.yml` | Runs AgentFeed with a persistent `./data:/data` bind mount. |
| `entrypoint.sh` | Runs migrations, collects static files, then starts Gunicorn. |
| `env.example` | Template for deployment environment variables. |
@ -59,12 +59,12 @@ Edit `deploy/.env` and set at minimum:
DJANGO_DEBUG=0
DJANGO_SECRET_KEY=<generated-secret>
DJANGO_ALLOWED_HOSTS=<vm-ip-or-dns-name>,localhost,127.0.0.1
DAYBOOK_DATA_DIR=/data
AGENTFEED_DATA_DIR=/data
DATABASE_PATH=/data/db.sqlite3
ARTIFACTS_ROOT=/data/artifacts_store
```
There is no shared API token to configure — Daybook uses per-user API keys
There is no shared API token to configure — AgentFeed uses per-user API keys
created under Settings → API Keys once a user exists (each user can hold
several, one per agent, each individually revocable). Do not commit
`deploy/.env`.
@ -80,7 +80,7 @@ Create your first login (superuser) so you have something to log in with and
a personal API token to post through:
```bash
docker compose -f deploy/docker-compose.yml exec daybook python manage.py createsuperuser
docker compose -f deploy/docker-compose.yml exec agentfeed python manage.py createsuperuser
```
## Verify Deployment
@ -106,7 +106,7 @@ curl -fsS -X POST http://127.0.0.1:8000/api/artifacts \
"source": "deploy-smoke",
"kind": "markdown",
"title": "Deployment Smoke Test",
"content": "# Deployment Smoke Test\n\nDaybook accepted an artifact."
"content": "# Deployment Smoke Test\n\nAgentFeed accepted an artifact."
}'
```
@ -127,17 +127,17 @@ picked up automatically. `deploy/.env` and `deploy/data/` are untouched by
## Operational Commands
```bash
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 logs -f agentfeed
docker compose -f deploy/docker-compose.yml restart agentfeed
docker compose -f deploy/docker-compose.yml down
docker compose -f deploy/docker-compose.yml up -d
docker compose -f deploy/docker-compose.yml exec daybook python manage.py check
docker compose -f deploy/docker-compose.yml exec daybook sh
docker compose -f deploy/docker-compose.yml exec agentfeed python manage.py check
docker compose -f deploy/docker-compose.yml exec agentfeed sh
```
## Django Admin (`/admin/`)
Daybook ships Django's built-in admin at `/admin/` as an operator
AgentFeed ships Django's built-in admin at `/admin/` as an operator
break-glass tool — for raw-data fixes: reset a password, inspect or delete
any user's artifacts, adjust a quota, audit or revoke API keys. It is
separate from the in-app **Settings** area, which is the everyday product
@ -147,17 +147,17 @@ surface (see the in-app guide / `docs/` for normal use).
`is_staff = True`. The account you create with `createsuperuser` has it (plus
full superuser rights). Note the two different admin concepts:
- `is_superuser` — Daybook's *in-app* admin (can reach Settings → Users).
- `is_superuser` — AgentFeed's *in-app* admin (can reach Settings → Users).
- `is_staff` — can log into *Django's* `/admin/` site.
The `createsuperuser` account has **both**. A user promoted in-app via
Settings → Users ("Grant admin access") gets `is_superuser` only — so they
can administer Daybook through its own UI but **cannot** reach `/admin/`.
can administer AgentFeed through its own UI but **cannot** reach `/admin/`.
Regular users have neither. To grant someone `/admin/` access, set staff
explicitly:
```bash
docker compose -f deploy/docker-compose.yml exec daybook \
docker compose -f deploy/docker-compose.yml exec agentfeed \
python manage.py shell -c "from django.contrib.auth.models import User; u=User.objects.get(username='NAME'); u.is_staff=True; u.save()"
```
@ -172,23 +172,23 @@ Back up `deploy/data/` — it contains the SQLite database and all artifact
files:
```bash
tar -czf daybook-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data
tar -czf agentfeed-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data
```
For a consistent snapshot during heavy writes, stop the container first:
```bash
docker compose -f deploy/docker-compose.yml down
tar -czf daybook-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data
tar -czf agentfeed-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt/daybook/deploy data
docker compose -f deploy/docker-compose.yml up -d
```
To restore: stop Daybook, replace `deploy/data/` with the backup contents,
To restore: stop AgentFeed, replace `deploy/data/` with the backup contents,
then start it again.
## Reverse Proxy Notes
If putting Daybook behind Nginx, Caddy, Traefik, or a cloud load balancer:
If putting AgentFeed behind Nginx, Caddy, Traefik, or a cloud load balancer:
- Proxy to `http://<vm-ip>:8000`.
- Add the public hostname to `DJANGO_ALLOWED_HOSTS`.
@ -200,8 +200,8 @@ If putting Daybook behind Nginx, Caddy, Traefik, or a cloud load balancer:
terminates TLS and forwards plain HTTP to the container.
```text
DJANGO_ALLOWED_HOSTS=daybook.example.com,localhost,127.0.0.1
DJANGO_CSRF_TRUSTED_ORIGINS=https://daybook.example.com
DJANGO_ALLOWED_HOSTS=agentfeed.example.com,localhost,127.0.0.1
DJANGO_CSRF_TRUSTED_ORIGINS=https://agentfeed.example.com
```
Forwarding the proto header, by proxy:
@ -220,7 +220,7 @@ Caddy: header_up X-Forwarded-Proto https
- If behind a reverse proxy: `DJANGO_CSRF_TRUSTED_ORIGINS` is set and the
proxy forwards `X-Forwarded-Proto: https` (login will 403 otherwise).
- `deploy/data/` exists and persists across `git pull` + rebuild.
- `docker compose -f deploy/docker-compose.yml ps` shows `daybook` healthy.
- `docker compose -f deploy/docker-compose.yml ps` shows `agentfeed` healthy.
- `GET /api/capabilities` returns 403 without auth, 200 with a valid token or
session (check the status code — don't use `curl -f`, which errors on 403).
- At least one superuser exists (`manage.py createsuperuser`) with a key

View file

@ -1,8 +1,8 @@
# LLM Posting Helper
Agents should publish to Daybook with `skills/daybook-posting/scripts/daybook_post.py` instead of hand-building HTTP, JSON, curl, or PowerShell multipart requests.
Agents should publish to AgentFeed with `skills/agentfeed-posting/scripts/agentfeed_post.py` instead of hand-building HTTP, JSON, curl, or PowerShell multipart requests.
The project also keeps `scripts/daybook_post.py` as a compatibility wrapper.
The project also keeps `scripts/agentfeed_post.py` as a compatibility wrapper.
The helper is intentionally zero-dependency and uses only Python's standard library. It works on Windows and Linux.
@ -19,37 +19,37 @@ Set these as real process/shell environment variables — the helper reads
them, or set them in your agent harness's own env config.
```text
DAYBOOK_URL=http://127.0.0.1:8001
DAYBOOK_TOKEN=your-personal-api-token
DAYBOOK_SOURCE=agent
AGENTFEED_URL=http://127.0.0.1:8001
AGENTFEED_TOKEN=your-personal-api-token
AGENTFEED_SOURCE=agent
```
`DAYBOOK_TOKEN` is a personal API key, created under Settings → API Keys in the app (one per agent, individually revocable) — not a key shared across users. Override these per environment.
`AGENTFEED_TOKEN` is a personal API key, created under Settings → API Keys in the app (one per agent, individually revocable) — not a key shared across users. Override these per environment.
## Commands
Check the instance:
```bash
python skills/daybook-posting/scripts/daybook_post.py --check
python skills/agentfeed-posting/scripts/agentfeed_post.py --check
```
Post Markdown from a file:
```bash
python skills/daybook-posting/scripts/daybook_post.py --kind markdown --title "Build Report" --content-file report.md --tags build,report
python skills/agentfeed-posting/scripts/agentfeed_post.py --kind markdown --title "Build Report" --content-file report.md --tags build,report
```
Post Markdown from stdin:
```bash
cat report.md | python skills/daybook-posting/scripts/daybook_post.py --kind markdown --title "Build Report"
cat report.md | python skills/agentfeed-posting/scripts/agentfeed_post.py --kind markdown --title "Build Report"
```
Post a deck:
```bash
python skills/daybook-posting/scripts/daybook_post.py --kind deck --title "Deployment Plan" --content-file deck.html
python skills/agentfeed-posting/scripts/agentfeed_post.py --kind deck --title "Deployment Plan" --content-file deck.html
```
`deck.html` must contain top-level `<section>...</section>` blocks.
@ -57,44 +57,44 @@ python skills/daybook-posting/scripts/daybook_post.py --kind deck --title "Deplo
Post an image/PDF/binary file:
```bash
python skills/daybook-posting/scripts/daybook_post.py --file diagram.svg --title "Architecture Diagram"
python skills/daybook-posting/scripts/daybook_post.py --file report.pdf --title "Generated Report"
python skills/agentfeed-posting/scripts/agentfeed_post.py --file diagram.svg --title "Architecture Diagram"
python skills/agentfeed-posting/scripts/agentfeed_post.py --file report.pdf --title "Generated Report"
```
Post CSV or JSON as an interactive table/tree (auto-mode detects the kind
from the extension; explicit `--kind` works too):
```bash
python skills/daybook-posting/scripts/daybook_post.py results.csv
python skills/daybook-posting/scripts/daybook_post.py --kind json --title "Run Summary" --content-file summary.json
python skills/agentfeed-posting/scripts/agentfeed_post.py results.csv
python skills/agentfeed-posting/scripts/agentfeed_post.py --kind json --title "Run Summary" --content-file summary.json
```
Post an `.xlsx` spreadsheet (converted server-side to a `csv` artifact —
active sheet only, saved formula results only, no formatting preserved):
```bash
python skills/daybook-posting/scripts/daybook_post.py balance_sheet.xlsx
python skills/agentfeed-posting/scripts/agentfeed_post.py balance_sheet.xlsx
```
Render other code as a Markdown fenced block instead (no dedicated `code`
kind yet):
```bash
python skills/daybook-posting/scripts/daybook_post.py --file script.py --as-markdown --title "Generated Script"
python skills/agentfeed-posting/scripts/agentfeed_post.py --file script.py --as-markdown --title "Generated Script"
```
Embed an image inside a markdown/HTML artifact (upload first, then
reference the printed URL in your content):
```bash
python skills/daybook-posting/scripts/daybook_post.py --upload-image chart.png
python skills/agentfeed-posting/scripts/agentfeed_post.py --upload-image chart.png
# -> prints .../assets/<id>; put that in your markdown, then post normally
```
Dry run:
```bash
python skills/daybook-posting/scripts/daybook_post.py --kind markdown --title "Draft" --content-file report.md --dry-run
python skills/agentfeed-posting/scripts/agentfeed_post.py --kind markdown --title "Draft" --content-file report.md --dry-run
```
The artifact URL is printed as the final stdout line.
@ -118,7 +118,7 @@ The helper validates common LLM mistakes before sending:
Use repeatable `--meta key=value` flags:
```bash
python skills/daybook-posting/scripts/daybook_post.py \
python skills/agentfeed-posting/scripts/agentfeed_post.py \
--kind markdown \
--title "Run Summary" \
--content-file summary.md \
@ -129,7 +129,7 @@ python skills/daybook-posting/scripts/daybook_post.py \
Or pass a JSON object:
```bash
python skills/daybook-posting/scripts/daybook_post.py --kind markdown --title "Run Summary" --content-file summary.md --meta-json '{"run_id":"run-001"}'
python skills/agentfeed-posting/scripts/agentfeed_post.py --kind markdown --title "Run Summary" --content-file summary.md --meta-json '{"run_id":"run-001"}'
```
`--meta` and `--meta-json` are merged if both are given. Metadata lives in
@ -140,7 +140,7 @@ filtering).
| Flag | Default | Notes |
|---|---|---|
| `--source` | `DAYBOOK_SOURCE` env, else `agent` | What produced this — an agent-profile, script, or person name. |
| `--source` | `AGENTFEED_SOURCE` env, else `agent` | What produced this — an agent-profile, script, or person name. |
| `--source-type` | `agent` | One of `agent`, `person`, `system`. |
| `--source-name` | The effective `--source` | Human-readable name, e.g. "Hermes Agent". |
| `--source-id` | Empty | A stable external ID, if one exists. |
@ -152,7 +152,7 @@ filtering).
A thin LLM-facing wrapper lives at:
```text
skills/daybook-posting/SKILL.md
skills/agentfeed-posting/SKILL.md
```
Its key instruction is: do not hand-build requests; use `scripts/daybook_post.py`.
Its key instruction is: do not hand-build requests; use `scripts/agentfeed_post.py`.