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>
- Replace the gear/username button with a round initials avatar (per-user
deterministic color via a new daybook_extras template filter); dropdown
now shows the username and keeps Settings/About/theme/logout. Sets up an
optional profile photo later.
- Regroup the settings nav into "You" (Account, API Keys, Storage, Demo
Data) and a superuser-only "Admin" (Users), About separate — the split
now reflects who each setting affects, not a flat list.
- Register ApiKey (key read-only) and TagColor in Django admin so /admin/
is complete as the operator break-glass tool, distinct from the themed
Settings product surface.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the single per-user DRF token with named, individually-revocable
API keys, so you can run one key per agent and cut off a leaked one without
disrupting the others.
- New ApiKey model (user, name, dbk_-prefixed key, created_at, last_used_at).
Data migration copies every existing authtoken 1:1 into a "default" named
key with the same value, so no client (incl. the sibling test project's
hardcoded test-user key) needs reconfiguring.
- Auth (resolve_token_user) resolves against ApiKey and stamps last_used_at,
throttled to one write/minute.
- Settings -> API Keys: table with name/key/created/last-used + per-row
revoke and a create form; keys viewable on demand. Settings -> Account now
links here; Settings -> Users issues a named initial key.
- Gated provisioning API for test installations: GET/POST /api/keys and
DELETE /api/keys/{id}, controlled by DAYBOOK_KEY_PROVISIONING_API (unset ->
follows DEBUG, so off in deployment). Advertised via key_provisioning_api
in /api/capabilities; 403 when disabled.
- Docs (api/deployment/quickstart/posting-helper), SKILL.md, and env.example
updated from "token / Settings -> Account" to "key / Settings -> API Keys".
- Tests: new API + UI suites for keys; existing token-based tests moved to
ApiKey. Full suite 129 passing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes the deploy blocker found deploying v0.1.0 to cloud-vm-1: the vendored
gridjs.umd.js ended with a //# sourceMappingURL=gridjs.umd.js.map trailer,
but that .map isn't in the repo. The strict CompressedManifestStaticFilesStorage
backend follows the reference and raises MissingFileError, aborting the
entrypoint's collectstatic so the container never served. Stripped the
debug-only trailer (no runtime effect); collectstatic now succeeds from a
pristine checkout (169 copied, 481 post-processed).
Also rolls up this release's already-committed work: GET /api/skill and the
location-agnostic posting-skill rewrite.
- Bump __version__ to 0.1.1.
- Runbook: note that a post-build crash-loop is most likely a collectstatic
MissingFileError (check docker logs), and how to clear on-server tracked
drift before checking out a tag.
- CHANGELOG: 0.1.1 entry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Single source of truth: __version__ in daybook_project/__init__.py, starting
at 0.1.0. Surfaced in two places from that constant:
- Settings -> About page (logo, name, version, description), in the settings
nav and linked from the gear menu.
- GET /api/capabilities now includes "version", so the deploy agent / tester
can confirm which version is actually running.
Release flow: bump __version__, commit, `git tag vX.Y.Z`, push tag, deploy.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
report used Georgia (serif) for body prose, which looked dated/out of place
(it's the default for markdown and html_fragment, so most text artifacts).
Switched it to the system sans stack and pinned that same stack explicitly
in tasks too, so all three document themes (base/report/tasks) share one
font family rather than matching only by inheritance. Headings, table
cells (monospace), and table headers (Arial) are unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Table cell data (td) now uses a fixed-width stack (Consolas, SF Mono, Menlo,
...) at 0.92em so columns — especially numbers — align and scan cleanly;
headers (th) use Arial/sans for clear contrast against the mono data.
Applies to markdown and html_fragment tables via the shared base.css.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
markdown/html_fragment (report, tasks, base themes) and the json/csv viewers
each used their own near-white background (cream #fffaf0, light-blue
#f7fbff, or plain white). They now all use #faf9f6 — the same off-white the
preview area uses for image/binary artifacts — so browsing across kinds is
visually consistent.
Left as-is on purpose: deck (intentional dark slide background; switching it
would require reworking its light text colors), html_full (served verbatim,
poster owns styling), and pdf (the browser's own viewer chrome). Existing
json/csv artifacts keep their baked-in #fffaf0, which is visually
indistinguishable from #faf9f6; only new ones get the exact value.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bumps the brand logo a notch; still fits within the existing top-bar
height (the filter toolbar remains the tallest element, so no layout
growth).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regenerated logo/favicon/apple-touch from daybook_icon_2.png, a genuinely
transparent PNG (vs the first icon, keyed out of a JPEG checkerboard). The
new source has a subtle neon glow rim: the top-bar logo uses a tight
alpha>=140 crop so it stays crisp on the light chrome, while the square
favicon/apple-touch keep the thin glow (looks good on dark tab bars/tiles).
Placement unchanged — logo sits in the top-left brand corner next to
"AgentFeed".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Generated a transparent PNG set from the source icon (a JPEG with a baked-in
checkerboard) by keying out the background on saturation — the arrow is
strongly saturated (0.47-0.68) while the grey/white background is 0.00, so
the cutout is clean. Produced static/logo.png (top-bar, natural aspect),
static/favicon.png (32px), and static/apple-touch-icon.png (180px).
Wired favicon + apple-touch links into all three page heads (feed, settings,
login) and placed the logo next to the "AgentFeed" title in the top bar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Establishes a clearer background hierarchy across the app chrome:
- Top bar: its own slightly darker grey (--topbar-bg).
- Both sidebar headers (pane-bars) and the content control bar: grey
(--pane-bar-bg now matches the sidebar grey instead of white).
- Artifact sidebar: grey background like the source sidebar; the rows
themselves stay white so they read as cards floating on grey.
- Preview/content area: a light off-white (--content-bg), distinct from
both the grey chrome and the white rows.
New --topbar-bg and --content-bg vars added to both light and dark
palettes. Also fixes a pre-existing bug from the dark-mode commit where
--scrollbar-thumb and --focus-ring had become self-referential (a
too-broad replace_all had clobbered their own definitions), so scrollbar
and focus-ring colors resolve correctly again. Verified both modes render
coherently.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The filter form sat at the left edge of its (wide, 1fr) grid cell, jammed
up against the brand. justify-content:center groups it in the middle of the
top bar, above the content area and roughly screen-centered.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When a single source is selected, every row in the middle sidebar repeats
that same source, so the source column is pure waste — the pane header
already names the source. The column now only shows under "All sources"
(where it's needed to tell rows apart); selecting a source hides it and
gives the width back to the artifact title. Also drops the now-dangling
row-main border-right in that state.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The UI stylesheet already centralized its palette in a :root block, so this
mostly meant (1) migrating the ~30 colors still hardcoded in rules into
variables so they flip in one place, and (2) adding a [data-theme="dark"]
override palette. Artifact rendering is untouched — those use the separate
static/themes/*.css and the preview backdrop stays white by design, since
artifacts (charts, reports) are authored light.
- Toggle lives in the gear-menu dropdown (Dark mode / Light mode), persists
to localStorage.
- A tiny inline script in each page <head> (feed, settings, login) applies
the stored theme before first paint, so dark-mode users never see a white
flash on load.
- color-scheme: dark on the dark palette makes native form controls
(inputs, buttons) render dark too.
- Semantic accents (kept=green, shared=blue, today, danger) got
dark-appropriate variants; status/data-viz colors (usage bar, tag chips)
and the white artifact backdrop are intentionally left as-is.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Any artifact can now be made publicly viewable via a share link, no login
required - opt-in per artifact, toggled from the feed UI next to Keep.
- Artifact.share_token: nullable, unique, high-entropy (secrets.token_urlsafe(32)).
NULL = not shared; SQL treats each NULL as distinct so uniqueness still
holds for the many not-shared rows.
- New public route GET /s/<token> (shared_artifact_view), completely
unauthenticated, serving the same rendered/raw content as the owner
route via a shared serve_artifact_file() helper.
- toggle_artifact_share: generates/clears the token: mirrors
toggle_artifact_keep's pattern.
- Fixed a real gap this surfaced: embedded images in a shared artifact's
content would otherwise break for an anonymous visitor, since asset_view
was owner-only. It now also allows access when the asset's parent
artifact is currently shared - unattached (orphaned) assets stay private
regardless.
- serialize_artifact now reports is_shared/share_url so the API reflects
sharing status (read-only for now; toggling stays UI-only).
- Feed UI: Share button (mirrors Keep's toggle interaction), a copyable
share-link box that appears when shared, and a "shared" badge on the
artifact row - distinct blue accent from Keep's green so both can be
visible on the same row without confusion.
Verified live end-to-end (toggle on/off, public access, fake-token 404,
old-link-dies-on-unshare, embedded-asset access before/after sharing)
before writing the 12 automated tests in tests/views/test_sharing.py.
Also fixed two unrelated stale spots noticed in docs/api.md while adding
the Sharing section: the example response was missing is_kept/size_bytes,
and the raw-content table didn't list json/csv (added earlier this
session but never documented there).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Markdown pipe-tables and hand-written html_fragment <table> markup already
rendered - the only existing rule was 'max-width: 100%', so they came out
as bare, unbordered browser-default tables. Adds borders, header
background, cell padding, and zebra striping, plus a display:block +
overflow-x:auto pattern so wide tables scroll horizontally instead of
squeezing columns or breaking page layout.
Lives in base.css, which report.css and tasks.css both @import, so it
applies to every existing and future markdown/html_fragment artifact
immediately - no agent-side change needed, since this is rendered live
from CSS rather than baked into stored HTML.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Gap 1 from planning/2026-09-02-artifact_kind_gaps_for_frequent_agent_output.md.
Chose new first-class kinds over riding on html_fragment, resolving that
doc's open design question in favor of filtering support, raw-source
preservation (like markdown's .md sidecar), and server-owned validation.
- json: validated with json.loads at post time (400 on invalid JSON),
rendered with renderjson (collapsible tree), vendored locally.
- csv: parsed server-side with the stdlib csv module into columns/rows and
handed to Grid.js as plain data - no client-side CSV-parsing plugin
needed, keeping normalization server-owned. Vendored locally (MIT).
- Both preserve their original text as a sidecar file, generalizing what
was previously markdown-only handling (storage.py's SIDECAR_SUFFIXES) so
disk-size accounting, eviction cleanup, and ?raw=1 all cover json/csv too.
- Raw JSON is embedded in a <script type="application/json"> block with
`</script` occurrences escaped (safe because JSON's \/ escape round-trips
correctly) - verified with a live </script>-injection payload against the
actual running server, not just unit tests.
New migration (0012) for the KIND_CHOICES change - SQLite doesn't enforce
choices at the schema level, but Django's migration state tracks it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Enables codehilite on the markdown renderer (Pygments, 'friendly' style,
vendored as static/themes/pygments.css) so fenced code blocks get real
syntax highlighting with zero client-side JS - matching the "themes are
CSS-only" stance in framework_artifact_rendering.md. Verified live against
the running dev instance: a fenced python block renders with highlighted
keyword/string/function spans.
This was Gap 2 from planning/2026-09-02-artifact_kind_gaps_for_frequent_agent_output.md,
picked as the first fix since it needed no new kind or design decision -
just enabling an existing markdown extension.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Daybook: a self-hosted, multi-user Django + DRF app where agents, scripts,
or people publish artifacts and each logged-in user browses their own
time-ordered, label-filterable feed.
This squashes prior local development history (kept privately on a separate
branch) into a single clean starting point for the public repository.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>