coach_state for current priorities, preferences, calibration and constraints.daily_recommendations each morning.daily.ts and its dead recommendation helper functions.GET /api/coach/context now includes coach_state and identifies Val Town as the primary source.COACHING_WORKFLOW.md so future Work sessions preserve the coaching/data contract.Frontend files are now served at version-addressed URLs
(/__immutable/45/frontend/index.tsx) with
Cache-Control: public, max-age=31536000, immutable, so repeat visits load the
whole client graph from the browser cache — roughly 3× faster (~665ms → ~157ms
measured). Publishing your val bumps its version, which changes every URL, so
caches invalidate automatically. Old-version URLs return 404 after a publish
(like Next.js build assets); a reload picks up the new version.
What changed in the template:
frontend/index.html → frontend/root.tsx: the HTML
shell is now JSX and stamps asset URLs with immutableFileUrl()index.ts: serves Root() at /, and one
app.get("/__immutable/*", (c) => serveImmutableFile(c.req.path)) route
serves all frontend filesYour copy of this template doesn't update automatically. Two options:
Minimal (most of the benefit): point both routes at serveImmutableFile —
your existing bare URLs redirect into versioned space, the new route serves
them, and the whole module graph gets cached (costs one redirect per page view):
import { serveImmutableFile } from "https://esm.town/v/std/utils/index.ts";
app.get("/__immutable/*", (c) => serveImmutableFile(c.req.path));
app.get("/frontend/**/*", (c) => serveImmutableFile(c.req.path)); // was serveFile
Full upgrade (also removes the redirect): three self-contained steps —
no other files needed. Adjust the <title>, favicon, and body of Root() to
match your app's existing index.html, and stamp anything else your shell
references directly (images, css) with immutableFileUrl().
frontend/root.tsx:/** @jsxImportSource npm:hono@4/jsx */
import { raw } from "npm:hono@4/html";
import { immutableFileUrl } from "https://esm.town/v/std/utils/index.ts";
// The HTML shell for the app. It is never cached, so immutableFileUrl can stamp
// the current val version into each asset URL — the browser caches those
// immutably, and publishing the val changes the URLs, refetching exactly once.
export function Root() {
return (
<>
{raw("<!DOCTYPE html>")}
<html lang="en">
<head>
<meta charSet="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Hono Val Town Starter</title>
<script src="https://cdn.twind.style" crossOrigin="" />
<link rel="icon" href={immutableFileUrl("/frontend/favicon.svg")} type="image/svg+xml" />
</head>
<body className="font-sans text-gray-800 p-6">
<main>
<div id="root" />
</main>
<script src="https://esm.town/v/std/catch" />
<script src={immutableFileUrl("/frontend/index.tsx")} type="module" />
</body>
</html>
</>
);
}
Root and serveImmutableFile, and replace
your / and frontend file routes with:import { serveImmutableFile } from "https://esm.town/v/std/utils/index.ts";
import { Root } from "./frontend/root.tsx";
// Serve the (never-cached) HTML shell at the root /
app.get("/", (c) => c.html(Root()));
// Serve frontend files at the version-addressed URLs Root() stamps, cached immutably
app.get("/__immutable/*", (c) => serveImmutableFile(c.req.path));
frontend/index.html (and any now-unused serveFile import).