stacktree-daily-brief
Publish a dated digest to stacktr.ee and, crucially, refresh it in place at the
same URL on every run. This is the publish path for the daily-brief job: a brief
the user bookmarks once and re-reads each morning, not a fresh link per day.
When to invoke
- The user wants a recurring digest: an overnight market/news brief, a standup
summary, a watchlist roundup, a daily metrics digest.
- It will be produced repeatedly (often on a schedule or an agent loop) and read at
one stable address.
- The user says "refresh it every morning", "same link, new content daily", or "set
up a daily brief".
For a one-off run report, use stacktree-agent-run-report. For a deliverable to a
client, use stacktree-client-deliverable. For a public live-status page, use
stacktree-status-dashboard.
The page shape
Produce a self-contained HTML document in the Daily brief shape: a .sheet with a
.topbar ("Morning Brief" plus a .status ok pill showing the update time, e.g.
"Updated 06:00"), a dated .eyebrow ("Tuesday, 25 June 2026"), an <h1>, and a
.lede promising a short read. Then .section blocks for the day's content, for
example Markets (.mover rows with inline-SVG .spark sparklines and .fig
up/down deltas), Top stories (<ul class="clean"> with linked sources), and a
watchlist. Close with a .foot that states it is published from a scheduled agent
and refreshed at the same link. The date and the update-time must change on every
run, the URL must not. Canonical reference: the daily-brief template in
apps/web/src/templates.ts.
Required env
STACKTREE_API_KEY=stk_live_... # generate at https://app.stacktr.ee/api-keys
This skill is authed-only by nature: refresh-in-place requires an owned site you can
update. Anonymous uploads cannot be updated and expire in 24h, so they cannot back a
daily brief. If no key is set, ask for one (or see the root stacktree-publish skill
for pay-to-provision).
The judgment this skill encodes
One site, updated in place. This is the whole point. On the first run,
publish once and record the returned id (and slug, if any). On every later run,
do not publish a new site, update the existing one:
echo "$BRIEF_HTML" | bash scripts/publish.sh --update <id-or-slug> --expires-never
or call update_site with the saved id. The user's bookmark, and any link they
shared, must keep resolving. Minting a new URL each day is the failure mode this
skill exists to prevent.
Persist the site id so the loop is stateless-safe. A scheduled run starts
fresh with no memory of yesterday. Store the brief's id/slug somewhere the next
run can read it (a project note, an env var, a tiny state file). If the id is
genuinely lost, recover it with list_sites and match by title/slug rather than
creating a duplicate. Never let "I forgot the id" become "publish a new link".
Never expire. A brief that is refreshed daily should not also be racing an
expiry clock. Publish and update with --expires-never. The content goes stale by
design and is replaced each morning; the site itself stays put.
Keep it unlisted by default; gate if it is personal. A personal brief
(watchlist, internal metrics) should stay on the unlisted token and, if it holds
anything private, get a set_password or set_email_gate. Do not give a daily
brief a public slug unless the user explicitly wants a public digest; that is the
status-dashboard pattern, not this one.
PII scan stays on (block). Briefs assembled from feeds, inboxes, or internal
metrics can pick up addresses or tokens. Keep the default and surface anything it
catches before the brief goes out.
Steps
- First run: build the brief as a complete HTML document in the page shape above,
with today's date and update-time. Publish once:
echo "$BRIEF_HTML" | bash scripts/publish.sh --expires-never
Record the returned id and url. Gate it if the content is private.
- Hand the user the URL to bookmark, and note that it will refresh at this same
address.
- Every later run (manual or scheduled): regenerate the brief with the new date and
content, then update in place:
echo "$BRIEF_HTML" | bash scripts/publish.sh --update <id-or-slug> --expires-never
or update_site. Confirm the id resolved; if not, list_sites and match rather
than re-create.
- To run unattended, wire this into the user's scheduler or agent loop so step 3
fires each morning. The update is idempotent: same site, new content.
What to tell the user
Give them the single link to bookmark, confirm it refreshes at the same address
(never a new URL), and state whether it is unlisted or gated. If you set up a
scheduled refresh, say when it runs and where the site id is persisted so the loop
keeps targeting the same page.
1---2name: stacktree-daily-brief3description: Publish a dated morning brief or digest to one stable link and refresh it in place each day, rather than minting a new URL every time. Use for a recurring digest (a market/news brief, a standup summary, a metrics digest) the user wants to bookmark once and re-read each morning. Suits a scheduled or agent-loop refresh. Produces a page in the Daily brief shape and always updates the same site via update_site, so the bookmark never breaks.4---56# stacktree-daily-brief78Publish a dated digest to **stacktr.ee** and, crucially, refresh it in place at the9same URL on every run. This is the publish path for the `daily-brief` job: a brief10the user bookmarks once and re-reads each morning, not a fresh link per day.1112## When to invoke1314- The user wants a recurring digest: an overnight market/news brief, a standup15 summary, a watchlist roundup, a daily metrics digest.16- It will be produced repeatedly (often on a schedule or an agent loop) and read at17 one stable address.18- The user says "refresh it every morning", "same link, new content daily", or "set19 up a daily brief".2021For a one-off run report, use `stacktree-agent-run-report`. For a deliverable to a22client, use `stacktree-client-deliverable`. For a public live-status page, use23`stacktree-status-dashboard`.2425## The page shape2627Produce a self-contained HTML document in the Daily brief shape: a `.sheet` with a28`.topbar` ("Morning Brief" plus a `.status ok` pill showing the update time, e.g.29"Updated 06:00"), a dated `.eyebrow` ("Tuesday, 25 June 2026"), an `<h1>`, and a30`.lede` promising a short read. Then `.section` blocks for the day's content, for31example Markets (`.mover` rows with inline-SVG `.spark` sparklines and `.fig`32up/down deltas), Top stories (`<ul class="clean">` with linked sources), and a33watchlist. Close with a `.foot` that states it is published from a scheduled agent34and refreshed at the same link. The date and the update-time must change on every35run, the URL must not. Canonical reference: the `daily-brief` template in36`apps/web/src/templates.ts`.3738## Required env3940```41STACKTREE_API_KEY=stk_live_... # generate at https://app.stacktr.ee/api-keys42```4344This skill is authed-only by nature: refresh-in-place requires an owned site you can45update. Anonymous uploads cannot be updated and expire in 24h, so they cannot back a46daily brief. If no key is set, ask for one (or see the root `stacktree-publish` skill47for pay-to-provision).4849## The judgment this skill encodes50511. **One site, updated in place. This is the whole point.** On the first run,52 publish once and record the returned `id` (and slug, if any). On every later run,53 do not publish a new site, update the existing one:54 ```bash55 echo "$BRIEF_HTML" | bash scripts/publish.sh --update <id-or-slug> --expires-never56 ```57 or call `update_site` with the saved id. The user's bookmark, and any link they58 shared, must keep resolving. Minting a new URL each day is the failure mode this59 skill exists to prevent.60612. **Persist the site id so the loop is stateless-safe.** A scheduled run starts62 fresh with no memory of yesterday. Store the brief's `id`/slug somewhere the next63 run can read it (a project note, an env var, a tiny state file). If the id is64 genuinely lost, recover it with `list_sites` and match by title/slug rather than65 creating a duplicate. Never let "I forgot the id" become "publish a new link".66673. **Never expire.** A brief that is refreshed daily should not also be racing an68 expiry clock. Publish and update with `--expires-never`. The content goes stale by69 design and is replaced each morning; the site itself stays put.70714. **Keep it unlisted by default; gate if it is personal.** A personal brief72 (watchlist, internal metrics) should stay on the unlisted token and, if it holds73 anything private, get a `set_password` or `set_email_gate`. Do not give a daily74 brief a public slug unless the user explicitly wants a public digest; that is the75 status-dashboard pattern, not this one.76775. **PII scan stays on (`block`).** Briefs assembled from feeds, inboxes, or internal78 metrics can pick up addresses or tokens. Keep the default and surface anything it79 catches before the brief goes out.8081## Steps82831. First run: build the brief as a complete HTML document in the page shape above,84 with today's date and update-time. Publish once:85 ```bash86 echo "$BRIEF_HTML" | bash scripts/publish.sh --expires-never87 ```88 Record the returned `id` and `url`. Gate it if the content is private.892. Hand the user the URL to bookmark, and note that it will refresh at this same90 address.913. Every later run (manual or scheduled): regenerate the brief with the new date and92 content, then update in place:93 ```bash94 echo "$BRIEF_HTML" | bash scripts/publish.sh --update <id-or-slug> --expires-never95 ```96 or `update_site`. Confirm the id resolved; if not, `list_sites` and match rather97 than re-create.984. To run unattended, wire this into the user's scheduler or agent loop so step 399 fires each morning. The update is idempotent: same site, new content.100101## What to tell the user102103Give them the single link to bookmark, confirm it refreshes at the same address104(never a new URL), and state whether it is unlisted or gated. If you set up a105scheduled refresh, say when it runs and where the site id is persisted so the loop106keeps targeting the same page.