Skip to content

Kody is live

Watch the launch video — what Kody is, and why it exists.

← Public packages

@kentcdodds/package-app-kit

Design tokens, PWA install/update, About/version, cache helpers, and optional realtime notes sync for Kody package apps.

starter-remix/STARTER.md

75 lines · 4.1 KB · Markdown

Remix starter template

Canonical scaffolder template for @kentcdodds/package-app-kit create-package-app (embeds via src/starter-templates.ts / scripts/embed-starter.mjs).

Requires the framework-agnostic package-app host (kody#2312+). Remix is a recipe with remount / tsconfig / island-id boilerplate — do not set kody.app.runtime.

The archived fetch template lives at starter-fetch/.

Layout (Remix recipe)

tsconfig.json              # jsx react-jsx, jsxImportSource remix/ui (+ dual file pragmas on SSR .tsx)
app/router.ts              # kody.app.entry — remount + export default { fetch }
app/routes.ts              # route(packageContext?.appBasePath ?? '', { … })
app/controllers/*.tsx      # home, about, notes, manifest, icons, version
app/middleware/*.ts        # request-id (example)
app/data/*.ts              # notes via get(KodyRuntime).packageStorage()
app/ui/*.tsx               # Document, layout, clientEntry('kody:app#…') islands
app/assets/entry.ts        # kody.app.client — run() + island registry
public/                    # kody.app.assets — styles.css + sw.js (__version.json precache)

package.json#kody.app (no runtime field — entry is a fetch handler):

{
  "entry": "./app/router.ts",
  "client": "./app/assets/entry.ts",
  "assets": "./public"
}

Hard rules

  • Import platform remix/* only (remix/ui, remix/router, remix/ui/server, …).
  • Use devDependencies.remix for editor types only — never a fat runtime remix dependency or @remix-run/*.
  • Mount-prefixed routes via packageContext.appBasePath, with remount in app/router.ts.
  • Controllers use get(KodyRuntime) for storage/context (no custom Kody middleware).
  • Root tsconfig.json sets "jsx": "react-jsx" + "jsxImportSource": "remix/ui" (supporting config).
  • Every SSR .tsx that uses JSX starts with both pragmas so host esbuild emits remix/ui automatic JSX:
    /** @jsxRuntime automatic */
    /** @jsxImportSource remix/ui */
  • Islands use explicit ids: clientEntry('kody:app#Name', function Name…).
  • No Vite/HMR; no import map for Remix (platform inlines remix/ui).
  • SW in public/sw.js reads /_assets/__version.json — no hash in source.
  • Keep app/ui/layout.tsx (and anything that imports routes) out of the browser island registry — SSR-only.

Placeholders

__PACKAGE_NAME__, __PACKAGE_ID__, __APP_TITLE__, __CACHE_NAME__, __KODY_DESCRIPTION__

List / identity mark

.kody/icon.svg is the scaffolded list mark (create-package-app / packageSave text lane). Prefer .kody/icon.png when adding a binary logo via Artifacts git. Never scaffold root community-icon.*. PWA icons/icon-192.png / icon-512.png stay product install assets — do not move them into .kody/.

After scaffold

Default tokens/theme-color are Remix-dark charcoal + cyan (match or replace when branding). Follow the After scaffolding checklist in AGENTS.template.md (becomes AGENTS.md in the new package): brand .kody/icon + PWA icons/icon-192.png / icons/icon-512.png, fill titles/description/packageName, keep local src/version.ts + src/record-version.ts, call this app's ./record-version after each publish, confirm the Remix recipe (tsconfig jsx, remount + { fetch }, clientEntry('kody:app#…')), and match manifest themeColor / backgroundColor to the mark. Optional: Lucide via scripts/add-lucide-icon.mjs.

Then smoke with packageAppFetch on /, /notes, /about, /manifest.webmanifest, icons, and /health.

Layout stability

Prefer zero content layout shift. Update prompts are a fixed dismissible toast, not an in-flow card. Same rule for other late UI: overlays or reserved space.

Press feedback

Taps that start work get immediate pending state. Busy labels use spin-delay timing (app/ui/busy.ts) so loading text does not flash on fast actions.

Errors

Use app/ui/error-banner.tsx (ErrorBanner) when a failure replaces expected content (validation, About check failed, SSR catch). Prefer toasts for short-lived action failures so layout stays stable.