App Contract
The Anyknown Framework defines the boundary an App must satisfy: the shape of the manifest, how handlers are registered, where handler files live, how pages are laid out, and what the route table supports.
The Framework defines the shape of the holes — what the platform requires.
The AI fills the holes with App-specific logic, components, and routes.
Copy-pasteable src/pages or src/components content is not part of the contract and is never documented here.
Manifest (anyknown.json)
Section titled “Manifest (anyknown.json)”Every App has an anyknown.json manifest at the project root.
It is generated by the Builder and must not be hand-edited.
{ "schemaVersion": 1, "sdkVersion": "0.0.0", "entry": { "server": "src/server.ts", "client": "src/client.svelte.ts" }, "render": "client-only", "routes": [ { "method": "GET", "path": "/products", "handler": "src/api/products/get.ts#default" }, { "method": "POST", "path": "/products", "handler": "src/api/products/post.ts#default" }, { "method": "GET", "path": "/products/:id", "handler": "src/api/products/[id]/get.ts#default" } ], "capabilities": { "db": { "provider": "sqlite" }, "storage": { "provider": "r2" } }}Fields
Section titled “Fields”| Field | Type | Description |
|---|---|---|
schemaVersion | 1 | Must be 1. Identifies the manifest format version. |
sdkVersion | string | SDK contract version. Set by the Builder. |
entry.server | string | Path to the Hono server entry. Always src/server.ts. |
entry.client | string (optional) | Path to the Svelte client entry. Required for client-only and ssr-with-hydration render modes. |
render | "client-only" | "ssr-with-hydration" | "server-only" | Rendering strategy for the App’s frontend. |
routes | ManifestRoute[] | The complete route table. Each entry maps a method + path to a handler file and export name. |
capabilities | object | Which capabilities the App uses, and their provider selections. |
Handler signature
Section titled “Handler signature”Every API handler is a Hono handler function exported as default from a file under src/api/.
import type { AppSdk } from "@anyknown/app-server"import type { Context } from "hono"
type AppVariables = { sdk: AppSdk }
export default (c: Context<{ Variables: AppVariables }>) => { const sdk = c.get("sdk") return c.json({ ok: true })}- Handlers receive a Hono
Contextobject typed with{ Variables: { sdk: AppSdk } }. - Retrieve the SDK via
c.get("sdk"). - Return any
Response-compatible value:c.json(...),c.text(...),c.html(...), ornew Response(...). - Route parameters are accessed via
c.req.param("name").
The sdk object is initialised once per request by a platform middleware.
Handlers must not call initSdk directly.
SDK initialisation (platform-managed)
Section titled “SDK initialisation (platform-managed)”The generated src/server.ts calls initSdk once per request inside a middleware and makes the result available via c.set("sdk", sdk).
This happens before any handler runs.
The raw Worker bindings (secrets, storage, etc.) are hidden from handler scope — handlers access capabilities only through sdk.
src/api/* path contract
Section titled “src/api/* path contract”Handler files live under src/api/ and follow a file-system-to-route mapping:
| File path | Route |
|---|---|
src/api/products/get.ts | GET /products |
src/api/products/post.ts | POST /products |
src/api/products/[id]/get.ts | GET /products/:id |
src/api/products/[id]/delete.ts | DELETE /products/:id |
Rules:
- The HTTP method is the file’s base name (lowercase):
get.ts,post.ts,put.ts,patch.ts,delete.ts. - Dynamic path segments are written as
[paramName]directory names and become:paramNamein the route. - The export must be named
default. - No catch-all segments (
*,**,[...slug]).
Route table
Section titled “Route table”The route table supports:
- Static segments —
/products,/about,/dashboard - Named parameters —
/products/:id,/users/:userId/posts/:postId
It does not support:
- Catch-all or wildcard segments
- Optional parameters
- Regular-expression segments
Route matching is exact: every segment of the request path must match a literal or a named parameter in the route definition. Routes are matched in declaration order; first match wins.
Four-region layout
Section titled “Four-region layout”Every page in an App is laid out using four fixed regions: header, sidebar, main, and footer.
| Region | Required | Typical use |
|---|---|---|
header | No | Navigation bar, site title, auth controls |
sidebar | No | Secondary navigation, filters, tree views |
main | Yes | Primary page content |
footer | No | Links, copyright, secondary actions |
main is always required.
The other three regions are included when the App’s design calls for them.
Each region holds a tree of components.
The root node of each region is a layout node with a type (e.g. Stack), optional props, and children.
Component model
Section titled “Component model”Components are Svelte 5 single-file components (.svelte) that live under src/components/.
Each component has an id and belongs to one or more page regions.
A component can be one of two kinds:
- Layout node — a structural container (
Stack,Grid,Flex, etc.) withtype,props,style, andchildren. - Custom node — a named component sourced from a specific file (
type: "custom",sourceFile,props).
Components use Tailwind utility classes for all styling. Class strings must be complete literal strings — no string interpolation or concatenation. This constraint exists because Tailwind’s build-time scanner can only detect literal class names.
<!-- correct --><div class="flex items-center gap-4 p-6 bg-white rounded-lg">
<!-- wrong — interpolated class strings are not detected at build time --><div class={`flex ${isActive ? "bg-blue-500" : "bg-gray-200"}`}>Client entry (src/client.svelte.ts)
Section titled “Client entry (src/client.svelte.ts)”Apps with a frontend (render mode client-only or ssr-with-hydration) have a client entry at src/client.svelte.ts.
This file mounts the Svelte 5 component tree.
It is platform-owned and generated by the Builder — do not modify it.
Freeze rule
Section titled “Freeze rule”SDK call shapes and handler/manifest signatures ARE the documented boundary (always allowed).
A copy-pasteable src/pages or src/components file, or a multi-file App skeleton, is content (forbidden — 2026-05-19 freeze).
The contract defines the shape of the holes; the AI fills the holes.