~ knotless Search/
↑↓ move↵ open⇧↵ all results

peterullrich.com/hatk

AT Protocol app framework

Forked from chadtmiller.com/hatk

0
0
main
113 lines · 4.5 KB Raw History

Template System Design

Context

The hatk new command currently scaffolds a bare project with empty directories and core framework lexicons. Users building AT Protocol apps need a way to start from a working example rather than an empty shell. The Statusphere app (from the ATConf workshop) is the first template — a complete working app with custom lexicons, feeds, XRPC handlers, seeds, a Svelte frontend, and tests.

Design

CLI Interface

hatk new my-app --template statusphere
  • --template <name> selects a bundled template
  • Without --template, behaves exactly as today (bare scaffold)
  • --svelte flag is still respected; templates can also declare "svelte": true in their manifest

How It Works

  1. Scaffold first — run the normal scaffold logic (config.yaml, package.json, docker-compose.yml, Dockerfile, core dev.hatk.* lexicons, tsconfig, linting config, .gitignore)
  2. Read manifest — load template.json from the template directory
  3. Apply Svelte — if manifest declares "svelte": true, generate SvelteKit files (same as --svelte)
  4. Merge config — deep-merge template's config object into the generated config.yaml
  5. Merge dependencies — add template's dependencies and devDependencies to package.json
  6. Copy files — recursively copy all template files (except template.json) into the project, overwriting scaffold defaults where they overlap
  7. Finalize — run npm install, hatk generate types, and svelte-kit sync if Svelte

Template Location

Templates are bundled inside the hatk package at packages/appview/templates/<name>/. Discovered by listing directories in templates/.

Template Structure

packages/appview/templates/statusphere/
├── template.json
├── lexicons/
│   └── xyz/statusphere/
│       ├── defs.json
│       ├── status.json
│       └── getProfile.json
├── feeds/
│   └── recent.ts
├── xrpc/
│   └── xyz/statusphere/
│       └── getProfile.ts
├── seeds/
│   └── seed.ts
├── test/
│   ├── feeds/
│   │   └── recent.test.ts
│   └── fixtures/
│       ├── _repos.yaml
│       ├── app.bsky.actor.profile.yaml
│       └── xyz.statusphere.status.yaml
└── src/
    ├── routes/
    │   ├── +page.svelte
    │   ├── +layout.svelte
    │   └── oauth/callback/+page.svelte
    ├── lib/
    │   ├── api.ts
    │   ├── auth.ts
    │   └── query.ts
    ├── app.html
    ├── app.css
    └── error.html

template.json Manifest

{
  "description": "Statusphere example app",
  "svelte": true,
  "dependencies": {
    "@tanstack/svelte-query": "^5"
  },
  "config": {
    "oauth": {
      "scope": "atproto repo:xyz.statusphere.status?action=create&action=delete"
    }
  }
}
FieldTypeDescription
descriptionstringShown in help text / template listing
sveltebooleanAuto-enable SvelteKit scaffold
dependenciesobjectMerged into package.json dependencies
devDependenciesobjectMerged into package.json devDependencies
configobjectDeep-merged into generated config.yaml

Files to Modify

  • packages/appview/src/cli.ts — add --template flag parsing, template discovery, manifest loading, config merging, dependency merging, file copying
  • packages/appview/templates/statusphere/ — new directory with template files copied from exercise 10 (with NSIDs kept as xyz.statusphere.*, imports updated to use hatk/ package names and hatk.generated.ts)

Key Decisions

  • Templates are plain file copies — no string interpolation or parameterization
  • xyz.statusphere.* NSIDs are kept as-is (they're the app's domain, not the framework's)
  • Template's config is deep-merged, not replaced — base config (relay, plc, port, database) stays intact
  • If a template includes src/, it implies Svelte — the manifest's "svelte": true ensures the scaffold generates SvelteKit config files before the template's frontend files are copied on top

Verification

  1. Run hatk new test-app — should produce bare scaffold as before (no regression)
  2. Run hatk new test-app --template statusphere — should produce a working Statusphere app
  3. cd test-app && npm install && hatk dev — app should start and be functional
  4. Run hatk test — tests should pass