# CURRENT.md — session state Last updated: 2026-09-16 This file tracks the work state. Read it first. Update it before you stop. ## Current focus (broad) The text layer is done. Voice actions and audio work. The local LLM harness (Veskslop agent, Go + Eino) is scaffolded and smoke-tested; the daemon-side task push is next. The web UI has a first mobile draft at 390px. ## In progress - Media archive project, branch `media-scrape-project` on `veskslop-t`. Design approved 2026-09-16 (docs: [media.md](docs/media.md), [media-scraper.md](docs/media-scraper.md), [slopbot.md](docs/slopbot.md), [media-mcp.md](docs/media-mcp.md)). Decisions: scrape the channel the command is sent in; slopbot (discord.js bot core) for guild channels and the puppet core bridge for group DMs; one self-contained SQLite + media dir per scrape under `media-scrape/db/` (gitignored); links indexed by default, downloads optional, third-party embeds never downloaded; 30 GiB default limit with a 90% warning and 5% no-delete overrun, usage bar and clean button in Settings → Bot; Media and Bot top-level tabs; MCP hooks designed for C8. The slopbot scaffold (config loader, invite helper) and its discord.js dependency were added 2026-09-16. C5 smoke test: `/api/media/status` and `/api/media` answer on a daemon with no core. Checkpoints, push after each: - [x] C1 design docs, AGENTS/INDEX pointers, `.gitignore` - [x] C2 core message shape: embeds, forwards, attachment metadata - [x] C3 media-scrape store and puppet walker, tests - [x] C4 slopbot backend, tests - [x] C5 daemon wiring: `scrape media` command, MediaService, `/api/media/*` - [x] C6 Media and Bot tabs in the Web UI - [x] C7a storage limits, retention, warning/confirm flow, storage and clean API - [x] C7b Settings group: limit field with info hover, usage bar, clean modal - [x] C8 MCP service hooks (`scrape_media`, scrape reads, storage, clean; reads in `run_commands`) - [x] C10 downloader: attachment and sticker bytes, hash-addressed, serial, size-capped, retries; embeds excluded in SQL; local files served at `/api/media///file` and preferred by the Media tab. Live run 2026-09-16: scrape `...-20260916083401` fetched the 784 KB attachment; storage counted actual bytes. - [x] C11 preview caching: Discord-hosted image/GIF previews (WebP 320px, hash-addressed, 5 MiB cap, one attempt) run after every walk in both modes. Live run `...-20260916090722`: `previewed: 2`; thumbs served over `/api/media///thumb` (200). - [x] C33 Puppet history pagination. The core's `message.fetch` read the client store, which keeps only the newest messages plus the channel's first — every page was 10 messages and the walk stopped after one page (a 10-message, 4-media scrape of an ancient group with thousands of messages). It now fetches through the client's REST layer first (contiguous 100-message pages, `transport: "rest"`), store as fallback. Rebuilt and restarted the managed client; live re-run of channel `591000745164406784`: 21+ pages / 2,100+ messages and climbing, with hundreds of images/videos being indexed. - [x] C32 Group-chat clarity and puppet refresh. Group DM scrapes already worked (live-verified against the running daemon: `zıbb & fred` and a 1:1 DM, backend `puppet`, done, previews cached); the Group chat tab had shown an empty list while the core was offline. It now says so explicitly and offers Retry. Expired attachment URLs in DM/group-DM scrapes refresh through the core bridge (`message.fetch` with `before: id+1`, which returns exactly the target). - [x] C31 Batched previews. The preview pass now runs in batches (default 25) with a cooldown (default 60 s), configurable via `VESKSLOP_MEDIA_PREVIEW_BATCH` and `VESKSLOP_MEDIA_PREVIEW_BATCH_PAUSE_MS`; batching counts rows, not successes. Live log: `preview batch of 25 done, pausing 60000 ms`. - [x] C30 Preview completeness. Audio attachments and voice messages get an ffmpeg waveform strip; oversized animated GIFs fall back to an ffmpeg-read first frame instead of `too large`; transient network failures stay pending for the next backfill instead of becoming permanent. Live: a scrape with 58 audio items backfilled 13 waveforms in 40 s, serving `image/webp`. Remaining non-cached: Lottie stickers/custom emoji (not indexed as media) and embeds whose pages refuse bots (marked PRIVATE/GONE by their 403/404). - [x] C29 Attachment video previews. Discord's image proxy renders a frame for video files (`?width=320&height=320&format=webp`), so `previewUrlFor` now resizes attachment mp4/webm in links mode too and `pendingPreviews` includes non-embed videos. Live: paused-scrape videos backfilled to `image/webp` thumbs, pending queue drained to 0. - [x] C28 Media grid usability. Infinite scroll (240 px threshold) with a Load more fallback, `previewError` exposed so tiles show PRIVATE (403) or GONE (404/410) with the reason in the tooltip, and the scrape strip lists only queued/running jobs — paused scrapes move to History. - [x] C27 Non-media stream guard. Rows awaiting backfill fell back to first-frame `