# Akan.js LLM Context Akan.js is a convention-driven, Bun-first full-stack TypeScript framework. The important authoring unit is business intent: pages, domain modules, signals, services, stores, and UI live in predictable places so humans and coding agents can extend projects without re-deriving architecture. ## How To Use This File - Use this file for broad context. - Use `/llms/pages/**/*.md` mirrors for page-specific context. - Use source docs under `/docs`, `/references`, `/conventions`, and `/cheatsheet` for the rendered website. - Generated files and generated indexes should not be hand-edited unless the docs say so. ## Core Workflow For Agents 1. Read the relevant convention page before adding files. 2. Keep business logic near the domain module that owns it. 3. Prefer Akan CLI generation and scan workflows over hand-writing generated surfaces. 4. Respect server/client import boundaries. 5. Run the smallest relevant lint, test, or build command after changes. ## Business Service Source: /docs/arch/backend Mirror: /llms/pages/docs/arch/backend.md Priority: P0 Headings: - Business Service Architecture - Two Actions, End To End - Endpoint, Slice, Internal - Bounding A Call - Work That Outlives The Request - What A Service Is Handed - Where An Error Belongs - The Same Endpoints, For Agents Business Service Business Service Architecture A customer taps Order on the kiosk, and that one button has to do four things: refuse the order when the mango has run out, write the order down, hand back a receipt now, and put the ticket on the kitchen screen before the customer turns away. One tap, four jobs One tap on the kiosk reaches the business service, which checks the stock, saves the order, hands back a receipt, and puts a ticket on the kitchen screen. None of that is drawing a screen. Together it is the business service: the action a request asks for, the business rule behind it, the background job it starts, and the change other screens must be told about. Every module splits that work across the same three files, and the split never changes. A request arrives at the API port and passes through them in order: One module, top to bottom Browser · mobile app · agent API port rules · other services schema · filters Stored data Each file answers one question, and only that one: - signal.ts — The phone operator — May this caller ask at all? — Takes the call, refuses the ones that should never reach the floor, and hands valid work to the right service. - service.ts — The business owner — What should happen? — Stock rules, payment status, reservation conflicts and external APIs are combined here into one meaningful action. - document.ts — The archive and its rulebook — How is the record stored, and which changes will it accept? — The stored form, the query filters, and the state changes a record will accept. A chain method mutates and returns this; the caller saves. Words used on this page Term - guard: A class that decides who may make a call. Every endpoint names its own in the signal file. - generated CRUD: The create, read, update and remove endpoints every model already has. You never write them. - chain method: A state change on the document: it checks, mutates and returns this. The caller saves. - adaptor: A singleton that wraps an outside system, such as a POS terminal, and is plugged into a service. - room: A pubsub channel. Every screen subscribed to it receives what the server publishes there. **The layers are not a formality.** A rule written into the kiosk screen ships once per client and drifts. The same rule on the service is one answer for the kiosk, the admin console, the mobile app and an AI agent, because all four arrive through the same endpoint. Two Actions, End To End Let's follow two real actions from the counter through the three files: A customer places an order Creating an order is generated CRUD, so no endpoint is written for it. What you write is the rule: an order takes stock out of today's inventory. Staff move it to the next status ## CSS And Styling Source: /docs/arch/css Mirror: /llms/pages/docs/arch/css.md Priority: P0 Headings: - Styling Foundation - Design System First - Theme System Declaration - Lib-Owned Tokens - Font Declaration CSS And Styling Styling Foundation When every screen writes its own colors (#ff493b here, a red utility class there), changing the brand or adding a dark theme means hunting down each one. Akan avoids that by naming colors for what they are for, and letting every screen use the names. Akan uses Tailwind CSS with a semantic design-token layer and the akanjs/ui primitives as the default styling foundation. So app screens say primary, background, warning or destructive instead of hard-coding every color. The two halves split the work like this: Structure and layout A fast utility language for layout, spacing, responsive behavior and one-off composition. Tokens + akanjs/ui Theme-aware colors and components Semantic color names and primitives (Button, Badge, Input, Field …) that follow the theme. Words used on this page Term - semantic token: A color named for its role (primary, background, destructive) instead of its value. - theme: One set of values for every token. The data-theme attribute picks which set applies. - primitive: A ready-made akanjs/ui component (Button, Input, Badge, Field) that already uses the tokens. - custom property: A CSS variable such as --primary. Tokens are custom properties underneath. How the layers work together Four layers, each built from the one below From the bottom up: semantic tokens, recipes that compose them into looks, components that add behavior, and screens that assemble components. Every color on a screen traces back to a token. Layer What it does - tokens: Brand decisions turned into names such as primary, background, warning and destructive. - recipes: Functions that compose token classes into one named look, such as buttonRecipe. - components: akanjs/ui primitives (Button, Input, Badge) and Tailwind utilities that use those names. - screens: Business screens assembled from components, without repeating raw color and spacing rules. Tokens are declared in page/styles.css, which also imports Tailwind and the Akan UI styles. The Theme System section below shows that file; the UI Recipe page covers the recipe layer. Design System First A page designed from scratch drifts: its buttons end up a little rounder, its borders a little lighter than the page next to it. So define the app's basic component style first, and let pages only assemble those components. Buttons, inputs, cards, forms, alerts, tabs, modals and navigation share the same spacing, radius, text color, border and state behavior, through shared classes. Business pages assemble the design system instead of redefining colors and spacing. Imported modules feel consistent too, because they use the same Tailwind and semantic design tokens. ## UI Architecture Source: /docs/arch/frontend Mirror: /llms/pages/docs/arch/frontend.md Priority: P0 Headings: - UI Architecture - How A Page Reaches The Browser - What Earns A Client Component - In Domain UI The Rule Is Mechanical - Splitting One Screen - Measuring The Split UI Architecture Every component in an Akan app runs in one of two places. A server component runs once on the server and reaches the browser as finished HTML. A client component — a file that starts with "use client" — reaches the browser as HTML too, but then its JavaScript follows, and the browser runs it again before its buttons and inputs work. This page is about deciding which of the two each piece of a screen should be. The mistake it exists to prevent looks like this: one button in a file needs an onClick, so "use client" goes on top. The file is two hundred lines of product markup and one handler, and now all two hundred lines ship twice. A client file ships twice A file marked use client travels to the browser twice: once as HTML the user can already read, and again as JavaScript the browser must download and re-run before the one button in it works. That is why Akan is SSR-first. Server is the default, and "use client" is a cost you justify for each component rather than a habit. The good news is that the line is mostly mechanical: the sections below show which features need the browser, how domain files decide for you, and how to measure where your app stands. Words used on this page Term - server component: Runs once on the server and arrives as HTML. None of its JavaScript reaches the browser. - client component: A file that starts with "use client". It arrives as HTML, then again as JavaScript in the bundle. - hydrate: The browser re-runs a client component's JavaScript so the HTML on screen responds to input. - shell: The first HTML the server sends. What the page awaited is in it; streamed sections follow. - island: One hydrated client component inside HTML the server rendered. `akan quality ssr` prints each app's and lib's server render share: the portion of JSX elements rendered on the server. **50% is the floor**, and a falling share is a regression. If a change moves markup to the client, say why, or move it back. How A Page Reaches The Browser Server-side rendering means the server builds the first HTML before the browser has loaded the app. A customer can already read the order list, the prices and the policy text while the filter and the submit button are still on their way. One request, end to end User Browser fetch.init and fetch.view Akan server request slice query init payload shell HTML, server components already rendered the user can read the page here each section streams in as its own promise lands hydrate the client islands only the user can now type and click Reading and interacting do not have to start at the same moment, so it helps to think of them as two separate clocks: ## Runtime And Infra Source: /docs/arch/infra Mirror: /llms/pages/docs/arch/infra.md Priority: P0 Headings: - Infra Architecture - Which Option Should I Use? - How Traffic Moves - Database Mode - Growth Stages Runtime And Infra Stable Beta Infra Architecture The business code you write is the same wherever it runs. What changes between a laptop and a cloud is everything around it: where traffic enters, where the app runs, and how data and deployments are managed. That surrounding layer is what this page calls infrastructure. Akan apps run on a developer machine or in a cloud cluster, and the same application code is packaged for both. The infrastructure falls into three areas: Area - Local: Your own machine, for fast iteration: MVP screens, feature prototypes and debugging. - Cloud Cluster: A Kubernetes runtime for shared team environments and production-like workloads. - Master: The deployment control area: CI/CD, environment files, secrets and release automation. Infrastructure shape A developer ships through the master infra — CI/CD, environment files and secrets — into a cloud cluster, where the Akan app runtime serves users and their devices. Words used on this page Term - container: The app packaged with everything it needs, so it starts the same way on any server. - pod: Kubernetes's unit of running: one or more containers placed together on one server (a node). - Ingress: The cluster's front door. It takes outside traffic for a domain and routes it inward. - Service: A stable address inside the cluster that forwards to whichever pods run the app. - chart: A Helm package of Kubernetes manifests. The one Akan ships lives in infra/app. - Secret: A Kubernetes object that hands private values, such as database URLs, to pods as env vars. - ReadWriteOnce, ReadWriteMany: Volume access modes: one node mounts the first, pods on many nodes share the second. - WAL: SQLite's write-ahead log mode, which lets reads keep going while a write is in progress. **There is no edge infrastructure to set up.** infra/ carries the cluster chart and the deployment control area only, so an edge site is one container you run yourself: set `AKAN_PUBLIC_OPERATION_MODE=edge` and `AKAN_DATABASE_MODE=single`, and point `AKAN_SQLITE_DIR` at a volume, which then holds its database and its cache and queue file. The operation mode is independent of the database mode, and only an `internal` job can be scoped to it (`operationMode: ["cloud"]`), never an endpoint. Which Option Should I Use? Start from the product situation, not from the infrastructure name. A small internal tool, a team QA environment and a production service need different levels of infrastructure, so start from the one that describes where you are today: - MVP or feature prototype — Local — Use local development first. Keep the setup small until the product needs shared data, shared testing, or deployment automation. - Team QA or staging — Cloud · debug / develop — Use cloud deployment with debug or develop environments so the team can test the same service together. - Production service — Cloud · main — Use the main branch of the same cloud deployment. The chart runs one pod in single mode; before traffic outgrows it, move that branch to cluster mode with your own Postgres and Redis. How Traffic Moves Infrastructure does not change the business code inside your app. It decides how a request reaches the Akan runtime. The path is simple on your laptop and goes through a structured layer in a cloud cluster. ## Native App Architecture Source: /docs/arch/mobile Mirror: /llms/pages/docs/arch/mobile.md Priority: P0 Headings: - Native App Architecture - Native Targets - CSR Runtime - Native Bridge Native App Architecture Akan ships the same product to the web, the app stores and the desktop, and you do not write a second app for any of them. The screens you already built for the web run inside a thin native app; only the parts that truly need the device, such as packaging, signing and device features, are native. Concretely, an Akan native app is a CSR web client running inside a native shell that akanjs's own runtime, @akanjs/native, generates. The product screen is still built with Akan page, UI, state, and service patterns; the runtime supplies the shell, app identity, store package, and device bridge from what akan.config.ts declares. The same target also builds a macOS, Windows or Linux app. A desktop app calls the shared backend like a phone does, or, with native.desktop.server on, carries the app's own server: it starts beside the window on a loopback port, keeps its data on that computer, and is the only backend the pages call, so the app works with no server elsewhere. Akan native app architecture The Akan app builds a CSR client that runs inside the Akan native shell on a phone and on a laptop. The shell is packaged for iOS and Android and for macOS, Windows and Linux, and every package talks to the shared Akan backend. Words used on this page Term - CSR: Client-side rendering: the app draws every screen itself from JavaScript on the device. - native runtime: @akanjs/native, shipped inside akanjs. It builds your CSR client into iOS, Android, macOS, Windows and Linux apps, with no Xcode project, Gradle files or CocoaPods to keep. - native shell: The small native app around your web client, built under dist/native///build: icon, ID, signing. - plugin: A native runtime plugin that exposes one device feature to JavaScript, such as camera, push or iap. This is the native bridge. - target: One native package built from an Akan app, with its own name and app ID. Who owns what - One UI surface — Written once, shared with the web — Web and native apps share the same Akan page tree, client router, generated fetch calls, dictionaries, and UI components. - Native shell boundary — What the native runtime generates — Native code owns packaging, signing, app capabilities, plugin linking, and store distribution. - Shared backend — The server you already run — Web clients and native apps call the same Akan services and can share auth, permission, database rules, and app-level domains. A desktop app whose target carries the server calls the copy of that server it carries instead. Native Targets Sometimes one product is really two apps in the store, such as a customer app and a staff app. Each needs its own name and app ID, yet both should run on the same backend. Native targets are for exactly that. A native target is one native package built from an Akan app. A single Akan app can publish several packages by pointing each target at a different basePath while reusing the same backend modules. A target takes from native every value it does not set itself. One app, two store packages One Akan app builds two store packages, a store app and an admin app, each opening its own basePath, and both talk to the same backend. — each basePath gets its own domain. — what every target shares, here the version and build number. — one entry per package, each with its own basePath, display name and app ID. Give each basePath its own host: the server resolves an incoming host to exactly one basePath, so two basePaths sharing a domain leave one of them unreachable. Use targets when packages need different app IDs, display names, entry surfaces, permissions, deep links, or store release tracks. CSR Runtime An app feels native because of small things: screens slide in, content stays clear of the notch, the tab bar stays put, and the keyboard does not cover the input. You get all of them without rewriting any UI in native code. The mobile page frame ## Architecture Overview Source: /docs/arch/overview Mirror: /llms/pages/docs/arch/overview.md Priority: P0 Headings: - Architecture Overview - One App, Many Surfaces - The Main Runtime Conversation - Architecture Areas Architecture Overview Why does one product need a frontend repository, a backend repository, a mobile project, and an infra chart before a customer can place a single order? Akan starts from the behavior instead. A customer sees a screen, takes an action, business rules decide what should happen, data changes, other clients may be notified, and the same app is packaged for web, mobile, cloud, or edge. This page is the map, not the territory. Each area below owns a different kind of decision, and the product stays legible as long as those decisions stay where they belong. Three rules hold across all of them: Behavior First Write business behavior first, then let generated helpers reduce API and state glue. One Service, Many Clients One business service layer serves every client surface: SSR web, CSR web, admin, partner, and mobile. Deploy Later Choose the deployment shape after the product needs it: local first, then cloud, edge, or hybrid. One App, Many Surfaces Akan is designed for products that rarely have only one screen. A store customer page, an admin console, a partner client, a mobile app, and an edge device workflow present different interfaces while sharing the same rules and the same data. Surface map A store page, an admin console, a partner client, a mobile app and an edge device all reach one shared business service — signal, service and document — through fetch, st, Model and usePage. The point is not to force every client to look the same. The point is to let different clients reuse the same business truth while presenting the right workflow for each audience. The Main Runtime Conversation Almost every Akan feature is one conversation between the interface and the business service. The interface shows useful content and captures intent; the business service receives a safe request, decides the rule, changes data, and may trigger background or realtime follow-up work. One request, end to end User Screen Page and client components reads the SSR first view, then types, clicks, filters intent valid work only endpoint · slice · internal — guards and boundaries run here load and write rules · external APIs · DI · background · realtime documents schema · query · sort · methods · statics ## UI Composition Source: /docs/arch/ui-composition Mirror: /llms/pages/docs/arch/ui-composition.md Priority: P0 Headings: - UI Composition - The Shape Of A Model Screen - The Load Shells - The CRUD Modals - Forms Are Store-Driven - One Vocabulary, Many Screens UI Composition Picture an order list screen. Besides the list itself, it needs six more things: a skeleton while it loads a placeholder when it is empty a page control at the bottom a modal for a new order a second modal for editing one a confirmation before anything is deleted That is six states around one array, and none of them is your product. akanjs/ui ships all six, already wired to the generated store. You write the row and the detail view; the shells around them handle loading, empty, paging, refresh and the CRUD modals. You write the row; the shell draws the rest On an order list screen you write only one row component. Load.Units repeats it, draws the page control under it and handles loading and empty states; the New button is a Model.New shell. This page is the inventory of those shells and the rules for combining them. Where the client boundary falls is the subject of UI Architecture. Words used on this page Term - shell: A ready-made akanjs/ui component that draws loading, empty, paging or modal states around yours. - slice: A module's named list query, such as icecreamOrderInPublic. A shell takes one as slice. - handle: What fetch.init, fetch.view and fetch.edit return: await it, or destructure one promise per field. - Suspense boundary: A spot that shows a fallback first and streams its content in when the data lands. What akanjs/ui gives you Export - Load.Units, Load.View, Load.Edit: Data shells: seed the store from a fetch handle and render loading, empty and list states. - Load.Stream: Awaits one promise behind its own Suspense boundary; a resolved value renders inline. - Model.New, Model.Edit, Model.SureToRemove: Create, edit and remove modals wired to the generated store actions. - Field: The control for every model field type. Never a bare input for a model field. - Tab, Layout, Link, Image, Empty: Composition primitives. Tab keeps panel bodies on the server; Link adds the locale prefix. - cn: The only class merge, from akanjs/client. Pass the caller's className last. Where your own components go What you write splits the same way, by whether it belongs to one model: Anything bound to one model. The module owns its own row, detail view, form and actions. Anything reusable across models and bound to none of them. ## App Config Source: /docs/core/config Mirror: /llms/pages/docs/core/config.md Priority: P0 Headings: - App Config - Config Shape - Application Env - Server Option - Routes and Domains - Web Surfaces And Prefixes - Native Apps - Images And Public Env - Secret Files - Build And Runtime - Pipeline - Workspace Config - Defaults And Rules App Config akan.config.ts is the app-level settings file. You do not need to understand every option on day one. Start with an empty file, then add only the fields your app actually needs. This is the whole key set. Every one of them has a default that a working app can live with, and the slides below cover the ones you are most likely to change: - routes (AkanRouteConfig[]): Public domains for the app, optionally split per client with basePath. - api ({ prefix, websocketPrefix }, default /api, /ws): Where signal endpoints and the websocket upgrade are mounted. Baked into every client bundle. - web (boolean | { csr: boolean }, default true): Which web surfaces the build produces and the app mounts at boot. - i18n ({ defaultLocale, locales }, default en, ["en", "ko"]): The locale segment every route sits under. defaultLocale must be one of locales. - native (AkanNativeAppConfig): The iOS, Android and desktop app: its identity, platform settings and targets. - images (AkanImageConfig, default webp, quality 75): Allow-list, sizes, and limits for the image optimizer. A remote host not listed is refused. - publicEnv (string[], default []): Extra process.env names the browser build may inline, beyond the built-in AKAN_PUBLIC_* pattern. - secrets (string[], default []): Globs for files that cannot live inside env.server.*.ts. Shipped by upload-env and git-ignored. - assets ({ pruneFonts, keepFonts }, default true, []): How akan build trims the public/ copy it ships. Source trees are never touched. - syncPageLibs (string[] | boolean, default false): Which library page folders this app mounts as its own routes. - plugins (AkanPlugin[], default []): Akan plugins this app contributes, read live by the CLI. - pipeline (AppPipelineConfig, default build → docker → deploy): The stages Akan Cloud runs to build and deploy this app, in order. - docker (string | DockerImageConfig, default oven/bun:1-slim): A whole Dockerfile as a string, or the parts akan build assembles one from. - database ({ modes: DatabaseMode[] }, default { modes: ["single"] }): The modes the build can run in; each deployment picks one with AKAN_DATABASE_MODE. - externalLibs (string[], default []): Packages kept as production runtime dependencies instead of being bundled. - trustedDependencies (string[], default []): Packages whose install scripts bun install --production runs, in the image and in a desktop app's server. - bin (Record, default {}): Executables every desktop build carries, per platform, first on its PATH; the image ignores it. - barrelImports (string[], default akanjs + workspace): Barrel paths Akan flattens while scanning and bundling. - optimizeImports (string[], default built-in list): Extra packages whose imports the client build rewrites to the exact source file. Start small Most defaults are already prepared, so an empty config is valid. Add only what changes Define only the parts your app actually needs to customize. One source of truth CLI commands, production builds, and native app commands all read this file. Config Shape The default export can be a plain object or a function. Use an object for most apps. Use a function only when the config needs app metadata while it is being loaded. ## Data Layer Source: /docs/core/data-layer Mirror: /llms/pages/docs/core/data-layer.md Priority: P0 Headings: - Data Layer - Model Shape - Document And Service - What A Filter Generates - Signal To UI - Fetch And Store Instances - Streaming Page Data - Common Decisions Data Layer The data layer is the path from business data definition to server logic and screen usage. If you are building products, orders, users, reservations, or invoices, this is where the business shape becomes real application behavior. Akan keeps this flow close to the model folder. For example, a product feature can define what a product is, how it is stored, how stock and price rules work, and how pages load product data from one module. One module, from the database to the screen One lib/product folder holds the whole path: document stores the data, service runs the business rules, signal opens them to pages, and past the API the store holds client state for the UI. The constant file runs underneath every step, because each of them reuses its shape. Model Shape The constant file is the design sheet of a business object. It answers questions such as: What fields does a product have? Which values are allowed? Which fields should be shown in a lightweight list? In the product example, the model keeps catalog information such as name, description, image URL, price, stock, and sale status. This is the shared source that the server and client can both understand. Fields that can be submitted when creating or updating data. The base object shape used to build other model views. A smaller view for lists, cards, and embedded references. The whole record, returned by a detail query. Write all five classes, in this order, in every constant file. Aggregate numbers a list query reports alongside the rows. Declare it even when it is empty. How the five classes build on each other Input is what a form sends. Object adds the stored fields the system controls. Light picks the few fields a list or card needs and carries the shared logic. Model combines Object and Light into the full record, and Insight counts over a list of them. Where each class shows up A create or edit form sends Input, a list of cards shows Light, a detail view shows the full Model, and the totals above a list read Insight. Document And Service The document file turns the model shape into stored data. It defines the database-facing model and the filter shape used when the application searches or sorts records. The service file is where business behavior lives. In this simple example, the document knows how to increase its own stock, and the service decides which product should be loaded and saved. Service decides, document changes itself The service loads a document from the database, the document validates and changes itself and returns itself, and the service saves it back. What A Filter Generates A query you declare in the document file is not one method. Akan generates fourteen from it, named after the filter key: declare byOwner and you have listByOwner, countByOwner, updateOneByOwner, and eleven more, on both the model and the service. One filter, fourteen methods One filter such as byOwner generates nine reads, one query descriptor for a slice, and four writes that run no hooks. Nine of the fourteen read, one only builds a query descriptor, and the remaining four write. Those four are the ones to be careful with: each is a single atomic statement against the database, so none of the model's document hooks run: Method - list: Read, no hooks. Hydrated documents, newest first; takes skip, limit, sort and select. — Example: `await listByOwner(ownerId, { limit: 20 })` - listIds: Read, no hooks. Just the ids; the same option, minus select. — Example: `await listIdsByOwner(ownerId)` ## File Rule Source: /docs/core/file-rule Mirror: /llms/pages/docs/core/file-rule.md Priority: P0 Headings: - File Rule - Module Files - Naming Rule - Facet Files And Barrels - Module Differences - Common Choices File Rule Folder names tell Akan what business area a file belongs to. File names tell Akan what role the file plays inside that business area. For example, product.document.ts describes stored product data, while Product.View.tsx describes how product data is shown on screen. Think of a module as a small business department. A product module may know what fields a product has, how to save it, how users request it, and how it is shown in the admin screen. Each file handles one of those jobs. Business meaning A file suffix explains what kind of work the file does for the model. Start small You do not need every file. Add files only when the business feature needs them. Module Files These files describe the data, server logic, API surface, and state around a business model. If you are building products, orders, users, invoices, or reservations, these are the files you will touch most often. The abstract file is not only for LLMs. It keeps domain knowledge beside the code, so people and agents can understand business invariants before changing implementation files. The five UI suffixes are not five sizes of component either. Each one answers a different question: how the user edits one record, how one record looks in a list, how one record looks on its own page, how a page section is assembled, and what extra action the model offers. The first column of each row is which side of the client boundary the file lives on: File - model.abstract.md: Business intent, domain rules, workflows and agent notes beside the module code. — shared - model.constant.ts: Constants, status values, default options, and shared model types. — shared - model.dictionary.ts: Labels, field names, and text keys the model uses, such as the price label. — shared - model.document.ts: Stored data shape, filters, and document model definition. — server - model.service.ts: Server-side business logic, such as creating an order or applying a coupon. — server - model.signal.ts: Public actions, slices, endpoints, and internal jobs that pages can call. — shared - model.store.ts: Client or model state used across screens, such as selected filters or a cart. — client - Model.Template.tsx: The create and edit form: reads st.use.productForm(), writes through generated setters. — client - Model.Unit.tsx: One item in a list or grid, such as a row or card; takes the trimmed LightProduct. — server - Model.Util.tsx: A domain UI helper named for the endpoint verb minus the model noun, like Refund. — client - Model.View.tsx: One record in full detail: the full model, with fields a list never loads. — server - Model.Zone.tsx: A composed page section: feeds the store to Load.Units or Load.View; Unit and View draw it. — client The client boundary follows the suffix, not your judgment. Template, Zone, and Util always carry "use client" on line 1; Unit and View never do, so they render on the server and ship no JavaScript. Naming Rule Akan file names use two patterns. Business core files use the model name in lower camel case. UI files use the model name in PascalCase. This makes a module easy to scan with your eyes. When you open lib/product/, every product.* file is business logic and every Product.* file is UI. You can immediately tell where to add a new query, screen component, or server action. Business files UI files ## Folder Rule Source: /docs/core/folder-rule Mirror: /llms/pages/docs/core/folder-rule.md Priority: P0 Headings: - Folder Rule - Workspace Rule - App/Library Folder Rule - Module Folder Rule - Growth Path Folder Rule Akan folders are designed around business ownership. When you add a new feature, first ask a simple question: is this a page customers visit, business data the app owns, shared UI, or server-only integration code? Find ownership If only one product uses it, put it in that app. If several products share it, move it to a library. Keep pages separate Screens such as /orders or /admin/users go under page/. Reusable components and logic go elsewhere. Model the business Business nouns such as user, order, product, and invoice usually become folders under lib/. Which folder does this file go in Who uses it? one product several products What does the file do? a URL a user visits data the business stores something the business does reusable markup browser API or React hook node, Bun, or a secret pure and isomorphic Workspace Rule At the workspace root, choose the folder by how widely the code is used. A single product goes to apps/. Shared product code goes to libs/. Framework code goes to pkgs/. A business product that can run by itself. Examples: customer web, admin portal, brand site, or mobile-backed service. Reusable product code shared by several apps. Examples: user account, billing, file upload, social features, security, admin features, etc. Code with special purpose, used or published as npm packages. Examples: payment gateway, robot control code, etc. Generated folders such as .akan/ and dist/ are build outputs, and you normally do not edit them by hand. Use pkgs/ only when the code should feel like a separate installable package. Ordinary one-app business logic belongs in apps/, and shared product logic usually belongs in libs/ first. App/Library Folder Rule An app is where a product becomes visible to users. A library is where reusable business capabilities live. They look similar because both can have domain modules, UI, assets, and server helpers. Each folder has an admission test rather than a theme, and the first column says which side of the client boundary its code runs on. A client folder ships to the browser, so nothing secret may reach one; a shared folder is read from both sides, so it must stay pure and environment-safe. A file that fails every test does not belong in the app or library root at all. ## Multi Client Source: /docs/core/multi-client Mirror: /llms/pages/docs/core/multi-client.md Priority: P0 Headings: - When To Split - Multi Client - Route Config - Page Structure - Local And Production - CSR And Mobile Builds Multi Client When To Split Your app has grown a second audience. The storefront and the admin console want different domains, different first screens, maybe different mobile packages — but the same products, the same orders, the same permissions. Creating a second app would duplicate all of that. Splitting the pages with basePath does not. The test is whether the surfaces are sold, deployed, or reached as separate products. If they are, split them; if one is a section of the other, a route group is enough: Situation - A customer storefront and an admin console — They share products, orders, users, and permissions, but need different domains, layouts, and release targets. - A consumer client, a partner portal, and an internal tool — One backend, three audiences. Each gets its own home screen and navigation without a second app. - Android and iOS packages released per brand, region, or user type — A native target points at a basePath, so each package opens its own client from the same backend. - White-label or regional sites on shared business rules — Different domains, names, and first screens over the same domain models — the case basePath exists for. - Account settings, dashboards, tabs, grouped screens — These are sections inside one client. A route group such as (user) organizes them without adding a URL segment. - A section that only some signed-in users may open — Authorization is a guard and a layout gate, not a deployment boundary. Splitting on it buys nothing and costs a domain. normal routing Akan can serve multiple web clients from one app by splitting pages with basePath. Every route sits under the locale, so locally a client is the segment right after it — /en/store — but in production the matching domain hides that segment and serves the client as a separate site. One app, many clients Akan App single server and backend store web admin web partner web demo web Multi web Each basePath can behave like its own website. Single backend All clients still share the same app server, domain modules, and services. Separate builds CSR web and mobile apps can be prepared per basePath. Route Config Define clients in akan.config.ts with routes. The basePath names the client, and domains decide which production host should open that client. - basePath (string): The client this route opens and its first page folder: basePath store lives in page/store. - domains (Record, default {}): Hosts per branch that open this basePath; a matching host hides the basePath segment. ## File Based Routing Source: /docs/core/routing Mirror: /llms/pages/docs/core/routing.md Priority: P0 Headings: - File Based Routing - File Convention - Page File Shape - Chain Stages - Layout File Shape - Root Layout Stages - Google Analytics - Search Engines - Base Paths - Library Pages - Dev Only Routes File Based Routing Akan uses file-based routing. You create files under page/, and the folder structure becomes the page URL. Every route also sits under a locale segment that Akan injects for you, so the same file serves every language you ship. From folder to URL (user) adds no segment Akan injects the locale File-based Folders and files decide the URL shape. Locale-aware Akan injects the locale segment automatically and hands it to every route as lang. Explicit files Use page and layout files instead of hidden magic. File Convention A route file is a page, a layout, or an overrides manifest. Everything under page/ must be a .tsx route module — no helper file, no logic file, no filename starting with an uppercase letter. File - folder/_index.tsx: The page for the folder it sits in: project/_index.tsx serves /:lang/project. - folder/_layout.tsx: Wraps every page below its folder. The root one is a rootLayout() chain. - folder/_overrides.tsx: A logic-free manifest of UI overrides for the subtree: one export default override({ … }). - path.tsx: A segment as one file: project.tsx serves /:lang/project. Never an uppercase first letter. - [param].tsx: A dynamic segment as one file: [projectId].tsx serves /:lang/:projectId. - (group)/: Organizes files without adding a URL segment, such as (user) or (public). - [lang]/: Never written: Akan injects the locale. _index.tsx, _layout.tsx and _overrides.tsx are the only reserved names an underscore may introduce. Page File Shape A page file exports a single page() chain and nothing else. Each route setting is one stage of the chain: .param() and .search() declare the values the page reads, .config() tunes the route, .head() and .loading() set the head tags and the loading fallback, and .render() returns the component. The render callback receives the declared values flat, already typed. Heads merge from the root down: a deeper .head() replaces the , a meta with the same name or property, and a canonical, manifest or icon link, and keeps everything else. A canonical link and og:url each name one URL, so a page carries them only from its own .head(), never from a layout's. Give <title> one string child, a template literal when it includes a value, and skip the hreflang alternates since Akan adds one per locale. A page() chain must be the module's only export, and the names in .param() and .prompt() are string literals. Chain Stages There are fifteen stages, and the three chains share most of them. page() adds .prompt(); layout() adds .notFound() and .error(); rootLayout() is a layout that also carries the app-wide stages. The three columns mark which builder each stage is legal on. Stage - Every chain - .param: Declares one [x] path segment, typed; a value the type refuses answers not-found. — (name, Type) ## Akan Runtime Source: /docs/core/runtime Mirror: /llms/pages/docs/core/runtime.md Priority: P0 Headings: - Akan Runtime - Identity And Environment - Database Variables - Text Search Variables - Logging Variables - getEnv() - OpenAPI JSON - Selective Module Boot - Health, Metrics, Logs Akan Runtime Akan applications run on a Bun-based runtime that connects app code, generated artifacts, server routes, and pages. The app entry point (main.ts) starts the runtime, and Akan handles the server shape behind it. When Akan App starts, Akan Server prepares everything the app can serve. In practice, the runtime exposes four kinds of work. Internal API (Queue, Timer, etc.): internal work that runs without a browser request. API (HTTP, WebSocket): public communication for data requests and realtime updates. SSR Pages (Web): web pages rendered by the server and sent to the browser. CSR Page (Android, iOS): client-rendered pages used by native targets. Runtime overview App code runs in the Akan App, which runs the Akan Server, and the server exposes an internal API for queues and timers, an HTTP and WebSocket API, SSR pages for the web and CSR pages for Android and iOS. AKAN_REPLICA decides how many server processes each role gets, and it defaults to 0,0,1 everywhere: one all server and nothing else. With a single traffic replica there is nothing to balance, so Akan App runs that server inside its own process instead of spawning it and proxying to it. The container holds one process, and every request skips a proxy hop. all: runs both federation and batch behavior in one server process. This is the default, and the shape almost every deployment ships. federation: serves browser traffic such as pages, API calls, and WebSocket connections. batch: runs background work such as queues, timers, and scheduled jobs. Default: one process, no gateway The browser reaches one process in the container where Akan App and Akan Server run together, serving pages, API and WebSocket and running queues, timers and jobs; a separate RSC worker process exists only for web. Five things bring the gateway back: two or more replicas, a batch-only replica that never listens, AKAN_SOLO=false, passing replica to new AkanApp(...), and akan start. Then Akan App spawns the servers and load-balances browser traffic across the ready federation and all processes. Replica and server modes The browser reaches the Akan App acting as gateway and load balancer inside the container; it spreads traffic over three federation servers for pages, API and WebSocket, and runs a batch server for queues, timers and jobs. A single Akan App has built-in clustering. You can run multiple server replicas and let Akan App distribute traffic, without setting up separate local load-balancing tools such as nginx, docker compose, or pm2. Identity And Environment The root .env file decides which organization, domain, environment, operation mode, and log level the app uses while it runs. Most projects keep these values stable, but changing them lets the same app behave like a local, debug, develop, or production-like service. Environment variables prefixed with AKAN_PUBLIC_ are public. They can be read by browser code, so never store secrets, private tokens, or credentials in them. Four of those names answer who this app is and where it runs, and the first two are required: - AKAN_PUBLIC_REPO_NAME (string): Organization or repository namespace, usually fixed for the life of the project. - required - AKAN_PUBLIC_SERVE_DOMAIN (string): The domain the app builds links, callbacks, and domain-based routes from. - AKAN_PUBLIC_ENV (local | debug | develop | main | testing, default debug): Which data set the app runs against, from local test data up to production-like main. - AKAN_PUBLIC_OPERATION_MODE (local | edge | cloud | module, default local when ENV=local, else cloud): Where clients connect: local runtime, cloud, or edge paths; module is only in the type. In practice you move two of them together. Build a feature with ENV=local and OPERATION_MODE=local, switch ENV to debug or develop when you need shared data or shared services, and deploy with ENV=main against whichever operation mode the cluster serves: Two more narrow who reaches the server, for one only its own computer calls, such as the server a desktop app carries: ## Fundamentals Source: /docs/intro/fundamentals Mirror: /llms/pages/docs/intro/fundamentals.md Priority: P0 Headings: - Write once, deploy everywhere - Make Developer a Businessman - Collab cohesively - Who should use? Fundamentals Write once, deploy everywhere Why do we need to create multiple separate projects to implement a single business? Isn't it confusing and inefficient to describe the same business intent separately for backend, frontend, app, database, and deployment? Can't one definition flow through every surface? Akan.js is a full-stack TypeScript framework where business definitions become the source of truth for web, app-oriented client surfaces, server runtime, data contracts, and deployment artifacts. Write business definitions once: pages, domain modules, signals, services, stores, and UI. Akan Runtime Pages File-routed web and app-oriented client surfaces. Server Services, signals, API traffic, realtime traffic, and background work. Data One convention-driven workspace produces runtime surfaces, data contracts, generated artifacts, and deployable packages. With one type-safe business definition, Akan conventions carry your intent across pages, API contracts, services, stores, schemas, and runtime surfaces. With this, you spend less time wrestling with platform glue and more time designing the product your customers experience. The same clarity also gives agents a predictable structure to extend. Akan.js smooths over the following background technologies so your application can grow as one extensible system. Web/App Tooling Deployment Make Developer a Businessman Akan.js helps you minimize technical plumbing and focus on expressing business logic. Akan.js also provides built-in application features and installable libraries so proven business patterns can be reused instead of rewritten. This is especially important in the age of agentic coding. Agents write better code when business intent has one obvious place and conventions decide where the rest should go. Workspace (monorepo) Akan.js is monorepo-native. A single organization can develop multiple apps and shared libraries in one repository, and app execution, production builds, library development, and package management all happen from the workspace root. Akan Workspace appA imports libA appB imports libA and libB appC imports libB code amount ## Practice Source: /docs/intro/practice Mirror: /llms/pages/docs/intro/practice.md Priority: P0 Headings: - Icecream business - Create icecream order module - Define Constant - Fill dictionary - Allow orders in signal - Make template file - Update unit and view files - Expose to page Practice Icecream business You are now the owner of a Korean-style yogurt ice cream shop, "Ko-yo". The shop is located in San Francisco and you need to open the shop and start your business. The shop is 20 square meters in size. The concept of Korean-style yogurt ice cream is that customers can freely add their desired toppings to the yogurt base ice cream. You need to implement a order form to allow customers to select and add toppings freely. First, let's create an akan app with the project code "koyo". The koyo project is a service that operates all services under your company as the brand "Ko-yo". Now, let's type the following command in the terminal. Now run koyo locally with the following command. koyo comes before myapp alphabetically, so koyo is http://localhost:8282 and myapp moves to 8283. AKAN_DEV_PORT pins the port. Create icecream order module Now, customers want to order the ice cream. The order is simple. You need to select the size of the yogurt base ice cream and check the desired toppings. In Akan.js, we organize features into "modules" - think of them as complete packages that handle everything related to one thing. An ice cream order module will contain all the code needed to create, display, and manage ice cream orders. When you create a module, Akan.js automatically generates all the files you need following a consistent pattern. This makes your code organized and easy to understand. Fruit Ring Oreo Strawberry Mango Cheese Cube Corn Granola Banana Fig Now, let's create a domain for the ice cream order. The domain name is icecreamOrder, and it stores information about each ice cream order. This command will ask you which application to add the module to - select "koyo" since that's our ice cream shop app. The module name "icecreamOrder" describes what this module handles. After running this command, Akan.js creates a complete folder structure with all the files you need. Let's look at what gets created: Application code Individual application Domain modules Icecream order domain module Business intent Types and schemas Translations Document ## Quick Start Source: /docs/intro/quickstart Mirror: /llms/pages/docs/intro/quickstart.md Priority: P0 Headings: - Quick Start - Requirements - Create a Workspace - Run the App - Build Quick Start Akan.js is a full-stack TypeScript framework that prioritizes designing and implementing actual business code. You can build a type-safe service with minimal code and deploy it to web, mobile, server, and DB infrastructure at the same time. This guide takes you from an empty directory to a running app. Requirements Bun is the only required dependency for the first run. Bun 1.4.0 or higher Git for source code management Android Studio or Xcode for native app builds Create a Workspace The quickest way is to let your coding agent do it. Open Claude Code or Codex in an empty directory and paste this prompt. It checks Bun, creates the workspace and starts the app: To create it yourself, run the workspace creator. It asks for a workspace name and an app name: Or use the globally installed akan command: Run the App Start the app with one command: The app opens on http://localhost:8282. The dev port is 8282 plus the app's index in alphabetical order, so the only app is 8282. Edit a page Akan pages live under apps/<app>/page. Edit the first screen and refresh: Know the app entry The generated main.ts starts the Akan runtime. The terminal shows the local runtime status. Build Build the app for production: The result is generated in the dist/apps/myapp directory. ## akanjs/base Source: /references/akanjs/base Mirror: /llms/pages/references/akanjs/base.md Priority: P0 Headings: - akanjs/base - ID - Int - Float - Any - Binary - ImageResult - Upload - dayjs / Dayjs - enumOf - getEnv - getApiPrefix / getWsPrefix - DataList akanjs/base `akanjs/base` holds the value types models and signals are built from, plus a few runtime helpers. It imports nothing else from Akan, so server files, client files and `common/` can all use it. Export - ID: A document id: a 24-character hex string. - Int, Float: Whole numbers and decimals. JavaScript `Number` is not a field type. - Any: An open value Akan does not check. You name its shape with a type argument. - Binary: Raw bytes in a signal argument or return. - ImageResult: A picture a signal returns: JSON over HTTP, an image block over MCP. - Upload: A file in the body of the upload mutation. - dayjs, Dayjs: The date library and its type. Every `Date` field holds a `Dayjs`. - enumOf: Turns a fixed list of values into an enum class. - getEnv: The running app's name, environment and server addresses. - getApiPrefix, getWsPrefix: The paths that signals and the websocket are served under. - DataList: A list keyed by id. Every model list in a store is one. Where Each Type Goes Type Model field — field() Signal argument — .body() .param() Signal return — query() mutation() - Import from `akanjs/base` - ID: Document ids. - Int · Float: Counts and decimals. - Any: Payloads whose shape stays open. - Binary: Keep stored bytes in a `File` model. - ImageResult: A picture for an agent to see. - Upload: Only in the body of a `fileUpload: true` mutation. - JavaScript globals, no import - String: Plain text. - Boolean: Text such as "true", "false", "1" and "0" is read as a boolean. - Date: The value is a `Dayjs`, not a JavaScript `Date`. ## akanjs/client Source: /references/akanjs/client Mirror: /llms/pages/references/akanjs/client.md Priority: P0 Headings: - akanjs/client - router - cn - ModelProps / ModelsProps - page / layout / rootLayout - layout / rootLayout Stages - PageConfig - prompt - resolveRouteModule / isRouteDefinition - Font / createFont - usePage / msg / Err - fetch / sig - getCookie / setCookie / getAccount / getAuthToken - setAuth / initAuth / resetAuth - Device akanjs/client `akanjs/client` is what route files and client code import from the framework: the route chain, navigation, class merging, auth helpers, device access and font declarations. Export - page, layout, rootLayout: The route chain: the one default export of every route file. - PageConfig: What `.config()` takes: transition, safe area, cache and SSR mode. - router: Moves between routes and adds the locale and basePath for you. - cn: Joins class names and resolves Tailwind conflicts. - ModelProps, ModelsProps: Prop types for components that draw one record or a list. - usePage, msg, Err, fetch, sig: Runtime proxies without your app's types. Import the typed ones from `@apps/<app>/client`. - getCookie, getAccount, getAuthToken: Read cookies, the auth token and the signed-in account. - setAuth, initAuth, resetAuth: Save or clear the auth token in fetch, the cookie and storage at once. - resolveServerUrl: Puts a stored `/api/…` URL on the server's origin when a CSR page is served elsewhere, such as in a desktop app. - Device: Platform, safe area, keyboard, haptics and scroll of the device. - Font: The type of one font entry in `rootLayout().fonts([...])`. - isMcpView: True when the page runs as an MCP App view inside an agent host's chat, where it posts nothing to its parent frame. - breakpointQuery, TailwindBreakpoint: The media query Tailwind's `md:` (or, with `{ below: true }`, `max-md:`) matches, for `matchMedia` in a component. - transitionTypes, TransitionType: The page transitions `.config({ transition })` takes. - resolveRouteModule, isRouteDefinition: Used by route loaders. App code never calls them. **Most of it runs on the server too.** `page()`, `cn`, `getCookie` and `getAccount` work in server components; `router.back()`, `setCookie` and `Device` need the browser. **Typed helpers come from your app.** `usePage`, `fetch`, `msg`, `Err` and `sig` here do not know your app's types. Import them from `@apps/<app>/client` to get your own dictionary keys and endpoints. router `router` moves between routes from stores, event handlers and utilities. Give it the app path: it adds the locale and basePath itself. Method - push(href, { scrollToTop, shallow }): Goes to a route and adds a history entry. Browser only; on the server, use `redirect()`. - replace(href, { shallow }): Goes to a route in place of the current history entry. Browser only; on the server, use `redirect()`. - back(): Goes back one entry. Browser only. - postPathChange(change): Tells the frame that embeds this page where it went: a new path, or `{ page }` of a paginated list. Posts nothing in an MCP App view. - backOrFallback(href?): Goes back, or replaces with `href` when there is no history. Defaults to the index path. - refresh(): Renders the current route again. Browser only. - redirect(href, { method, status }): On the server, answers with a redirect (307 by default). In the browser, navigates. ## akanjs/common Source: /references/akanjs/common Mirror: /llms/pages/references/akanjs/common.md Priority: P0 Headings: - akanjs/common - Logger - sleep - capitalize / lowerlize - formatPhone / isPhoneNumber - isEmail - RestClient - pathGet / pathSet - randomPick / randomPicks akanjs/common `akanjs/common` holds small helpers that depend on no platform. The same import works in a page, a store, a service and a CLI script. On this page Export - Logger: Writes leveled log lines and hands them to the sinks you register. - sleep: Waits the given number of milliseconds. - capitalize, lowerlize: Changes the case of the first character only. - formatPhone, isPhoneNumber: Adds dashes to a Korean phone number and checks the dashed form. - isEmail: Checks that a string looks like an email address. - RestClient: Calls a REST API that is not an Akan server. - pathGet, pathSet: Reads and writes a nested value by a path such as `items[0].name`. - randomPick, randomPicks: Picks one or several random items from a list. More in akanjs/common - clamp: Keeps a number between `min` and `max`. — Example: `clamp(120, 0, 100); // 100` - formatNumber: Adds thousands separators to a number string and keeps the decimals as written. — Example: `formatNumber("1234567.89"); // "1,234,567.89"` - isValidDate: Tells whether a `YYYY-MM-DD` string, `Date` or `Dayjs` parses, though `2024-02-30` still passes. - isDayjs: Tells whether a value is a `Dayjs`. - splitVersion, mergeVersion: Splits "1.2.3" into major, minor and patch, and joins them back. — Example: `splitVersion("1.2.3"); // { major: "1", minor: "2", patch: "3" }` - objectify, plainFieldsOf: Copy data fields without methods, and only `plainFieldsOf` keeps a model's `Date` fields. - deepObjectify: Makes a deep plain copy, JSON-ready when you pass `serializable` or `convertDate`. - decodeJwtPayload: Reads a JWT's payload without checking its signature, so never trust it for access. - bearerTokenOf: The token of an `Authorization` value: `Bearer` in any case, then one token and nothing after it. Else `null`. — Example: `bearerTokenOf("bearer abc"); // "abc"` - parseSearchParams: A query string as a record: a key given once is a string, a key given again an array of every value, empty ones included. — Example: `parseSearchParams("?tag=&tag=b&q=x"); // { tag: ["", "b"], q: "x" }` - isThenable: Tells whether a value can be awaited. - interpolateTranslation: Fills `{name}` placeholders and leaves one whose value is missing as written. — Example: `interpolateTranslation("Hi {name}", { name: "Akan" }); // "Hi Akan"` The same import also carries route-convention helpers and wire contracts that the framework uses itself. App code rarely needs them. Logger Akan's leveled logger. A service already has one as `this.logger`, named after its class, and an `adapt()` adapter has one named after its key. Anywhere else, create `new Logger("Name")` or call the static methods. A script that logs through an instance, a static call, a structured record and a sink: **Six levels, lowest first:** `trace`, `verbose`, `debug`, `info`, `warn`, `error`. A line prints at or above the console level, and `error` lines go to stderr. ## akanjs/constant Source: /references/akanjs/constant Mirror: /llms/pages/references/akanjs/constant.md Priority: P0 Headings: - akanjs/constant - via - field - field.visual / field.hidden / field.secret - resolve - getDefault - DocumentModel / DefaultOf / QueryOf - crystalize / purify - serialize / deserialize - ConstantRegistry akanjs/constant `akanjs/constant` is Akan's schema layer. Every `.constant.ts` file is built from two of its exports: `via`, which declares a class, and `field`, the builder `via` hands you. Everything else supports those two. From `getDefault` on, the entries are helpers you mostly read rather than call. Export - via: Declares every constant class. What you pass decides which class it is. - field: The builder `via` hands you. Each call declares one stored field. - field.visual, field.hidden, field.secret: Variants of `field` that keep a value away from agents, the client, or default reads. - resolve: Declares a field the server computes for each response instead of storing it. - getDefault: Builds the blank object a new record or form starts from. - DocumentModel, DefaultOf, QueryOf, PurifiedModel, ProtoFile, ProtoLightFile: Types for the stored shape, the default shape, a query, a purified value, and a file. - crystalize, makePurify: Turn raw data into model values, and a model back into a checked plain object. - serialize, deserialize: Convert values to and from the payload that crosses a boundary. - ConstantRegistry: Finds model classes, refNames and enums at runtime. Words Used on This Page Term - refName: The camelCase name a module is registered under, such as `banner`. - scalar: A value object with no table of its own. Other documents embed it whole. - relation: A field whose type is another database model. It stores that document's id. - projection: A read option that names the fields to load, such as `{ password: true }`. The Five Classes of a Module A database module declares these five classes, always in this order. The banner module is the example throughout this page: Class - BannerInput: The fields a caller sends to create or update a banner. - BannerObject: The Input plus fields the server keeps, and `id`, `createdAt`, `updatedAt`, `removedAt`. - LightBanner: Only the fields a list needs. Display and predicate methods live here. - Banner: The full model: every field, plus the ones `resolve` computes. - BannerInsight: Numbers about a whole list. It starts with `count` and is written even when empty. **The order is fixed.** `enumOf` classes go on top, then Input, Object, Light, full and Insight. Write the Insight class even when it is empty. **Shared logic goes on Light.** The server and the client both hold the Light class, so `isNew()` or `canWrite(user)` belongs there, not in a util module. **A scalar is a single class.** `via((field) => ({ … }))` alone declares it. It lives under `lib/__scalar/<name>/`. ## akanjs/fetch Source: /references/akanjs/fetch Mirror: /llms/pages/references/akanjs/fetch.md Priority: P0 Headings: - akanjs/fetch - InitHandle / ViewHandle / EditHandle - ClientInit - ClientView / ClientEdit - SliceMeta - FetchInitForm - Account - FetchClient - getRequest / headers / cookies akanjs/fetch `akanjs/fetch` holds the types that carry fetched data from a route to its components, and the client that sends those calls. Zone files import its types with `import type`. Words Used On This Page Term - handle: What `fetch.init*`, `fetch.view*` and `fetch.edit*` return. Await it, or read one field off it. - payload: Plain data a Zone receives, such as `userInitInOrg`. It can cross from server to client. - hydrated instance: A model class instance such as `cnst.User` or a `DataList`. It stays in server components. - slice: A named list query of one model. The `inOrg` slice of `user` gives `fetch.initUserInOrg`. - Zone: A module's client component. It fills the store from a payload and renders it. Exports - InitHandle, ViewHandle, EditHandle: What `fetch.init*`, `fetch.view*` and `fetch.edit*` return: awaitable, or split per field. - ClientInit: Type of a Zone's `init` prop: a list payload or its promise. - ClientView, ClientEdit: Types of a Zone's `view` and `edit` props for one record. - ServerInit, ServerView, ServerEdit: The same three payloads, already resolved instead of a promise. - SliceMeta: Names the slice a component works on: `refName`, `sliceName` and `argLength`. - FetchInitForm: Options for loading a list: page, limit, sort, insight, default values and invalidate. - QuerySetting: `{ queryKey, args }`: the filter a root-slice list component runs. - Account: The account data a sign-in token carries. - FetchClient: The runtime client behind every app's `fetch`. - getRequest, headers, cookies: Read the request a page is being rendered for. Server only. - Everything else: `HttpClient`, `WsClient`, `AgentTurn`, request helpers like `getRequestTheme`, and client types. InitHandle / ViewHandle / EditHandle A route's `fetch.init*`, `fetch.view*` and `fetch.edit*` calls return a handle. Await it and you get the same object these helpers always gave; read a field off it and you get that field's own promise. So each section renders as soon as its own data lands, and the page never waits for the slowest query. Three Handles Handle Returned by Fields - `InitHandle` — fetch.init<Model><Suffix>(...args, option?) — <model>Init<Suffix> · <model>List<Suffix> · <model>Insight<Suffix> - `ViewHandle` — fetch.view<Model>(id, option?) — <model> · <model>View ## akanjs/server Source: /references/akanjs/server Mirror: /llms/pages/references/akanjs/server.md Priority: P0 Headings: - akanjs/server - AkanApp - AkanAppOptions - AkanServer Web Surfaces - AkanOption - AkanResponse - WebProxy - Try - Transaction akanjs/server AkanServer Web Surfaces `akanjs/server` is the server half of Akan: it starts the app, holds the server settings, and sees page loads before the router. Import it only from server files — `main.ts`, `lib/option.ts` and `srvkit/`. Words Used On This Page Term - gateway: The front process: it starts the replicas and relays HTTP and WebSocket traffic to them. - replica: One server process that runs your modules. It takes traffic, runs batch work, or both. - solo: A single replica running inside the `main.ts` process itself, with no gateway in front. - RSC worker: A separate process that renders pages on the server. Each replica serving pages has one. - web proxy: A class that sees each page load before the router and can redirect, rewrite or answer it. Exports - AkanApp: Starts the app from `main.ts`: one process, or a gateway with replicas. - AkanAppOptions: What `new AkanApp()` takes: replicas, port, route prefixes and which modules boot. - AkanServer: One replica's server, generated into `server.ts`. It decides which web surfaces are served. - AkanLib: Bundles one app's or lib's modules and option. Also generated into `server.ts`. - AkanOption: The builder `lib/option.ts` exports: injected values, middleware, proxies, MCP and LLM settings. - AkanResponse: Helpers a web proxy returns to continue, rewrite or redirect a request. - WebProxy: The interface a web proxy class implements: one `use(request)` method. - LocaleWebProxy, HostBasePathWebProxy: The two built-in proxies. Every app runs them before its own. - Try: Legacy decorator: logs a warning and returns `undefined` instead of throwing. - Transaction: Legacy decorator: runs a method in a database transaction. - Everything else: Build-artifact types and console, OAuth, sitemap and metrics helpers the framework and CLI use. Where It Is Imported File - main.ts: Use the leaf path, which keeps the SSR renderer out of the gateway. — Example: `import { AkanApp } from "akanjs/server/akanApp";` - server.ts: Generated; never edit it by hand. — Example: `import { AkanLib, AkanServer } from "akanjs/server";` - lib/option.ts: One per app and one per lib. — Example: `import { AkanOption } from "akanjs/server";` - srvkit/*.ts: Server-only helpers: proxy classes and legacy decorated classes. — Example: `import { AkanResponse, Try, type WebProxy } from "akanjs/server";` AkanApp `AkanApp` is what `main.ts` starts. It decides how many server processes run, and keeps them running until the container stops. ## akanjs/signal Source: /references/akanjs/signal Mirror: /llms/pages/references/akanjs/signal.md Priority: P0 Headings: - akanjs/signal - Public / None / guard - McpProgress - Req / Res / Ip / Ws - middleware / Middleware - SignalRegistry akanjs/signal Export `akanjs/signal` declares the API boundary around a service: what may be called, by whom, over which transport. You import it in `*.signal.ts` files and in the `srvkit/` files that hold guards and middleware. What It Exports - endpoint: Declares the calls a module exposes: queries, mutations and WebSocket endpoints. - internal: Declares work the server starts itself: schedules, lifecycle hooks, queue jobs, resolved fields. - slice: Declares the list queries a client store loads, and guards the generated CRUD endpoints. - Public, None, guard: Guards. They run before the handler and decide whether the call may go on. - Req, Res, Ip, Ws: Internal arguments: handler arguments the server fills in, such as the request. - middleware, Logging, Timeout: Middleware wraps every endpoint call. The two built-ins are registered by default. - McpProgress: Reports progress from inside a long MCP tool call. - SignalRegistry, serverSignal: Look up registered signals, and publish or enqueue from a service. - SignalContext: The per-call context guards and middleware receive: transport, arguments and caller. Four Endpoint Kinds The `endpoint` builder hands you four kinds, and each kind fixes its transport: Kind HTTP WebSocket - Request and response - query: Reads, over `GET`. The only kind that may declare `cache`. - mutation: Writes, over `POST`. The `method` option moves it to `PATCH`, `PUT` or `DELETE`. - Realtime - pubsub: The client subscribes to a room, and the server publishes into it. - message: The client sends one message and gets one answer back. travels over it does not An MCP prompt is not an endpoint kind. It is declared on a page with `page().prompt(name, description)`. - The Signal File — How `Internal`, `Slice` and `Endpoint` are laid out in one `*.signal.ts`. - MCP Prompts — Declared on a page with `page().prompt(name, description)`. - The Guards That Ship — `Every`, `Admin`, `Person` and the other guards `libs/shared` provides. ## akanjs/webkit Source: /references/akanjs/webkit Mirror: /llms/pages/references/akanjs/webkit.md Priority: P0 Headings: - akanjs/webkit - lazy - useDebounce - useInterval - useThrottle - useFetch / useFetchFn - useCamera - useGeoLocation - usePushNotification - usePurchase - useLocation / useHistory - LoginForm akanjs/webkit required Export Returns `akanjs/webkit` holds React hooks and helpers that run only in the browser or in the native app. Timers, lazy loading, promise state, device features and the CSR router state live here. On This Page - lazy: Loads a component's code on demand. `ssr: false` skips server rendering. - useDebounce: Runs a callback once, after the calls stop for a while. - useInterval: Runs a callback on a fixed interval and stops on unmount. - useThrottle: Runs a callback at once, then ignores calls for a while. - useFetch, useFetchFn: Tells a client component whether a promise has resolved, and its value. - useCamera, useGeoLocation: Camera and location through the native runtime's plugins, with a browser fallback and the permission prompts. - usePushNotification: Not in this module: the push hook lives in `@libs/util/webkit`. - usePurchase: In-app purchase on the native iap plugin, verified by your server. Imported from `akanjs/webkit/usePurchase`. - useLocation, useHistory: The CSR router's location parser and history stack. - LoginForm: The argument of the shared store's `login` action. Other Exports - useBodyScrollLock(active): Locks `document.body` scrolling while `active`. Overlays share one count. - useEscapeKey(active, onEscape): Calls `onEscape` on Escape while `active`. Only the topmost open surface gets the key. - usePageFocusEffect(effect, deps): Runs `effect` while the user is on this page and cleans it up when they leave. A page kept under the current one for a swipe back stays mounted, so a plain effect there keeps running. - usePageLocation(): `{ pathname, params, searchParams }` of this page. `st.use.searchParams()` follows the page on screen, so a page being prepared or kept under the current one reads its own here. - usePageActivity(): `"current" | "prev" | "pending" | "hidden"` — where this page stands in the CSR stack; always `current` outside one. - useVisualViewportFrame(): `{ keyboardHeight, height, offsetTop }` of the part of the page left visible while the keyboard is up. - usePageTool, useScreenScope: Show a pager and on-screen items to the in-page agent. `Load.Units` and `Load.View` call them. - createRobotPage, createSitemapPage: Build robots rules (`disallow: "/admin/"` by default) and a list of sitemap entries. - bootCsr, replacePages, useCsrValues: Start the CSR (mobile) bundle, swap its route modules in place during dev, and hold its router state. The generated entry calls them. - LoginAuth, ScreenScopeItem: Types: `"user" | "admin" | "public"`, and one on-screen item `{ id, label? }`. **Call the hooks from a client file.** They are React hooks, so they need a file with `"use client"`. Put `lazy()` in the `ui/<Folder>/index_.tsx` boundary file. **Push and speech come from the util library.** `usePushNotification` and `useSpeech` are imported from `@libs/util/webkit`, not from here. Writing Your Own Hook ## Agent Source: /references/cli/agent Mirror: /llms/pages/references/cli/agent.md Priority: P0 Headings: - Agent CLI Agent Agent CLI `akan agent install` writes the rule files a coding agent reads before it touches your code: one `AGENTS.md` for every agent, plus pointers for Claude Code and Cursor. A convention is written once, and every agent reads the same copy. Words Used on This Page Term - agent guide: The workspace's `AGENTS.md`, the one file holding the conventions every coding agent follows. - pointer: A short file that only tells one tool to read `AGENTS.md`, such as `CLAUDE.md`. - managed block: The part of `AGENTS.md` between the `akan:agent` markers. The command rewrites only this part. - scoped guide: `apps/<app>/AGENTS.md` or `libs/<lib>/AGENTS.md`: the UI recipes that scope can import. What Each Target Writes Name a target, or leave it out to write all three. The guide is refreshed in place; a pointer is written whole. Target App/lib guides - Guide · only the block is rewritten, so `--force` is never needed - agents-md: Rebuilds the managed block, then writes every app and library guide. - Pointers · written whole, so an existing file needs `--force` - claude: Claude Code imports the guide through `@AGENTS.md`. - cursor: An always-on Cursor rule that points at the guide. - Default - all: All three, in the order `cursor`, `agents-md`, `claude`. Writes Does not **`--force` replaces `CLAUDE.md` and the Cursor rule whole.** Anything you added there is lost, so keep your own instructions in `AGENTS.md`, outside the `akan:agent` markers. When to Run It **A new workspace already has them.** `create-workspace` runs `akan agent install all --force` unless you pass `--agent-install false`. **After upgrading Akan.** `bun update` leaves the guide as it was, so run `akan agent install agents-md`. A bare `akan agent install` stops at the existing Cursor rule and writes nothing. **When `akan doctor` warns.** `agent-guide-stale` means a release other than the installed one wrote the guide, and `agent-guide-unstamped` means it has no version stamp. `akan agent install agents-md` fixes both. **To add one pointer.** Pass `claude` or `cursor` as the target. Codex and other agents that read `AGENTS.md` by themselves need none. What the Guide Holds The managed block is rebuilt from the installed Akan release and your workspace. Top to bottom, it holds: ## Application Source: /references/cli/application Mirror: /llms/pages/references/cli/application.md Priority: P0 Headings: - Application CLI - Rules Every Command Shares - Short Names Application Backend environment the app connects to. Application CLI These commands carry an app from creation to release: create it, run it locally, check and build it, then ship it as a native app. - Manage Apps - create-application: Create a new app under `apps/` from the template. - remove-application: Delete an app's folder from the workspace. - sync: Regenerate the generated files of an app or library. - plan-slice: List the files an app needs to move into a workspace of its own. - Local Development - start: Run the dev server for one or more apps. - dbup: Start the local database containers. - dbdown: Stop the local database containers. - db-export, db-import: Copy an app's data out of one database mode and into another. - script: Run a file from the app's `script/` folder. - console: Open an interactive server console. - logs: Follow a running app's logs, filtered. - Check and Build - typecheck: Typecheck an app or a library, its tests included. - test: Run the tests of an app, library or package. - build: Build the app for production into `dist/apps/<app>`. - Native - start-ios, start-android: Run the app on a simulator, an emulator or a connected device. - start-desktop: Run the app as a desktop app on this computer. - build-ios, build-android, build-desktop: Build the native app on the native runtime. - release-ios, release-android: Build the app for an App Store or Play Store release. - update-keygen, publish-update, pack-update, push-update, register-binary: Sign and publish releases installed apps update themselves to, or pack a phone update for a signer elsewhere. Command `akan create-application <appName> [--start <boolean>]` Create `apps/<appName>` from the app template, then sync it. With `--start` it also boots the dev server. ## Cloud CLI Source: /references/cli/cloud Mirror: /llms/pages/references/cli/cloud.md Priority: P0 Headings: - Cloud CLI Cloud CLI Eight optional commands for signing in to Akan Cloud, updating the framework, moving env values and managing pipeline secrets. Internal deployment commands are left out of this page on purpose. Words Used on This Page Term - Akan Cloud: The service at `https://cloud.akanjs.com` that holds your account, env values and tunnels. - env values: Each app's and library's `env/env.client.<env>.ts` and `env/env.server.<env>.ts`, kept out of git. - AKAN_WORKSPACE_ID: The cloud workspace id in the root `.env`, which decides where env values are kept. - SCP server: A server of your own, reached over SSH, that keeps env values when there is no cloud workspace. - pipeline secret: A named value build steps read as an environment variable; it is written, never read back. Where Each Command Connects Command This machine only - Account - login: Signs in through the browser and saves the session. - logout: Deletes the saved session without contacting the cloud. - Framework - update: Installs from npm, or from a local registry with `--registry local`. - Env values - download-env: Pulls env values from Akan Cloud or an SCP server, whichever the workspace uses. - upload-env: Pushes the local env values to that same place for the next `download-env`. - Pipeline secrets - upload-secret: Saves a named secret that pipeline steps can read. - list-secrets: Lists the secrets' names and scopes, never their values. - remove-secret: Removes a secret from the project. Connects Does not connect **Run them from the workspace root.** Like most `akan` commands, they need the folder that holds `package.json`, `tsconfig.json` and `.env`. **`--host` points at another cloud.** Every command that talks to Akan Cloud takes it, so a self-hosted cloud works with the same commands. `cloud: { host }` in the root `akan.config.ts` makes one the default. **One sign-in per host, per machine.** The session lives in `~/.akan/config.json`, so every workspace on this machine shares it. `--host` and `cloud.host` are both read as the URL's origin and path without a trailing slash, so a trailing slash, an uppercase host or a default port still names the same session. **Without a terminal, a missing argument is an error.** When stdin is piped or closed, as in CI, a missing argument or option is not asked for: the command fails at once with an error that says which is missing. A question a command asks while it runs — which script to run, a confirmation, which env server to copy to — fails the same way, naming the option that answers it. ## Code CLI Source: /references/cli/code Mirror: /llms/pages/references/cli/code.md Priority: P0 Headings: - Code CLI - Profiles Code CLI `akan code` runs an AI coding agent in your terminal that already knows this workspace. Ask it to add a field and run the validation loop, with no editor, no MCP client setup, and no explaining the module conventions first. Put a model key in the workspace `.env`, e.g. `DEEPSEEK_API_KEY` for the default model. Run `akan code` to start a session, or `akan code "<prompt>"` for one run. What The Agent Brings - Coding Tools — read · write · edit · ls · grep · find · bash — Reads, edits and runs commands in the workspace, and fetches and searches the web. The profile decides which are on. - Akan Tools — plan_workflow · apply_workflow · run_validation — Context inspection, workflows, repair and validation: the same set `akan mcp` gives an editor's agent. - Akan Skills — akan-module · akan-store · akan-validate · … — Playbooks for the scaffolding chain, the store surface and the validation loop, read when a task needs one. Add your own in `~/.akan/code/skills` or `.akan/code/skills`. - Project Rules — AGENTS.md — The workspace's `AGENTS.md` sits in the context window, so the agent follows the conventions from the first turn. Not akan mcp, Not akan agent install Command Agent runs in What it is - akan code — Your terminal — An agent of its own that already carries the tools and rules above. - akan mcp — Your editor — A server that lets an editor's agent reach this workspace's tools. - akan agent install — Your editor — Writes the rule files an editor's agent reads. Three Ways To Run One command runs in three modes, and the arguments pick one — there is no subcommand. They are checked in this order: Mode When What you get - RPC — `--rpc` — Serves akan wire frames over stdio for another process to drive. - Full-screen session — `--interactive`, or no prompt and no `--json` on a terminal — A chat you keep talking to. A prompt you pass becomes its first message. - One run — Any other call with a prompt — Runs the prompt to the end and prints each event. With `--json`, one JSON line per event. **Without a terminal, or with `--json`, a missing prompt is an error.** In a pipe or a CI step, always pass one: `akan code "add a comment module"`. **One run is the shape for scripts.** It exits when the prompt is done, and `--json` makes its output machine-readable. `akan code [prompt] [--app <app>] [--profile <local|pod|review|web>] [--model <provider/id>] [--json <boolean>] [--thinking <boolean>] [--rpc <boolean>] [--resume <id>] [--interactive <boolean>]` Runs the Akan coding agent. Pass a prompt for one run, or leave it off to open the full-screen session. - prompt (String): What the agent should do. Left off on a terminal, the full-screen session opens. - --app (String, nullable · flag: -a): Narrows the agent to one app, rooted at `apps/<app>`. Without it, the whole repo is in scope. ## Context Source: /references/cli/context Mirror: /llms/pages/references/cli/context.md Priority: P0 Headings: - Context CLI - What doctor Checks - MCP Tools And Resources Context `akan context [--format <format>] [--app <app>] [--module <module>]` Prints the workspace structure in a form an agent can read. Use it when an external coding agent, CI job or IDE extension needs a summary of the workspace. - --format (String, default markdown, markdown | json): Output format: `json` for tools, `markdown` for people or a chat prompt. - --app (String, nullable): Lists only this app. Every library and package still appears. - --module (String, nullable): Lists only modules of this name and puts each `*.abstract.md` body before its file list. - What it prints: Apps, libraries and packages, each module's files, generated-file patterns, validation commands. - Abstract scope: Without `--module`, an abstract shows only its path and headings; `--module` adds the body. - Privacy: It never prints `.env` values or secrets. `akan doctor [--format <format>] [--strict <boolean>] [--ios <boolean>]` Reports where the workspace drifts from Akan conventions, such as stray files or missing module abstracts. Run it before and after an agent's change; `--format json` gives a machine-readable result. - --format (String, default text, text | json): Output format. Use `json` for agent validation loops and CI. - --strict (Boolean, default false): Turns recommended conventions into errors; today that is a missing module abstract. - --ios (Boolean, default false): Checks only the native config instead, for a placeholder bundle id Apple has likely claimed. - Status: `failed` when any diagnostic is an error, `passed` otherwise. - Also printed: Generated-file freshness, a repair command per problem, and the validation commands. - Boolean options: `--strict` alone means `--strict true`. `akan mcp [--mode <readonly|plan|apply>]` Starts the Akan MCP server over stdio. An MCP-aware coding agent asks it for workspace and module context, guidelines, command explanations and diagnostics. `--mode` decides how far the agent may go, and the default is the narrowest. - --mode (String, default readonly, readonly | plan | apply): `readonly` only reads; `plan` may also write a plan file; `apply` may also edit source. - plan mode: Adds `list_workflows`, `explain_workflow` and `plan_workflow`, which write only a plan file. - apply mode: Adds `apply_workflow`, `run_validation` and the repair tools, so it edits source. - Workflow policy: `AGENTS.md` tells agents to plan with `--mode plan`, apply with `--mode apply`, prefer workflows. - Module context: `get_module_context` returns the module abstract first, then the module's file list. - Where to run: Start it from the workspace root; the server reads the workspace from its current folder. `akan mcp-install [target] [--force <boolean>] [--mode <readonly|plan|apply>]` Registers the Akan MCP server in the project config of Cursor, Claude Code and Codex. Other servers in those files are kept; only the `akan` entry is written. - target (String, default all, cursor | claude | codex | all): Which tool to register. Leave it off to register all three. - --force (Boolean, default false): Replaces an `akan` entry that differs. Without it the command stops with an error. - --mode (String, default apply, readonly | plan | apply): The mode the editor starts `akan mcp` in. The default here is `apply`, not `readonly`. ## Guideline Source: /references/cli/guideline Mirror: /llms/pages/references/cli/guideline.md Priority: P0 Headings: - Guideline CLI - Guideline List Guideline `akan guideline <action> [name]` Lists the guidelines bundled with the CLI, or prints one of them as Markdown. Use it when an agent, a documentation tool or a contributor needs more depth on one area than `AGENTS.md` carries. - action (String, list | show, required): `list` prints every guideline name, one per line; `show` prints one guideline. - name (String): Guideline to print, such as `framework`, `moduleOverview` or `modelSignal`; required for `show`. - Read-only: Guidelines are files installed with the CLI; the command reads them and never writes. - Same text as agents: MCP `get_guideline` and `akan guideline show` read the same bundled files. - Unknown name: `show` with a name that does not exist fails with an error listing every valid name. - Version: The text is the installed CLI's own, so it changes when you upgrade the CLI. Guideline CLI Guidelines are instruction documents for coding agents that ship inside the Akan CLI. `akan guideline` prints them in the terminal; it calls no LLM and changes no file. Reach for it when one module file, scalar file, UI pattern or framework-wide rule needs the most specific instruction there is. Words Used On This Page Term - guideline: An instruction document for coding agents that ships inside the Akan CLI, one per area or file role. - AGENTS.md: The guide an agent reads on every task: the short rules, plus which guideline covers the rest. - MCP: Model Context Protocol, the standard way a coding agent calls tools outside itself. - get_guideline: The MCP tool that returns one guideline by name. Where The Same Text Is Read Every path below reads the same files, so a person and an agent see the same words. Path - akan guideline show <name>: A person reads one guideline in the terminal, as Markdown. - get_guideline: The tool the `akan code` agent and editor agents on `akan mcp` use to fetch one guideline. - akan://guidelines/<name>: An MCP client finds one resource per guideline in its resource list. - akan agent install: Copies `framework`, `conventions` and `workspaceOnboarding` into the `AGENTS.md` agents read. **AGENTS.md is a copy.** It is written when you run `akan agent install`. Every other path reads the installed CLI each time. **Agents fetch before a deep pass.** `AGENTS.md` names the guideline for each area, and the agent loads it with `get_guideline` before a larger change there. MCP Tools And Resources Every tool `akan mcp` offers, `get_guideline` included. Writes and refreshes `AGENTS.md` and the editor pointers. ## Library Source: /references/cli/library Mirror: /llms/pages/references/cli/library.md Priority: P0 Headings: - Library CLI Library Library CLI Five commands that create, install, sync, check and remove the shared libraries in `libs/`. Use a library for domain, utility, UI or platform code that several apps import. Words Used on This Page Term - library: A folder under `libs/` holding code several apps share: domain modules, UI or utilities. - template: A ready-made library from Akan.js, such as `shared` or `util`, that `install-library` copies in. - akan.source: The stamp `install-library` puts in the library's `package.json`: origin, commit or version, hash. - drift: An installed library whose files no longer match the hash in its stamp. What Each Command Touches Command Root `package.json` Git history - Add a library - create-library: Start a new library you fill in yourself. - install-library: Copy in a template such as `shared` or `util`. - Keep it current - sync-library: Refresh the generated files after you change the library. - library-status: Check whether installed libraries changed after the install. - Remove - remove-library: Delete the whole library folder. Changed Untouched Common Rules **Name the library, or pick it from a list.** `remove-library` and `sync-library` list the libraries in `libs/` when the name is missing or unknown; `create-library` and `install-library` ask you to type one when it is left out. **`akan sync <lib>` is the same step as `sync-library`.** `create-library` runs it for you, and `akan lint <lib>` runs it before linting. **Only an installed library has a stamp.** A library made with `create-library` shows as `unstamped` in `library-status`. **Commit your own work before these.** `install-library` stages the whole working tree with `git add .` and commits it, and `remove-library` deletes the folder without asking. Related Pages create-workspace ## Module Source: /references/cli/module Mirror: /llms/pages/references/cli/module.md Priority: P0 Headings: - Module CLI Module Module CLI Six commands that create, remove and fill in modules inside an app or library. Use `create-module` for a feature built around a stored model, `create-service` for one that is not. Words Used on This Page Term - database module: A module built around one stored model, in `lib/<module>/`. - service module: Behavior not tied to one stored model, such as notifications, in `lib/_<service>/`. - sys: The app or library that holds the module: `shop` in `shop:story`. - scaffold: The starter code a command writes, meant to be edited. - report: What a create command prints at the end: the files it wrote and the commands to run next. Files a New Module Gets File - Model and logic - .abstract.md: The module's rules and workflows, in prose. - .constant.ts: The fields and the Light class. - .document.ts: Queries and state changes on the stored record. - .dictionary.ts: English and Korean labels. - .service.ts: The business logic. - .signal.ts: The endpoints callers reach. - .store.ts: Client state and actions. - UI - .View.tsx: The detail screen for one record. - .Unit.tsx: One row or card in a list. - .Template.tsx: The create and edit form. - .Zone.tsx · .Util.tsx: A page section, and small domain helpers such as a remove button. Written Not written The other three create commands fill in one UI file of an existing module: `create-view` the View, `create-unit` the Unit, and `create-template` the Template. Rules All Six Share **Name the target, or pick it from a list.** `create-module` and `create-service` take the app or library as their second argument; the other four take `<sys>:<module>`. Leave it out and the CLI asks. ## Commands Source: /references/cli/overview Mirror: /llms/pages/references/cli/overview.md Priority: P0 Headings: - CLI Commands - Shared Behaviour - Validation Order - Command Index Commands Command CLI Commands The `akan` CLI runs the whole workspace lifecycle: creating workspaces and apps, generating code, local development, native builds, local databases and optional cloud helpers. This page is the index. Each group links to a detail page with argument tables, option tables, notes and terminal examples. Reading a command line Notation - <app>: A value the command needs. Leave it off and the command asks for it. - [filename]: An optional value. The command runs without it. - <app|lib|pkg>: `|` means or: the name of an app, a library or a package. - <sys:module>: An app or lib and a module, joined by a colon: `myapp:icecreamOrder`. - [apps...]: One or more app names, space- or comma-separated, or `all` for every app. - --name <value>: An option. Words are joined with dashes: `--max-diagnostics 0`. - --fix false: A boolean option takes `true` or `false`. The flag alone means `true`. - --no-write: A boolean option that defaults to `true` also takes `--no-<name>` to turn it off. Shared Behaviour These hold for every command, so the detail pages do not repeat them. - Verbose Output — `-v, --verbose` — Every command accepts it. It prints the output of each process the command runs, which a spinner normally hides. - Help — `akan <command> --help` — Prints the command's arguments and options with their defaults and choices. Bare `akan` lists every command. - Run From The Workspace Root — `package.json · tsconfig.json · .env` — Run every command except `create-workspace` from the folder that holds these three files. Anywhere else it stops with an error. - Short Aliases — `akan ba = akan build-android` — Nine commands also answer to the first letter of each dashed word. The table below lists all of them. Alias Runs - akan s — akan start - akan b — akan build - akan t — akan typecheck - akan bi — akan build-ios - akan ba — akan build-android - akan bd — akan build-desktop - akan si — akan start-ios ## Package Source: /references/cli/package Mirror: /llms/pages/references/cli/package.md Priority: P0 Headings: - Package CLI Package Package CLI Six commands that create, build and verify the packages under `pkgs/`: the framework (`akanjs`), the CLI and other tooling. They sit below the app and library commands, so use those for product code. Words Used on This Page Term - package: A folder under `pkgs/` with its own `package.json`, such as `akanjs` or `@akanjs/cli`. - dist: The build output in `dist/pkgs/<pkg>/`, which is the folder that gets packed and published. - exports: The export map in `package.json`: which import paths a consumer may use, and the file each opens. - npm pack --dry-run: Lists what a publish would upload and its size, without writing a tarball. Typical Order `akan create-package --name renderer` makes `pkgs/renderer/`. Add its `package.json` and `index.ts` yourself. Write the code and test it with `akan test renderer`. `akan build-package renderer` writes `dist/pkgs/renderer/`. `akan verify-dist-package renderer` checks that folder before you publish it. What Each Command Changes Command Source Root tsconfig Build output - Check - version: Print the `akanjs` version in use. - sync-package: Scan one package's imports as a quick check. - Add and remove - create-package: Start a new folder in `pkgs/` and register its import path. - remove-package: Delete the folder and its import path. - Build and publish - build-package: Write the dist folder and the dependency list. - verify-dist-package: Check the dist folder before you publish it. Changed Untouched ## Page Source: /references/cli/page Mirror: /llms/pages/references/cli/page.md Priority: P0 Headings: - Page CLI Page Page CLI `create-crud-page` writes the list, create, detail and edit pages for a module that already exists, so you can browse and edit its data right away. Run it after `create-module`, then edit the pages like any other code. Words Used on This Page Term - CRUD: Create, read, update and delete: the basic things you do with a model's records. - sys:module: How the CLI names a module: `shop:product` is `lib/product/` in the `shop` app. - route group: A folder in parentheses, such as `(public)`. It groups files and adds nothing to the URL. - scaffold: The starter code a command writes, meant to be edited. Pages It Writes File Default - Written into the target folder, by default `page/(<app>)/(public)/<module>/` - _index.tsx: `/<module>`: the list of cards, with a create button. Under `--single` the button opens a modal. - new/_index.tsx: `/<module>/new`: the create form, built from `Template.General`. - [<module>Id]/_index.tsx: `/<module>/<id>`: the detail from `Zone.View`, with a link to the edit page. - [<module>Id]/edit/_index.tsx: `/<module>/<id>/edit`: the edit form, filled with the saved record. Written Not written What the Module Must Have The pages call these parts of the module. A module made with `create-module` has all of them; if you renamed or removed one, fix the generated pages to match. Part - inPublic: The slice the list and both forms load and save through. - Zone.Card, Zone.View: The list of cards and the detail screen. - Template.General: The form body, shared by the create and edit pages. Check After It Runs **Links assume the URL is `/<module>`.** The buttons, the redirect after saving and the cards in `Zone.Card` all point to paths starting with `/<module>`. Move the pages to another URL and update them too. **`--single` writes no detail page.** Each card still links to `/<module>/<id>`, so change that link, or generate the full set of four pages without `--single` instead. **The pages check no session.** Writes follow the slice `create-module` wrote: `cru: Admin` with `libs/shared`, `cru: None` without it. Gate the pages in a `_layout.tsx` and set the guards your screens need before you ship. **`--base-path` is a folder inside the app, not a URL prefix.** `--base-path admin` writes to `apps/shop/admin/`, outside `page/`, so no route is created. Give the whole folder, such as `page/(shop)/(admin)/product`. ## Pipeline Source: /references/cli/pipeline Mirror: /llms/pages/references/cli/pipeline.md Priority: P0 Headings: - Pipeline CLI Pipeline `akan pipeline [plan|validate|dry-run] [--branch <branch>] [--env <env>] [--apps <a,b>] [--trigger <trigger>] [-n <num>] [--commit <sha>] [--out <file>] [--format <text|json>]` Plan the build pipeline declared in the workspace and app `akan.config.ts` files, without running it. Each flag is a fact about the build: a flag you give is copied into the plan as is, and a missing one comes from git and the workspace. - action (String, default dry-run, plan | validate | dry-run): `dry-run` shows the plan, `validate` checks it, `plan` prints the envelope. - --branch (String, default current git branch): Branch the build is for; every `when.branch` is decided against it. - --env (String, default the branch): `AKAN_PUBLIC_ENV` the build is for. - --apps (String, default every app): Apps the build covers, comma-separated; an unknown or repeated app is an error. - --trigger (String, default manual, push | redeploy | initial | rebuild | manual): What started the build; every `when.trigger` is decided against it. - --build-num (Number, default 0, -n): The build's number, a whole number of 0 or more. - --commit (String, default HEAD): Commit the build is for. - --out (String): Also write the envelope to this file, whole or not at all. - --format (String, default text, text | json): `json` prints the envelope instead of text, for any action. - nothing runs: No stage runs and nothing is uploaded; Akan Cloud runs the same planner when it builds. - function form: `validate` runs a function-form `pipeline` for one sample context and warns that others may differ. - exit code: 0 a plan, 1 errors with the envelope written, 2 anything else with no envelope. Pipeline CLI `akan pipeline` turns the pipeline declared in your `akan.config.ts` files into the plan Akan Cloud would run, and runs none of it. Check a change with it before you push. Words Used on This Page Term - plan: The phases, stages and steps one build runs, as JSON that Akan Cloud executes. - phase: Stages that run together; the next phase starts when every stage of this one ends. - envelope: `{ ok, plan, diagnostics }`, the result `plan` prints or writes to `--out`. - diagnostic: An error or warning about a definition, with a code such as `pipeline.action.dockerWithoutBuild`. Three Actions Prints Use it for - dry-run — The plan as a table, phase by phase. — Seeing what a build would run. - validate — A one-line verdict and the diagnostics. — Checking a definition before you push. - plan — The envelope as JSON. — Handing the plan to a program. Exit Codes ## Primitive Source: /references/cli/primitive Mirror: /llms/pages/references/cli/primitive.md Priority: P0 Headings: - Primitive CLI - Primitive or Workflow Primitive Primitive CLI Three commands that add one field or one UI file to a module that already exists. They write the mechanical part people get wrong by hand: a dictionary label left out, an import never added, a component in the wrong file. They are the steps the `create-ui`, `add-field` and `add-enum-field` workflows apply. Run them directly when you already know what you want. Words Used on This Page Term - primitive: A command that writes one change you already decided on straight to source, with no plan step. - surface: The role of one module UI file — `view`, `unit` or `template` — picked with `--surface`. - report: What each command prints when it ends: the changed files, diagnostics, and what to run next. - workflow: The same change plus a plan to review first and checks to run after, compared at the end. What Each Command Writes Command - Add a UI file - create-ui: Writes one View, Unit or Template file and nothing else. - Add a field - add-field: Adds the field to the Input class and its label to the dictionary. - add-enum-field: Declares an enum class first, then adds a field typed as that class. Written Not touched Rules All Three Share **Missing options are not asked for.** Leave out `--app` or `--module` and the command prints an error in its report instead of a prompt. **An error writes nothing.** An unknown app, a missing input or a bad value leaves every file as it was, and the report names the cause. **You run sync and lint.** The command only writes source. Its report lists `akan sync <app>` and `akan lint <app>` as the next steps. **`--format json` is for scripts and agents.** It prints the same report as one JSON object. `akan create-ui --app <name> --module <name> [--surface <view|unit|template>] [--format <markdown|json>]` Write one UI file into `lib/<module>/` of an existing module: a View, a Unit or a Template. It writes from the same template `akan create-module` uses, and touches no other file. It is the flag form of `akan create-view`, `create-unit` and `create-template`. - --app (String, -a, required): Target app or library name. - --module (String, -m, required): Target module name, such as `icecreamOrder`. - --surface (String, default template, view | unit | template · -u): Which file to write; Zone and Util are not built by this command. - --format (String, default markdown, markdown | json · -o): `markdown` is for a person to read; `json` is the same report as one object. ## Quality Source: /references/cli/quality Mirror: /llms/pages/references/cli/quality.md Priority: P0 Headings: - Quality CLI - What Scan Reports - Rules By Scope - Server Render Share Quality Quality CLI Lint tells you a line is wrong. `akan quality` tells you the shape of the codebase is drifting: none of it is a syntax error, and none of it shows until someone measures. What It Catches - Files Grown Too Long — A service past 500 lines, a Template or Zone past 800, or a Util past 1,000. — `akan.file.recommended-max-lines` - Helpers In The Wrong File — A helper function declared in `order.service.ts` next to `OrderService`. — `akan.convention.service` - Modules With No Server View — Its UI renders only from Template, Zone and Util, so all of it ships to the browser as JavaScript. — `akan.ssr.module-missing-server-view` - Markup In The Bundle — A client component wraps a large static subtree around one or two handlers. — `akan.ssr.client-static-markup` Run it before a review, after a refactor, and after any change to a `.tsx` file. The render share is the one number a UI change can quietly lower. Words Used On This Page Term - rule: One check, named `akan.<scope>.<name>`; every warning names the rule that raised it. - scope: The group a rule belongs to; there are six, and the output is sorted by scope name. - server render share: Of the JSX elements in `ui/` and `lib/`, the percentage that renders on the server. `akan quality [action] [--format <text|json>]` Scan every app and library for code quality warnings, or measure the server/client render balance.`scan` (default) prints every warning, then the SSR balance and the suggested rules.`ssr` prints the SSR balance first, then only the warnings whose scope is `ssr`. - action (String, default scan, scan | ssr): Which report to print: `scan` covers everything, `ssr` the render balance alone. - --format (String, default text, text | json): Short form `-f`; `json` prints the whole result for tools, each warning's `fix` included. - where to run: The workspace root, the folder holding `package.json`, `tsconfig.json` and `.env`. - what is read: `.ts` and `.tsx` under `apps/` and `libs/` except `.d.ts`, plus every `*.abstract.md`. - what is skipped: Paths matched by the root `.gitignore`, plus `node_modules` and `.git`. - exit code: Success whatever it finds, so it runs beside lint and typecheck without becoming a third gate. What Scan Reports Each warning says where, which rule, what is wrong and how to fix it. After the warnings come the SSR balance and the suggested rules, so one plain `akan quality` run covers both. A shortened run looks like this: **One line per warning:** `<file>:<line>:1 - warning <rule>: <message>`. A `global` warning has no single file, so it prints `<global>` instead. **Indented lines add detail.** `note: related location` lists each place involved, and `fix:` says what to change. **Sorted by scope name,** then by file and line, so the scopes below appear in this order. **Only need the render balance?** `akan quality ssr` prints it first and keeps only the `ssr` warnings. The Six Scopes - agent: Form fields that publish no agent tool because their setter is wrapped. ## Scalar Source: /references/cli/scalar Mirror: /llms/pages/references/cli/scalar.md Priority: P0 Headings: - Scalar CLI Scalar Scalar CLI Two commands that create and remove a scalar inside an app or library. A scalar is a reusable value object saved inside other models, not a model with its own table; for that, use `create-module`. Words Used on This Page Term - scalar: A named group of fields saved inside other models, like `Price`. It has no table of its own. - sys: The app or library that holds the scalar: `shop` in `akan create-scalar price shop`. - scaffold: The starter code a command writes, meant to be edited. - report: What `create-scalar` prints at the end: the files it wrote and the commands to run next. Files Each Command Touches File - Scaffolded into `lib/__scalar/<scalar>/` - <scalar>.abstract.md: What the value means and its reuse rules, as headings to fill in. - <scalar>.constant.ts: The class with the fields, starting with one placeholder `field: field(String)`. - <scalar>.dictionary.ts: English and Korean labels, written with `scalarDictionary`. - <scalar>.document.ts: The server-side class, one line: `by(cnst.<Scalar>)`. - Written by hand, in the same folder - <Scalar>.Template.tsx: The editor for the value inside a parent form. - <Scalar>.Unit.tsx: The display of the value inside a parent card or detail page. - Outside the folder - code that uses it: Fields such as `field(Price)` and imports in other modules. Neither command touches them. Written or deleted Not touched Rules to Know **Name the target, or pick it from a list.** The second argument is the app or library. Leave it out, or give a name that does not exist, and the CLI shows a list. A missing scalar name is asked for. **`create-scalar` never overwrites.** A file already at the path keeps its content, so running it again only restores missing files. **`create-scalar` ends with a report.** It lists the files written and the next steps, `akan sync <sys>` and `akan lint <sys>`. Add `-o json` for the same report as one JSON object. **`remove-scalar` takes the folder name exactly as typed.** Nothing is lowercased, so write `coordinate`, not `Coordinate`. It prints no report. **Check usages before you remove a scalar.** `remove-scalar` deletes the folder without asking and leaves every field and import that used it broken until you fix them. Related Pages ## Tunnel CLI Source: /references/cli/tunnel Mirror: /llms/pages/references/cli/tunnel.md Priority: P0 Headings: - Tunnel CLI - Share Or Tunnel Tunnel CLI `akan tunnel` puts a public URL in front of the dev server on your laptop, for as long as you need it. No deployment is involved. - Check on a Phone — A designer opens the screen you just built on their own phone, right now. - Receive a Webhook — A payment provider's webhook reaches the handler you are still editing. Usually you need this while running the app anyway, so `akan start --share` opens the share with the session. `akan tunnel` is the standalone form: it shares an app that is already running and does nothing else. See which one to use. Words Used on This Page Term - share: One local app connected to a public URL. It has a code, a URL and an expiry. - code: The short name of a share. `--stop` takes it. - Akan Cloud: The server that issues public hostnames and tracks shares. `akan login` signs in to it. - TTL: How long a share lives before it expires on its own. **Anyone with the URL reaches your whole dev server.** That is every route under `page/`, the API prefix, the websocket, and `/mcp` if the app mounts it, with nothing in front. Give it a `--ttl`, stop it when the call ends, and never share a session signed in to production data. `akan tunnel [app] [--list <boolean>] [--stop <code>] [--host <url>] [--port <number>] [--ttl <min>]` Share an app running on this machine on a public URL. The connection runs inside this command, so nothing needs installing before the URL appears. The share lives as long as the command does: Ctrl-C ends it and hands the address back. - app (String): App to share. Taken as is when there is only one app, and picked from a list when there are several. - --list (Boolean, default false): List this account's shares with connection state, code, URL, app name and expiry, then exit. - --stop (String, default ""): Revoke the share with this code, then exit. - --host (String, default https://cloud.akanjs.com): Akan Cloud to use. In the framework repo (`USE_AKANJS_PKGS=true`) it is `http://localhost:8283`. - --port (Number, nullable): Local port to share. Unset, it is the dev port `akan start` gives this app. - --ttl (Number, nullable): Minutes until the share expires on its own. Unset, Akan Cloud decides. - URL: Printed with its expiry and an `akan tunnel --stop <code>` line, and copied to the clipboard. - Ctrl-C: The first one hands the hostname back. A second exits at once, and the share expires on its TTL. - reconnect: A dropped link is reported and reconnected. The share stays open. - before the app: The share can open before the app listens. Requests are refused until the port opens. - account: A share belongs to the account `akan login` signed in to on that `--host`. `--list` shows them. - --list · --stop: Neither asks for an app. They act on the account's shares. - not a deployment: Requests reach the dev server as they are. No auth, cache or build step is added in front. Share Or Tunnel Both open the same kind of share on the same Akan Cloud. What differs is which process holds it, and so when it ends. Aspect ## Workflow Source: /references/cli/workflow Mirror: /llms/pages/references/cli/workflow.md Priority: P0 Headings: - Workflow CLI - Plan, Apply, Validate - Workflow Catalogue Workflow plan and apply mode apply mode CLI only Needs: Workflow CLI Adding one field to a module touches five files, and most of that work is mechanical. By hand, the decisions that matter — the name, the type, the default — get lost among dictionary labels and generated barrel files, and no two modules end up quite alike. A workflow gives that change a name: you plan it, read the plan, apply it, and validate the result. When validation fails, `akan repair` runs the one command that clears that failure. Words Used on This Page Term - workflow: A named recipe for a change that always touches the same files in the same order. - plan file: The JSON `plan --out` writes: the steps, the files it expects to change, and the checks to run. - run artifact: What an apply, a validate or a repair leaves in `.akan/workflows/runs/<runId>.json`. - runId: The run artifact's file name, such as `apply-20260921103000-a1b2c3`. - akan repair: A narrow fix for one known kind of failure, picked by `<kind>`. **Reach for a workflow before a direct edit.** When a workflow or a repair can make the change, use it instead of editing source by hand. Plan, Apply, Validate The steps form one chain, and each hands the next a file path rather than a name. That makes the plan a document you review before anything is written, and the run artifact a record of what happened. Workflow chain Plan Apply Validate Repair plan JSON on failure 1. Plan Checks your inputs and writes the plan JSON: the steps, the files it expects to change, and the checks to run. Source is neither read nor written. 2. Apply Takes the plan file, not a workflow name, and writes the source changes. A plan with an error, such as a missing input, applies nothing. 3. Validate ## Workspace Source: /references/cli/workspace Mirror: /llms/pages/references/cli/workspace.md Priority: P0 Headings: - Workspace CLI - Rules Every Command Shares Workspace Workspace CLI These commands act on the whole workspace. Create a new one, and lint or sync every app and library at once. Command - create-workspace: Create a new workspace with its first app, agent rules and MCP config. - lint: Format and lint one app, library or package with Biome. - lint-all: Sync every app and library, then lint every app, library and package. - sync-all: Run `akan sync` on every library, then on every app. Words Used On This Page Term - workspace root: The repo's top folder, the one holding `package.json`, `tsconfig.json` and `.env`. - sync: Rescans an app or library and rewrites its generated files. `akan sync <app|lib>` does one. - Biome: The formatter and linter Akan uses. Its rules live in `biome.json` at the workspace root. Which One To Run The three upkeep commands differ in scope and in whether they lint after the sync. - One target - lint: You changed one app, library or package. A package is linted without a sync. - Whole workspace - lint-all: Before a wide check, where generated files, app code and libraries must agree. - sync-all: Generated files look stale, or you changed the shared workspace setup. Runs it Skips it `akan create-workspace <workspaceName> --app <app> [options]` Create a new workspace and its first app in one go. It runs these steps in order:Write the workspace files into `<dir>/<workspaceName>`, with `--registry` saved to `.npmrc`.Run `bun install`. `--init false` skips it.Install the `util` and `shared` libraries, only with `--libs true`.Create the first app, named by `--app`.Write the agent rules and the MCP config. `--agent-install` and `--mcp-install` turn them off.Make the first git commit. If git fails, the workspace still works; commit by hand.It ends by printing the next step: `cd <dir>/<workspaceName> && akan start <app>`. - workspaceName (String, required): Organization or workspace name, lowercased with spaces as hyphens. Asked for when omitted. - --app (String, required): Name of the first app, lowercased with spaces as hyphens. Asked for when omitted. - --dir (String, default .): Parent folder, relative to where you run it. Defaults to `local` if `USE_AKANJS_PKGS=true`. - --libs (Boolean, default false): Also install `shared` and `util`. Leave it off, as recommended, to start from an empty workspace. - --init (Boolean, default true): Run `bun install` once the files are written. - --registry (String, default https://registry.npmjs.org): npm registry for the Akan packages, saved to `.npmrc`. `AKAN_NPM_REGISTRY` sets the default. ## Assets (public/ private/) Source: /conventions/applib/asset Mirror: /llms/pages/conventions/applib/asset.md Priority: P1 Headings: - Asset Folders - Public Assets - Optimized Images - Private Assets - Library Assets - Which Folder? Assets (public/ private/) Asset Folders Apps and libraries keep file assets in two folders at their root, beside `lib/` and `ui/`. Which one a file goes in depends on one question: may the browser download it? - public/ — The browser may download it — Served as static files by URL. Images, PDFs, downloadable JSON and icons go here. — `public/images/hero.png → /images/hero.png` - private/ — Only the server reads it — Never served. Seed data, private JSON, model files and resources for server jobs go here. A desktop app that carries its server ships the folder in plain text on the user's computer. — `private/model/yolo.onnx` **No wrapping folder.** There is no `asset/` folder; `public/` and `private/` sit directly at the root. **Libraries have the same pair.** Every app that depends on the library can use them, as the Library Assets section shows. Public Assets The server serves every file under `public/` as a static file. Its URL is the file path with `apps/myapp/public` dropped: File - /docs/product-guide.pdf: `apps/myapp/public/docs/product-guide.pdf` - /data/sample-products.json: `apps/myapp/public/data/sample-products.json` ## Common Utils (common/) Source: /conventions/applib/common Mirror: /llms/pages/conventions/applib/common.md Priority: P1 Headings: - Common Utility Overview - What Belongs In common/ - Barrel And File Shape - Using It On Both Sides - Practical Rules Common Utils (common/) Server Browser Common Utility Overview `common/` holds code that behaves the same on the server and in the browser: small, pure helpers that need no runtime of their own. A service, a signal, a store, a page and a `*.constant.ts` file can all import the same helper. Reach for it when both sides need the same formatting, validation, metadata or transform, so the two never disagree. Which folder? Code outside `lib/` goes in one of five folders. Choose by what the code touches, not what it is for; the `srvkit/` and `webkit/` pages open with this same table. Folder - common/: Pure, isomorphic, zero-dependency; imports only sibling common/* and akanjs/base, not Err. - webkit/: Touches window, navigator or the native bridge (akanjs/client/native), or is a React hook. - srvkit/: Touches node:*, Bun, process.env, a secret, or a server SDK. ## akan.config.ts Source: /conventions/applib/config Mirror: /llms/pages/conventions/applib/config.md Priority: P1 Headings: - akan.config.ts Overview - Config File Shape - routes - native - database - web - images - i18n - publicEnv - secrets - syncPageLibs - externalLibs - barrelImports - optimizeImports - docker - Library Config Fields akan.config.ts akan.config.ts Overview Every app and library keeps one `akan.config.ts` at its root. It declares how that app is served, built and packaged: domains, web surfaces, the native app, the database modes and the Docker image. Start from an empty object. Every key you leave out takes a framework default, so add a key only when the default stops fitting: Every key at a glance An app declares its config as `AppConfig` and a library as `LibConfig`. The sections below cover each key; `api`, `assets` and `plugins` are in the full reference. Key App Library - Serving the web - routes: Which domains open the app, and which basePath each one maps to. - web: Which web surfaces the build produces: SSR pages, the CSR shell, or API only. ## Server Utils (srvkit/) Source: /conventions/applib/srvkit Mirror: /llms/pages/conventions/applib/srvkit.md Priority: P1 Headings: - Server Utility Overview - What Belongs In srvkit/ - Server Level: WebProxy And Middleware - Signal Level: Guard And InternalArg - Service Logic And External Libraries - Adaptor And plug - Practical Rules Server Utils (srvkit/) Server Utility Overview `srvkit/` holds server-only code that services, signals and server jobs call. Keeping it here lets the module files stay focused on business behavior. It is also the one safe door for external libraries: vendor SDKs and low-level server APIs pass through srvkit first. **Module files cannot import a third-party package.** In `*.service.ts`, `*.signal.ts` and the other module files, lint accepts only relative paths and workspace packages such as `akanjs/*`, `@apps/*` and `@libs/*`. Even `node:crypto` is refused, so import it in srvkit and export what the service needs. Which folder? Code outside `lib/` goes in one of five folders. Choose by what the code touches, not what it is for; the `common/` and `webkit/` pages open with this same table. Folder - common/: Pure, isomorphic, zero-dependency; imports only sibling common/* and akanjs/base, not Err. - webkit/: Touches window, navigator or the native bridge (akanjs/client/native), or is a React hook. - srvkit/: Touches node:*, Bun, process.env, a secret, or a server SDK. - ui/: Renders JSX or defines a recipe, bound to no model; a model-bound component goes in its module. ## Components (ui/) Source: /conventions/applib/ui Mirror: /llms/pages/conventions/applib/ui.md Priority: P1 Headings: - UI Folder Overview - Recommended Shape - Import From The Barrel - Composite Components - Practical Rules Components (ui/) UI Folder Overview `ui/` holds components that draw a piece of screen and are not bound to one model. Pages and module components import them by name instead of repeating the markup. App UI Components one app owns, such as an admin header, a landing hero, a dashboard widget or an app-only interaction. Keep the folder shallow. Library UI Components several apps share, such as auth gates, responsive wrappers, editor pieces or common form fields. Words used on this page Term - barrel: A folder's `index.ts` that re-exports its files, so callers import one path: `@apps/myapp/ui`. - "use client": The first line that makes a file a client component. Without it, a component renders on the server. - namespace component: Several components exported as one object, used as `Only.Web` or `Chart.Bar`. ## Web Utils (webkit/) Source: /conventions/applib/webkit Mirror: /llms/pages/conventions/applib/webkit.md Priority: P1 Headings: - Webkit Overview - What Belongs In Webkit - Barrel And File Names - Practical Rules Web Utils (webkit/) Webkit Overview `webkit/` holds browser code that several screens reuse but that is not a component. It is the browser-side twin of `srvkit/`, which holds server-only code. Pages and components then import one name from the webkit barrel instead of carrying the logic themselves. Words used on this page Term - barrel: A folder's `index.ts` that re-exports every file in it, so callers import the folder path. - "use client": Marks a file as client code. A server component cannot call its functions or read its values. - server component: A page, `Unit` or `View`. It renders on the server and reaches the browser as HTML only. Which folder? Pick the folder by what the code touches, not by what it is for. The `common/`, `webkit/` and `srvkit/` pages all open with this table. Folder ## model.abstract.md Source: /conventions/module/abstract Mirror: /llms/pages/conventions/module/abstract.md Priority: P1 Headings: - model.abstract.md - A Real Example - Replace The Scaffold model.abstract.md Every database module keeps one `lib/<model>/<model>.abstract.md`: a few lines of markdown stating the rules the module obeys but its code cannot say. Read it before changing the module, and update it when one of those rules changes. What The Code Cannot Say Take the `user` module in `libs/shared`. Its constant file and its abstract say different things about the same two fields. What The Constant File Shows `accountId` and `phone` are secret, optional strings. What Only The Abstract Says Neither may repeat across active, dormant and restricted accounts, but both may repeat once an account has left. **Nothing else states it.** No field or type says it, and `user.document.ts` repeats the check in several methods without ever naming it as a rule. **Missing it breaks sign-up.** A uniqueness index added without knowing the rule stops everyone who ever deleted an account from signing up again. **That is the abstract's job.** It holds the invariants the module obeys but cannot state (rules that must always hold), and nothing the constant file already says. The Four Parts ## model.constant.ts Source: /conventions/module/constant Mirror: /llms/pages/conventions/module/constant.md Priority: P1 Headings: - model.constant.ts - Field Options - Hidden, Secret, Visual - The Instance And Its Logic - Text Search Fields - Cascade Remove Fields - Resolved Fields - Extending Library Models - Practical Rules model.constant.ts This one file describes the shape of one business object. The storage schema, the generated CRUD, form state, the API contract, the admin explorer and the schema an AI agent reads all come from it, so no other file in the module restates the fields. Open it whenever a field is added, changed or removed, and whenever the model needs display or predicate logic. Words Used On This Page Term - document: One stored record of a model, such as one ticket. - relation: A field whose type is another model, like `File`. It stores the id and loads the model. - scalar: A value object declared under `lib/__scalar/`, stored inside the document, not as its own row. - hydrate: Turning fetched plain data back into a model instance, with its methods and `Dayjs` dates. - projection: A read option naming extra fields to load, such as `{ secret: true }`. - agent: An AI caller: the in-page agent or an MCP client. Five Classes, Always In This Order ## model.dictionary.ts Source: /conventions/module/dictionary Mirror: /llms/pages/conventions/module/dictionary.md Priority: P1 Headings: - model.dictionary.ts - Model Dictionary Pattern - Using Dictionaries - Extending A Library Model - Scalar And Service Dictionaries - Errors, UI Text, And Languages - Rules At A Glance model.dictionary.ts `<model>.dictionary.ts` is the module's language layer. It gives every name a user reads a label in each language: fields, insight values, filters, sort orders, enum values, slices, endpoints, errors and the module's own UI text. Code never writes that text itself; it asks for it by key, such as `l("ticket.title")`. The keys are typed against the constant, filter, slice and endpoint, so adding a field without a label is a compile error. Words used on this page Term - label: The text a user reads for one name, written once per language: `t(["Title", "제목"])`. - desc: A longer explanation added with `.desc([en, ko])`. Forms show it as a tooltip. - key: The dotted path code uses to read a label, such as `ticket.title`. - language tuple: One entry per language, in the order the builder was given: `["Title", "제목"]`. - stage: One call in the chain, such as `.model()` or `.error()`. Each labels one kind of name. Model Dictionary Pattern A database module uses `modelDictionary`. The stage order is fixed, and a stage with nothing to label is still written, empty, so every dictionary reads the same way. ## model.document.ts Source: /conventions/module/document Mirror: /llms/pages/conventions/module/document.md Priority: P1 Headings: - model.document.ts - Standard Document Shape - Queries, Sorts And Generated Methods - Text Search Query - Changing One Document - Model-Level Helpers - Extending A Library Model - Loaders And Lookups - Schema Hooks And Indexes - Practical Rules model.document.ts `model.document.ts` decides how a stored model is queried and changed. `model.constant.ts` says what the data looks like; this file holds the reusable queries, the state changes and the database helpers that services call. Open it when a service repeats the same query, when a record moves between states, or when a table needs a counter, a loader or an index. Words used on this page Term - filter: A named, reusable query such as `inProject`. Each one generates fourteen methods. - document: One loaded record: a class instance with `set()`, `save()` and your own chain methods. - chain method: A document method that changes `this` and returns it, so calls chain before one `save()`. - model: The class for work on the whole collection. A service reaches it as `this.ticketModel`. - this.Ticket: The table facade inside the model class: `pickById`, `find`, `updateOne` and more. - hook: A function that runs before or after a document is written. - query-level write: One UPDATE over every match. Fast, but no hook runs. ## Overview Source: /conventions/module/overview Mirror: /llms/pages/conventions/module/overview.md Priority: P1 Headings: - Module Overview - Module File Map - Server To Client Flow - Role Boundaries - Recommended Reading Paths - Practical Rules Overview Module Overview An Akan module is one folder for one business feature. The model's shape, its wording, storage, workflows, API, client state and UI all sit side by side in it. This page is a map for choosing which file to open next. Syntax and examples live on each file's own page. An Example Module The `banner` module in `libs/shared` looks like this: **Lowercase files are logic.** They are named `<model>.<role>.ts` and hold data, storage, API and client state. **PascalCase files are UI.** Their components are reached through the model's namespace: `Card` in `Banner.Unit.tsx` is `<Banner.Unit.Card />`. **`index.ts` is generated.** Never edit it. `*.signal.spec.ts` holds test fixtures and `*.signal.test.ts` the assertions. **This page covers database modules** in `lib/<model>`. Service modules (`lib/_<service>`) and scalar modules (`lib/__scalar/<scalar>`) have their own overview pages. Words used on this page Term ## model.service.ts Source: /conventions/module/service Mirror: /llms/pages/conventions/module/service.md Priority: P1 Headings: - model.service.ts - Service Shapes - What serve() Gives You - Generated Methods - Service Extension - Injection Builder - Injection Types - Business Logic Flow - Lifecycle Hooks - Practical Rules model.service.ts `<model>.service.ts` is where one business action runs from start to finish: load the documents, change them, save, then tell whoever else needs to know. Open it when an action needs more than one document, another service, a background job, an external API, or anything that must stay on the server. Which file owns the work The work document — *.document.ts service — *.service.ts signal — *.signal.ts - Changing one document - state change: A chain method such as `story.approve()` validates, changes the document and returns `this`. - state precondition: The chain method throws when the document is in the wrong state for the change. - Running a business action ## model.signal.ts Source: /conventions/module/signal Mirror: /llms/pages/conventions/module/signal.md Priority: P1 Headings: - model.signal.ts - Extending A Library Model - Defining Internal Tasks - Defining APIs With endpoint() - The Options Object - What An Argument May Be - Generated Model APIs - Slices: Lists For Pages - Rules To Remember model.signal.ts `model.signal.ts` is the door to a module. It decides what a client can call, which lists a page can load, and what the server runs on its own. You open it when a page needs a new call or list, or the server needs a scheduled job. The logic stays in the service; handlers here only call it. Class - StoryInternal, internal(): Work the server runs by itself: computed fields, schedules, lifecycle hooks, queue jobs. - StorySlice, slice(): Lists a page loads, like `inRoot`. Each one becomes fetch methods and store state. - StoryEndpoint, endpoint(): Calls a client makes: queries, mutations, websocket messages and pubsub rooms. Words used on this page Term - guard: A class that decides if a call may run: `Public`, `Every` (any signed-in account), `Admin`. - internal argument: A value the server fills in, not the caller, such as the signed-in user from `.with(Self)`. - refName: The model's camelCase name, like `story`. Routes and fetch method names are built from it. ## model.store.ts Source: /conventions/module/store Mirror: /llms/pages/conventions/module/store.md Priority: P1 Headings: - model.store.ts - Store Class Structure - Extending Library Stores - Writable And Derived State - Reading And Writing State - Standard Model API - Generated Slice API - Usage Patterns - Rules And Common Mistakes model.store.ts `<root>` for the root slice, `<named>` for inProject. `<model>.store.ts` holds one module's client state and the actions that change it. Pages and components read state from the store and call its actions; they never coordinate `fetch` calls themselves. Most stores stay nearly empty, because a model store generates its state and CRUD actions. Write an action by hand only for one of these: A Toast Loading and success messages around a custom endpoint call. An Optimistic Update Change the client model first, send the request without waiting, then commit. A Multi-Field Write Several state keys that must change together in one write. What the store owns The work ## Model.Template.tsx Source: /conventions/module/template Mirror: /llms/pages/conventions/module/template.md Priority: P1 Headings: - model.Template.tsx - File Convention - Standard Form Template - Field Patterns - Split Components - Opening A Template - Rules At A Glance Model.Template.tsx Left as it was. model.Template.tsx `<Model>.Template.tsx` is a module's form: the fields a person fills in to create or edit one record. Most exports are whole forms, but a Template may also export a small piece of one, such as a submit button, an onboarding step or a preview block. A Template only connects the screen to the store. Anything that needs a decision lives somewhere else: The work Template — *.Template.tsx Elsewhere - Drawing the form - Field.*: Labelled controls, each bound to one field of the form draft. - submit button · step · preview: Small interaction pieces that belong to one form. - l("<model>.<field>"): Labels and help text from the module dictionary. ## Model.Unit.tsx Source: /conventions/module/unit Mirror: /llms/pages/conventions/module/unit.md Priority: P1 Headings: - Model.Unit.tsx - ModelProps And Light Models - Unit Variants - Actions Inside Units - Load.Units And Direct Rendering - Practical Rules Model.Unit.tsx A Unit file draws one record of a model: a card, a compact row, an avatar, a gallery tile, or a column helper for tables. Every list and relation that shows the model reuses these exports. Open it when a list needs a new look, or a row should show another field. A Unit only draws; everything else has a file of its own: What Unit Util Template Store page - What the Unit does itself - Light model fields: Title, status, dates: drawn as a card, a row or a tile. - usePage · l(): Translation works on the server, so labels need no client code. ## Model.Util.tsx Source: /conventions/module/util Mirror: /llms/pages/conventions/module/util.md Priority: P1 Headings: - Model.Util.tsx - File Convention - Model Wrapper Actions - Dialog And Modal Actions - Query And Route Helpers - Rules And Common Mistakes Model.Util.tsx A Util file holds a module's small client components, each doing one action: a remove button, a toolbox, a dialog trigger, a filter control or a back link. Clicks and store actions gather here, so Unit and View stay server-rendered and Page, Zone and Template keep to their own jobs. - Always a client file — `"use client";` — "use client" goes on line 1 by file role. A Util exists to handle a click, a hook or the store. - Named after its action — `Project.Util.Remove` — Name it after the verb without the model, such as Remove, Resolve or SetOrg. The namespace adds the model. - Takes ids, not models — `projectId: string` — A model prop would cross the server-client boundary as a class instance. Read the rest from the store. - Calls, never decides — `st.do.resolveReport(reportId)` — It calls a store action or a Model wrapper. Who may act and what changes is decided by the service and document. Words used on this page Term - Model.Edit, Model.Remove: Components from `akanjs/ui` that run a module's generated edit or remove flow for you. - st.do, st.use: The client store: `st.do.x()` runs an action, and `st.use.x()` reads a key and re-renders on change. - fetch.slice.<name>: Slice metadata that tells a wrapper which model and list to act on. It sends no request. ## Model.View.tsx Source: /conventions/module/view Mirror: /llms/pages/conventions/module/view.md Priority: P1 Headings: - Model.View.tsx - View vs Unit - Standard View Shape - Full Model Detail Patterns - Using View In Pages - Load.View And Store Hydration - Practical Rules Model.View.tsx Model Export Props Drawn by A View file draws one record in full: the body of a detail page or a detail section. It takes the full model as a prop and only draws it. - Takes the full model — `ticket: cnst.Ticket` — Every field is there, including long text and nested data that a list leaves out. - Only draws — `Ticket.Util.* · Ticket.Unit.*` — It may render Units, Utils, Zones and its own subcomponents. Saving and deciding happen elsewhere. - Exports General — `Ticket.View.General` — `General` is the main export. A long screen adds named sections beside it. - Drawn through a Zone — `renderView={(ticket) => …}` — A detail Zone hands the model from the server to it through `Load.View`. Words used on this page Term ## Model.Zone.tsx Source: /conventions/module/zone Mirror: /llms/pages/conventions/module/zone.md Priority: P1 Headings: - model.Zone.tsx - File Convention And Props - List Zone With Load.Units - View Zone With Load.View - Section Orchestration Zones - Live And Dashboard Zones - When To Use Zone - Practical Rules Model.Zone.tsx required model.Zone.tsx A Zone is the client part of a page section. The page fetches the data; the Zone puts it into the store and hands each record to a Unit or View that draws it. Open this file when a page gets a new list or detail section, or when a section needs a modal or live updates. One section comes together in four steps: **The page starts the fetch.** `fetch.init<Model><Suffix>()` loads a list and `fetch.view<Model>(id)` loads one record. The result goes down as `init` or `view`. **The Zone hands it to `Load.Units` or `Load.View`.** They fill the store and draw the loading and empty states. **Each record goes to a server component.** A row goes to a `Unit`, the detail to a `View`. **Actions and forms live in their own files.** A button is a `Util`, a form is a `Template`, and state and actions live in the store. Words used on this page Term - init: The `<model>Init<Suffix>` field of `fetch.init<Model><Suffix>()`: a `ClientInit`, awaited or not. ## scalar.abstract.md Source: /conventions/scalar/abstract Mirror: /llms/pages/conventions/scalar/abstract.md Priority: P1 Headings: - scalar.abstract.md - Writing The Rules - Fill In The Scaffold scalar.abstract.md Every scalar keeps one `lib/__scalar/<scalar>/<scalar>.abstract.md`: a few lines of markdown about the value. A scalar is a value that something else holds, usually a model's field, so this file answers not what the value is, but what may be assumed about it. What May Be Assumed Take `coordinate` in `libs/util`. Its constant file and its abstract say different things about the same array. What The Constant File Shows `coordinates` is an array of two floats. What Only The Abstract Says Longitude comes first, the opposite of how almost everyone says a position out loud. The Three Parts A scalar abstract has three parts, and there is no fourth: <one sentence: what this value represents, and who holds it> <something a caller would otherwise get wrong> ## scalar.constant.ts Source: /conventions/scalar/constant Mirror: /llms/pages/conventions/scalar/constant.md Priority: P1 Headings: - scalar.constant.ts - Basic Shape - Defaults And Optional Fields - Array Fields - Enum Fields - Small Helpers scalar.constant.ts A scalar constant declares the shape of a small value that other models embed, such as a price or an address. You open it when that value gains, loses or changes a field. Keep it simple enough to read without opening a service, signal or store. Most need only `via()`, `field()`, a few defaults and optional fields, and sometimes one small enum. Words used on this page Term - scalar: A small value object saved inside another model, such as a price, an address or a coordinate. - parent model: The model that embeds the scalar, such as a `Product` holding a `Price`. - via(): Turns a list of fields into a class, imported from `akanjs/constant`. - field(Type): Declares one value and its type, plus options such as a default. - enumOf(): Declares a fixed list of allowed values, imported from `akanjs/base`. One class, not five A module constant declares five classes because its model keeps records of its own. A scalar keeps none, so its file is one class plus its enums: ## scalar.dictionary.ts Source: /conventions/scalar/dictionary Mirror: /llms/pages/conventions/scalar/dictionary.md Priority: P1 Headings: - scalar.dictionary.ts - Basic Pattern - Builder Order - Language Order - Enum Name Matching - Small Custom Text scalar.dictionary.ts A scalar dictionary gives a scalar its labels in every language: the scalar's name, each field, and each enum value. Open it whenever you add a field or an enum value to the scalar's constant. Words used on this page Term - label: The name a person reads, one string per language: `t(["Amount", "금액"])`. - .desc(): A one-sentence explanation chained after a label. - language tuple: One string per language, in the order `scalarDictionary(["en", "ko"])` lists them. - key: The dotted path code reads a label by, such as `price.amount`. Smaller than a module dictionary A scalar is a value embedded in a model, so it has no list or API of its own to label. `scalarDictionary` therefore has no query, sort, slice, or endpoint stage at all. Stage model — modelDictionary ## scalar.document.ts Source: /conventions/scalar/document Mirror: /llms/pages/conventions/scalar/document.md Priority: P1 Headings: - scalar.document.ts - The Whole File - Helpers Go On The Constant - When You Use It scalar.document.ts `price.document.ts` is the server-side class of a scalar. It is one line that wraps the constant class, and it stays that way. `akan create-scalar price` writes it together with the other core files. Keep it even when the scalar needs nothing but fields and labels. Words used on this page Name - cnst.Price: The constant class that server and browser both load: fields, defaults and helpers. - by(cnst.Price): Builds a server-side class with the same fields as the constant class. - db.Price: The value's type in server code: its stored fields, without methods. The Whole File Import the constant file as `cnst` and wrap its class with `by(cnst.Price)`. The document class then has the same fields as the constant class: **Same name as the constant class.** The `price/` folder exports `Price`, which wraps `cnst.Price`. **Import the sibling file.** The path is `./price.constant` in the same folder. ## Overview Source: /conventions/scalar/overview Mirror: /llms/pages/conventions/scalar/overview.md Priority: P1 Headings: - Scalar Overview - When To Use A Scalar - Scalar Files - Small Example Overview Scalar Overview A scalar is a small, named group of fields that lives inside other models. Define it once, then embed it wherever the same fields repeat. For example, a product, an order and an invoice all need a price. Instead of writing `amount` and `currency` three times, define a `Price` scalar once and embed it in all three. Words used on this page Term - value object: A value defined only by its fields, like a price or an address, with no `id` of its own. - embed: Putting a scalar inside another model as a field, so it is saved with that model. - parent model: The model that holds the scalar, such as `Product` holding a `Price`. - database module: A model with its own table, service, endpoints and screens, under `lib/<model>/`. When To Use A Scalar Ask whether the value only exists inside another record. If it does, it is a scalar; if it needs its own list, permissions or lifecycle, it is a database module. ## Scalar.Template.tsx Source: /conventions/scalar/template Mirror: /llms/pages/conventions/scalar/template.md Priority: P1 Headings: - Scalar.Template.tsx - File Shape - Scalar Template Example - Use From Parent Form - Field Or Custom UI Scalar.Template.tsx A scalar Template is a small form piece that edits one scalar value inside a parent model's form. Write one when several models hold the same value: Product, Order and Invoice can all reuse `Price.Template`. It edits the value and nothing else. Reading the draft, saving it and submitting the form happen elsewhere: The work Scalar — Price.Template Parent — Product.Template Shell — Load.Edit - Editing the value - Field.*: One control per scalar field, labelled from the scalar's dictionary. - new cnst.Price().set(value): Builds the changed value and hands it to `onChange`. - Keeping and saving it - st.use.productForm(): Reads the parent's draft, where the price is one field. ## Scalar.Unit.tsx Source: /conventions/scalar/unit Mirror: /llms/pages/conventions/scalar/unit.md Priority: P1 Headings: - Scalar.Unit.tsx - File Shape - Scalar Unit Example - Use From Parent Unit - Small Variants Scalar.Unit.tsx A scalar Unit is a small display component for one scalar value, used inside a parent's card, row, detail page or table cell. Write one when several models should show the same value the same way: Product, Order and Invoice can all reuse `Price.Unit.Label`. It draws the value and nothing else. The parent Unit decides the layout around it, and loading happens elsewhere: The work Scalar Unit — Price.Unit Parent Unit — Product.Unit Elsewhere — page · Zone · Util - Drawing the value - price.amount · price.currency: Formats the value the same way on every screen that shows it. - l("price.amount"): Labels each field from the scalar's own dictionary. - Around the value - product.price: Picks the scalar field off the parent model and passes it down. ## service.abstract.md Source: /conventions/service/abstract Mirror: /llms/pages/conventions/service/abstract.md Priority: P1 Headings: - service.abstract.md - The Four Parts - Fill In The Scaffold - What Counts As A Rule service.abstract.md A short markdown file beside a service module. It holds the invariants — rules that must always hold — which the code obeys but cannot explain, and nothing else. One rule from the oauth module shows the difference: What the Code Says `oauth.service.ts` hands this window to `refreshSession`: a refresh token reused within 30 seconds of its rotation is rotated again, not revoked. What the Abstract Adds Why. A client that holds the same token twice is not a thief, and treating it as one signs the user out of an app that did nothing wrong. The second card is the abstract's whole job. The file sits in the module folder; the folder keeps its underscore and the file name drops it: `lib/_oauth/oauth.abstract.md`. When to touch it **Before you change the module,** read it first. **When an invariant, a workflow or public behaviour changes,** update it. **When only formatting, imports or style change,** leave it alone. ## service.dictionary.ts Source: /conventions/service/dictionary Mirror: /llms/pages/conventions/service/dictionary.md Priority: P1 Headings: - service.dictionary.ts - Naming The Endpoints - Naming Every Argument - Errors And Phrases - Reading A Key Back service.dictionary.ts `<service>.dictionary.ts` labels, in every language, what a service module shows: its endpoints, its errors and its other phrases. Open it when you add an endpoint, throw a new error, or show a new line of text. A model dictionary starts by naming fields. A service module has none, so its dictionary starts one stage later, at the endpoints, and the first line says so: `serviceDictionary`, not `modelDictionary`. Words used on this page Term - label: The name a person reads, one entry per language: `fn(["Disconnect App", "앱 연결 끊기"])`. - .desc(): A longer sentence beside a label. An AI agent picks a tool by reading it. - key: The dotted path code reads a text by, such as `oauth.consentTitle`. - language tuple: One string per language, in the order `serviceDictionary(["en", "ko"])` lists them. Three stages Stage What it holds ## Overview Source: /conventions/service/overview Mirror: /llms/pages/conventions/service/overview.md Priority: P1 Headings: - Service Module Overview - The Eight That Exist - The Two Poles - Service File Map - Ship The Empty Files - Model Module Or Service Module Overview The store is the empty scaffold. Service Module Overview Signing a token, streaming a stored file back to a browser, running an OAuth handshake to its end: none of these is a record. A folder built around a stored model would give you five files to leave empty and one to fill. A service module is that folder without the model. - Where It Lives — In `lib/_<service>`, with a leading underscore. The files inside drop it. — `libs/util/lib/_security/security.service.ts` - What It Owns — An action or a capability instead of a table. Nothing to list, edit, or keep until tomorrow. — `sign · encrypt · stream · authorize` - What It Leaves Out — No document file, no filters, no slices, no generated CRUD: there is no table behind it. — `no *.document.ts · no slice()` - How It Is Called — The same path a model module uses, minus the document layer. — `fetch → signal → service → srvkit/` Here is one call through a service module, using `_oauth` as the example: One call through a service module A page, a store, an MCP client ## service.service.ts Source: /conventions/service/service Mirror: /llms/pages/conventions/service/service.md Priority: P1 Headings: - service.service.ts - Asking For What It Needs - The Options Argument - What A Method Looks Like - What Stays Out service.service.ts The service file holds a service module's workflow: the rules its signal calls into. Open it whenever that workflow changes. Words used on this page Term - service module: A module under `lib/_<name>/` that owns a workflow and no table. - model service: `lib/<model>/<model>.service.ts`, built on a table with `serve(db.<model>, …)`. - injection callback: The function passed to `serve()` that returns the service's dependencies. - federation, batch: Process roles: federation serves requests, batch runs background work and serves none. Both kinds of service start with `serve()`. What differs is the first argument: Model Service Names its table and inherits a table's worth of generated methods. Service Module ## service.signal.ts Source: /conventions/service/signal Mirror: /llms/pages/conventions/service/signal.md Priority: P1 Headings: - service.signal.ts - Every Endpoint Names Its Guards - Routes A Protocol Fixes - Work The Runtime Starts - Realtime Without A Model service.signal.ts service.signal.ts is the door in front of a service module. The signal decides who may call and with which arguments, and the service decides what happens. You open it to add an endpoint, a scheduled job or a realtime room. Words used on this page Term - service module: A module in `lib/_<name>` with no table of its own, such as `_security` or `_oauth`. - guard: A class that decides whether a call may run, such as `Public`, `Every` or `Admin`. - internal argument: A value the server fills in rather than the caller, taken with `.with(...)`. - MCP: The protocol AI agents use to call your endpoints. Akan serves it at `/mcp`. - serverMode: A server's role: `federation` answers requests, `batch` runs background work, `all` does both. Two classes, not three A model module's signal declares three classes. A service module's declares two, because it has no table to put a slice in front of: Class ## service.store.ts Source: /conventions/service/store Mirror: /llms/pages/conventions/service/store.md Priority: P1 Headings: - service.store.ts - State The Screen Shares - An Action Returns Nothing - Calling The Endpoint service.store.ts `<service>.store.ts` holds the client state and actions of a service module. Most service modules never fill it, so it is the one file in the folder you will probably not need. Fill it only when several components share a value, or a screen needs an action that calls the module's endpoint. Words used on this page Term - state: A value the store holds. A component that reads a key re-renders when that key changes. - action: A method of the store class. Components call it as `st.do.<action>()`. - st.use, st.do: How a client component reads a key (`st.use.<key>()`) and runs an action (`st.do.<action>()`). - model store: A store bound to a model's signal, `store(sig.<model>, …)`. Lists, forms and CRUD are generated. - service store: A store bound to a plain name, `store("<name>" as const, …)`. Nothing is generated from a model. How many service modules have one Four of the eight service modules in this workspace have a store, and two of those four are still the empty scaffold: ## Service.Util.tsx Source: /conventions/service/util Mirror: /llms/pages/conventions/service/util.md Priority: P1 Headings: - Service.Util.tsx - The Shape, If You Write One - Two Component Roles Service.Util.tsx `Service.Util.tsx` holds a small client control, such as a button, that runs one of a service module's endpoints. Not one of the eight service modules in this workspace has this file, and that is by design, not a gap waiting to be filled. This page explains why the file is rare, where the control goes instead, and what it takes for yours to be the exception. Words used on this page Term - service module: A `lib/_<name>` folder with no model: a service, a signal, a dictionary and often a store. - model module: A `lib/<model>` folder built around one stored model. Its Util acts on that model's records. - Util: The file role for a small control, such as a button, that runs an endpoint. - client component: A file that starts with "use client". It arrives as HTML, then again as JS the browser re-runs. - ui/: The app or lib folder for components that render JSX and are not bound to one model. Why it is rare - Model Module: Verb And Noun — A Util is named for the endpoint verb minus the noun: Serve, Refund, Complete. The button runs the module's own endpoint on the module's own record, so it belongs there. ## Service.Zone.tsx Source: /conventions/service/zone Mirror: /llms/pages/conventions/service/zone.md Priority: P1 Headings: - Service.Zone.tsx - Hold No Markup - Seed It From The Route - Or Just Write The Page Service.Zone.tsx A Zone is a section a page drops in whole, such as a search console, an upload panel or a device dashboard. Most service modules never need one: of the eight in this workspace, none has a Zone, and none has a Util either. The reason is that a service module has no records to list. Its UI is usually a screen of its own or one button inside another screen, not a section. Words used on this page Term - service module: A `lib/_<name>` folder with no model: a service, a signal, a dictionary and often a store. - Zone: The file role for a section a page drops in whole. It is always a client component. - server component: A file without "use client". It runs on the server and arrives as HTML. - client component: A file that starts with "use client". It arrives as HTML, then again as JS the browser re-runs. - slot: A `ReactNode` prop such as `header`. The page renders its content on the server and passes it in. Where each kind of UI goes The UI is ## Format & Lint Source: /conventions/workspace/lint Mirror: /llms/pages/conventions/workspace/lint.md Priority: P1 Headings: - Lint Is Not About Style - Six You Will Meet First - Every Rule That Breaks The Build - Suppressing A Rule - Commands And Configuration Format & Lint Why: Fix: Rule Scope: Level: module files, `page/**`, barrels `apps/**` `libs/**`, except tests, `*.constant.ts`, `common/**`, `env/**` A thrown `Error`. Throw `new Err("<module>.error.<key>")` and register the key. An `Error` built anywhere else, to reject, return or store, is a warning. `logger.log()` reads like its own level but emits at `info`. Write `.info()`. `ui/` `webkit/` `common/` `page/`, `*.constant.ts` `*.store.ts`, module components A `//!` or `/*!` comment survives minification and ships. Use `// FIXME:` instead. ## Structure Source: /conventions/workspace/structure Mirror: /llms/pages/conventions/workspace/structure.md Priority: P1 Headings: - Workspace Anatomy - Workspace Commands Structure Workspace Anatomy An Akan workspace is one Bun-first monorepo. The top-level folder a piece of code sits in says what it is: a product you run, a library apps share, or a package. A workspace root looks like this: Which folder does my code go in? Code apps/ libs/ pkgs/ - Runs as one product - customer site · admin portal · brand app: A product you run and deploy on its own. - business code one app uses: Its pages, modules and UI stay inside that app. ## Using Insight Source: /docs/tutorials/insight Mirror: /llms/pages/docs/tutorials/insight.md Priority: P1 Headings: - Stats of Query - Create Query Maker - Accelerate with Insight Using Insight Stats of Query When multiple orders come in at once, you can make ice cream at once. You need to extract the insight of the current orders' ice cream amount, topping information, etc. Create Query Maker Before extracting insights, we need to define what data we want to query. A Query Maker allows users to filter data dynamically - like a barista checking orders by status to see which drinks to make next. Let's enhance our Slice to support flexible queries with search parameters. First, let's update the Slice to accept status filters. The .search() method defines query parameters that users can set from the frontend: Let's understand the key components of this Slice definition: Defines a searchable parameter that can be set from the frontend. Here, "statuses" accepts an array of IcecreamOrderStatus values to filter orders. Pre-defined slices with fixed status filters. inWaiting shows active and processing orders, while inPickup shows orders ready for customer pickup. Add dictionary entries for the slice and its search parameter to enable localization: Now let's create a UI component that allows users to select which statuses to filter by. This Query Maker component uses the auto-generated store hooks: Key features of the Query Maker component: ## UX with Pages Source: /docs/tutorials/page Mirror: /llms/pages/docs/tutorials/page.md Priority: P1 Headings: - Kiosk for Customers - Add Schema - Kiosk Landing Page - Order Form Page UX with Pages Kiosk for Customers The number of customers at the store has increased, and the staff is having trouble processing orders. Let's create a kiosk for customers to order ice cream. A kiosk is a simple interface that allows customers to order ice cream. Add Schema There is some missing information in the current schema to allow customers to order directly from the kiosk. We need to add serve type and contact information. Let's expand the schema to add these features. Let's understand the new schema additions: An enum defining how the customer wants their order - for here, take out, or delivery Customer's phone number for pickup notifications. isPhoneNumber accepts a Korean mobile number in the form 010-0000-0000, the same shape as the field placeholder. field.hidden stores it and lets server code read it, but every response sends null, because anyone can read an order Updated to include serveType for display in order lists and dashboards Next, we need to add dictionary entries for the new fields and enum values: Next, let's add serveType and phone selection to the order form template. Finally, let's display serveType on the order's Unit card to clearly show whether the customer's order is for here or take out, etc. ## Relate Data Source: /docs/tutorials/relation Mirror: /llms/pages/docs/tutorials/relation.md Priority: P1 Headings: - Delivery Feature - Create Delivery Module - Define Relationship - Summary Relate Data Delivery Feature The ice cream shop is so successful that delivery orders are flooding in! Now we need to manage delivery orders. A delivery driver can deliver multiple orders at once, which means we need to create a relationship between deliveries and orders. This is a classic one-to-many relationship - one Delivery contains many IcecreamOrders. In this tutorial, you'll learn how to: Define relationships between models with Light model references Trigger side effects when related data is created Build UI components for selecting and displaying related data Create Delivery Module First, let's create the Delivery module using the CLI. This module will connect multiple ice cream orders into a single delivery batch. Define Relationship Now let's define the Delivery model with a relationship to IcecreamOrder. The key is using LightIcecreamOrder as the field type - the delivery stores each order's id, and reading a delivery hands the orders back as LightIcecreamOrder. Let's understand the key relationship pattern: ## Using Scalar Source: /docs/tutorials/scalar Mirror: /llms/pages/docs/tutorials/scalar.md Priority: P1 Headings: - Use Setting Module - Create Scalar - Create Inventory - Business Logic - Connect Service - Connect Signal - Interact on UI Using Scalar Use Setting Module Now the ice cream shop can receive and process orders, and with many customers coming in, it's easy to run out of stock. Let's find out how to handle this situation. You need to add a service that checks the remaining ice cream and toppings every morning, sets the inventory status in the system, and automatically disables orders when the inventory is depleted. Create Scalar First, let's create a Scalar to represent individual stock items. Think of a Scalar as a reusable data building block - like Lego pieces that can be combined into larger structures. Unlike a full Model that has its own database collection, a Scalar is embedded within other models. In our case, the Stock scalar will be used inside the Inventory model. Use the CLI to generate the scalar structure: Now define the Stock scalar with the item type and quantity tracking: Let's understand the Stock scalar structure: An enum combining yogurt ice cream with all available toppings. This allows tracking inventory for all product types in one system. Track both the starting amount and current remaining quantity. This helps calculate usage and identify when restocking is needed. Add dictionary entries for the scalar. Notice how we reuse the topping translations from the icecreamOrder dictionary: ## Interact in Service Source: /docs/tutorials/service Mirror: /llms/pages/docs/tutorials/service.md Priority: P1 Headings: - Interact in Service - Declare Adapter - Use External API - Query in Document - Use Interval Interact in Service When an order comes in, you need to inform the staff so that they can make ice cream, and when the ice cream is made, you need to notify the customer. Also, if the ice cream melts, you need to notify the customer again if they don't pick it up for a long time. To achieve this, you need to add a service that sends periodic warnings if a served order is not finished, and a service that sends an alert message to the customer to remind them to pick up the order. Declare Adapter First, let's start by connecting an external API or module like an alert. You can connect an api that sends messages or emails, but in this tutorial, we'll create an api that simply prints to the console and connect it. Modules like service, signal, document should not be directly connected to external systems, but rather created as adapters that are injected. First, let's create an adapter in the /srvkit folder with adapt(). An adapter gets its own logger as this.logger. Why use the adapter pattern? By injecting external dependencies as adapters rather than directly importing them in services, you gain several benefits: (1) Testability - you can easily mock or replace the adapter in tests without modifying the service code (2) Flexibility - you can swap implementations (e.g., switch from console logging to email notifications) without changing the service logic (3) Separation of Concerns - the service focuses on business logic while adapters handle external interactions (4) Reusability - the same adapter can be injected and shared across multiple services Use External API ## Displaying with Slice Source: /docs/tutorials/slice Mirror: /llms/pages/docs/tutorials/slice.md Priority: P1 Headings: - Displaying with Slice - Dashboard Slice - Connect to Zone - Zone with Slice - Slice Component Rules Displaying with Slice We want to show customers a real-time dashboard of ice cream order processing. Completed orders should be displayed prominently, and the list of ongoing orders should also be visible. By using Slice, you can present the same ice cream order data in real time from different perspectives for customers, staff, and administrators. Dashboard Slice First, let's declare a slice for the real-time dashboard to show to customers. You can display the waiting orders and the orders being picked up by querying them separately. inWaiting slice is a slice that queries the waiting orders and inPickup slice is a slice that queries the orders being picked up. Each init() names its own guards, and the dashboard is public. When the slice is declared, the state and actions of the store are automatically created. Just like labeling different shelves in an ice cream shop - "Ready for pickup", "Being made" - we need to give proper names to our slices in the dictionary. This ensures the UI displays meaningful labels and the slice functions are properly documented. Connect to Zone Now let's build the actual dashboard page that customers will see. Think of this like the large display screens in a cafe that show "Now Serving: Order #42" - it needs to show different views of the same order data simultaneously. We'll use Zone components to connect our slices to the UI and display them in real-time. Don't forget to add the translation labels for the dashboard sections: Let's break down how this dashboard page works: Notice there is no await. Both slice queries leave the moment they are called, and destructuring the result gives one promise per field instead of a resolved object. Each promise goes straight to the Zone that renders it, so the pickup board and the waiting board arrive independently — a slow query on one never delays the other, and the page heading is on the wire before either lands. Zone components connect slice data to UI rendering. init is the window the route already resolved, and slice names the store slice the Zone hydrates and that its controls write back to. ## Modifying Status Source: /docs/tutorials/util Mirror: /llms/pages/docs/tutorials/util.md Priority: P1 Headings: - Modifying Status - Implement Document Business Logic - Implement Service Layer - Create Signal Endpoints - Create Frontend Store Actions - Create Utility Components - Apply To Unit & View Components - Test Status Management - What's Next? Modifying Status Now that customers can create and view ice cream orders, let's add functionality for shop staff to manage the order lifecycle. In a real ice cream shop, orders need to progress through different stages: from "active" (newly placed) to "processing" (being prepared) to "served" (completed) or "canceled" if needed. Think of status modification like the workflow in a real ice cream shop. When a customer places an order, it starts as "active" - like a ticket on the order board. Then staff begins preparation ("processing"), and finally serves it to the customer ("served"). This tutorial shows you how to implement this natural workflow with proper validation and user-friendly controls. Before implementing the functionality, let's understand the business logic behind ice cream order status transitions: When a customer places an order, it starts as "active". Staff can begin processing it by clicking "Process". While an order is being prepared, it's in "processing" status. Once ready, staff can mark it as "served". Once the customer has picked up the order, staff closes it as "finished". Only active orders can be canceled. Once processing begins, cancellation is no longer allowed. Business Rules Only active orders can be processed or canceled Only processing orders can be served Only served orders can be finished ## Show Details Source: /docs/tutorials/view Mirror: /llms/pages/docs/tutorials/view.md Priority: P1 Headings: - Show Details - Add View Modal - Add View Button to Unit Cards - Design Detail View - Test Your Implementation - What's Next? Show Details A Unit card renders the light model: just enough to tell orders apart. A detailed view is what opens when a customer taps one — the exact size, every topping, the order time, and whether it is ready. In Akan.js, three components work together to build a detailed view: A clickable wrapper that triggers the view modal when clicked. Think of it as the "View Details" button functionality. A modal popup that displays when customers want to see details. It handles opening, closing, and data loading automatically. The actual content inside the modal, showing all the order information in an organized layout. This separation allows each component to have a single responsibility: the wrapper handles clicking, the modal handles the popup behavior, and the view handles the display formatting. Add View Modal Now let's add a view modal to our ice cream order page. This creates a popup window where customers can see all their order details in an organized format. The modal functions like a detailed receipt that appears when customers want to review their order information. This code renders each order as a card with its own view modal. Let's examine what each part does: Load.Units Component Renders every order as a Unit card in a list, each showing basic order information ## Agent Source: /references/ui/agent Mirror: /llms/pages/references/ui/agent.md Priority: P1 Headings: - Agent UI - Chat - Development Dock Agent Agent UI An assistant that presses the buttons already on the screen, under the same guards, while the person watches. It is not a separate API for robots. The `Agent` namespace is that UI. One `<Agent.Chat />` in a layout is the whole integration; the other members narrow it or show what it sees. **The relay endpoint never runs a tool.** Every call runs in the user's own browser session, through the app's guards and the approval card. So a tool exists only where a component declared one, and what the screen does not offer the user, the agent cannot do either. Words used on this page Term - tool: One action a component publishes with `st.tool`, usually the handler its button calls. - surface: Everything the agent can do and read on the current screen: the mounted tools and keys. - session: One conversation with its loop and options. `Agent.Chat` and `Agent.Zone` each build one. - transcript: The conversation so far. It is sent to the model again on every turn. - built-ins: Runtime tools every screen gets: `navigate`, `goBack`, `readScreen`, `readState`, `highlight`. ## Core Source: /references/ui/core Mirror: /llms/pages/references/ui/core.md Priority: P1 Headings: - Core UI - Link - Image - Layout - Load - Model Core Core UI The five `akanjs/ui` components almost every screen uses. Each section below lists the props and ends with one working example. Component - Link: Moves between internal routes. Every internal link is a `Link`. - Image: Draws an uploaded file or a URL, resized by Akan's image optimizer. - Layout: The page frame: content containers, top and bottom chrome, a header and drawers. - Load: Turns a fetch result into a list, a detail, a form, or any awaited value. - Model: Create, edit, view and remove shells wired to a model's generated store. Words used on this page Term - slice: A named list query of a model, such as `productInShop`. Components take it as `fetch.slice.<name>`. ## Customization Source: /references/ui/customize Mirror: /llms/pages/references/ui/customize.md Priority: P1 Headings: - Customization - How It Works - Scoping - Overridable Slots - Generic Components - Compound Components - Recipe Slots Customization Any `akanjs/ui` component can be re-skinned per route without forking it. Write a replacement in your app's `ui/` and bind it to a slot in a `page/**/_overrides.tsx` manifest. Every `<Modal>`, `<Button>` or `<Table>` under that folder then renders yours, with no call site changed. Manifests cascade down the route tree like layouts, and the closest one wins. Words used on this page Term - slot: A named place where a framework component can be swapped, such as `Modal` or `InputPassword`. - _overrides.tsx: The manifest in a `page/` folder that binds slots for every route under that folder. - drop-in: Your replacement. It takes the same props as the original, so no call site changes. - headless parts: Parts with behavior but no look of their own, such as `Dialog.Modal`. - recipe: A function that returns the className for a variant, such as `buttonRecipe({ variant: "primary" })`. Two kinds of slot One manifest takes both kinds. Swap a recipe when only the look is wrong, and a component when the markup is. ## Display Source: /references/ui/display Mirror: /llms/pages/references/ui/display.md Priority: P1 Headings: - Display UI - Data - RecentTime - Loading - Badge - Empty - Table - Pagination Display Display UI Components that show data: model listings, timestamps, loading and empty states, status pills, tables and pagers. All of them come from `akanjs/ui`. Component - Data: The admin listing screen and its parts, bound to one model's slice. - RecentTime: A time shown as "3 minutes ago", with the exact date in a tooltip. - Loading: Six waiting indicators: spinner, skeleton, progress bar and three placeholders. - Badge: A status pill: a `<span>` styled by `badgeRecipe`. - Empty: The "no data" placeholder, with room for a follow-up action below it. - Table: Rows you already hold, drawn as a table with an optional pager. - Pagination: A page-number control driven entirely by props. Words used on this page ## Forms Source: /references/ui/forms Mirror: /llms/pages/references/ui/forms.md Priority: P1 Headings: - Forms UI Forms Forms UI The form controls in `akanjs/ui`. A model form keeps its state in the store's `<model>Form`, a generated setter writes one field, and a control only shows the current value and hands back the next one. Words used on this page Term - <model>Form: The store's draft of the record being edited, such as `icecreamOrderForm`. - st.do.set<Field>On<Model>: The generated form setter. It writes one field of that draft. - controlled: Shows the `value` you pass and hands the next one to `onChange`. Only `Switch` can also run alone. - agent tool: An action the in-page agent may call. A form setter passed by reference becomes one. - override slot: A name in `_overrides.tsx` that swaps a component for one route subtree. Pick a control Work down the groups: `Field.*` for a model field, a bare control when there is no label row, and `Button` for the action at the end. ## Overlays Source: /references/ui/overlays Mirror: /llms/pages/references/ui/overlays.md Priority: P1 Headings: - Overlays UI Overlays Overlays UI The overlay components in `akanjs/ui`: modal windows, confirmations, bottom sheets, menus, hints and a copy action. Start with `Modal`, and compose the headless `Dialog` only when you need your own layout. Words used on this page Term - portal: Drawing an element elsewhere in the DOM, here at the end of `document.body`, so no parent clips it. - trigger: The element the user clicks to open the overlay, passed as `trigger` or as `children`. - controlled: You pass `open` and set it back in `onCancel`. Left out, the component keeps its own open state. - override slot: A name in `_overrides.tsx` that swaps a component for one route subtree. - scrim: A see-through layer behind a popover that catches the click outside it. Pick a component Component ## Overview Source: /references/ui/overview Mirror: /llms/pages/references/ui/overview.md Priority: P1 Headings: - akanjs/ui - Page Map - Every Export Overview Core Display Forms Overlays System Agent Customization Only here akanjs/ui `akanjs/ui` is the framework's shared UI package: links, data loading, model CRUD shells, form controls, display helpers, overlays, the in-page agent and the app shell. Every name in this reference imports from that one path. By Layer ## System Source: /references/ui/system Mirror: /llms/pages/references/ui/system.md Priority: P1 Headings: - System UI System System UI The parts around your screens rather than feature widgets: the app shell, theme and language switches, an API explorer, tabs, and animation. They go in root layouts, admin pages, signal dashboards, tabbed detail views, and animated UI, and all come from `akanjs/ui`. Words used on this page Term - app shell: The frame every page renders inside, holding the theme, fonts, locale, toasts and socket. - Suspense: A React boundary that shows a fallback until the content inside it is ready. - serialized signal: Every endpoint with its arguments, guards and return model, shipped as `fetch.serializedSignal`. - agent tool: An action a control publishes so the in-page agent can do what the user's click does. Pick a component Component Auto ## Console Source: /cheatsheet/dev/console Mirror: /llms/pages/cheatsheet/dev/console.md Priority: P2 Headings: - Server Console - Local Console - Multi-line Input - Container Console - Console Process - Globals And Commands - Safety Console Server Console The server console is a JavaScript prompt inside your app's server. Use it to inspect services and run small operator commands. Command - akan console myapp: Local development: boots the app from its source in the workspace. - AKAN_CONSOLE=1 bun console.js: Docker or Kubernetes: runs the `console.js` that `akan build` puts next to `main.js`. **Never create console files inside a running container or pod.** The image already ships `console.js`. Local Console Open it to inspect a service, call a method, or try a query without writing a script file. Run it from the workspace root with the app's name: **The prompt reads `akan:myapp>`.** Type `.help` to list the commands and input rules. **Work you will repeat belongs in a script.** See Scripts. Multi-line Input ## Schema Docs Source: /cheatsheet/dev/constants Mirror: /llms/pages/cheatsheet/dev/constants.md Priority: P2 Headings: - Constant Schema Docs - Generated Schema - Printable Definition Schema Docs Constant Schema Docs You do not have to write a data model spec by hand. `Constant.Doc` reads every model registered in `ConstantRegistry` and draws field tables and a relation diagram from it. Words used on this page Term - refName: A model's name in code, such as `user` or `bizContract`. You pick models by it. - variant: One of the five classes a model declares: Input, Object, Light, Full and Insight. - scalar: A value object stored inside another model, declared under `lib/__scalar/`. - enum: A fixed list of allowed values, declared with `enumOf(...)`. The parts Component - Constant.Doc.Zone: An explorer for the screen, with search, a table or diagram view and a tab per variant. ## Docker Source: /cheatsheet/dev/docker Mirror: /llms/pages/cheatsheet/dev/docker.md Priority: P2 Headings: - Docker - Minimal Compose - Container Env - Scale With AKAN_REPLICA - Several Containers On One Host - Trim The Web Surface - Customize The Image - Open Console - Tips Docker Say you have a built app and a small machine at the edge of a factory floor. It has to come back after a power cut with its data intact, and you need to see why it fell over. For a small edge server, start with one Akan app container. Plan around these image defaults: Image default What it means for you - PORT=8282: The app listens on 8282, so publish `8282:8282`. - /workspace/sqlite: The sqlite files land here, so mount a volume on it to survive restarts. - AKAN_LOG_TO_FILE=0: File logging is off, so collect stdout or set it to 1 and mount a log volume. - ca-certificates, tzdata: The only packages installed, so declare ffmpeg or Chromium in `docker.preRuns`. - console.js: It ships next to `main.js`, so you open an operator console with `docker exec`. **Why file logging is off:** a container's writable layer is thrown away with the container, so the files would only fill the disk. stdout is the collection path. Minimal Compose ## Documentation Source: /cheatsheet/dev/docs Mirror: /llms/pages/cheatsheet/dev/docs.md Priority: P2 Headings: - API Documentation - Render A Zone - Try An Endpoint - Auth And Guards - Tips Documentation required No arguments. Returns `"ping"`. Takes a path parameter `id` and returns `pingParam: <id>`. Takes a query-string `id` and returns `pingQuery: <id>`. Takes a body field `data` and returns `pingBody: <data>`. Press Listen, then Send. The reply `wsPing: <data>` appears in the stream. A room to try Subscribe and Unsubscribe on. API Documentation Akan turns your app's `fetch` into an API explorer: every endpoint of a signal with its arguments, guards and return type. It is not just a list, because you can call each endpoint from the same screen. Words used on this page Term ## Kubernetes Source: /cheatsheet/dev/k8s Mirror: /llms/pages/cheatsheet/dev/k8s.md Priority: P2 Headings: - Kubernetes - Architecture - Values - Scale - Open Console - Tips Kubernetes Every Akan app deploys with the same Helm chart, `infra/app`. It creates four resources in the namespace `<appName>-<branch>`: Resource Name What it does - app-deployment: Runs the app image in exactly one pod. — Deployment - app-svc: Exposes the app on port 8282 inside the cluster. — Service - app-ingress: Connects your domains to the Service and gets their TLS certificate. — Ingress - sqlite-data: Keeps the sqlite data in `/workspace/sqlite` across pod restarts. — PersistentVolumeClaim The namespace picks the branch You never write the branch as a value. The chart reads it from the release namespace: You deploy into `<appName>-<branch>`, for example `myapp-main`. ## Build Pipeline Source: /cheatsheet/dev/pipeline Mirror: /llms/pages/cheatsheet/dev/pipeline.md Priority: P2 Headings: - Build Pipeline - Add A Stage To An App - Run Steps Around Every App - Give A Step A Secret - Check Before You Push - Pitfalls Build Pipeline Akan Cloud builds and deploys each app as `build`, `docker`, then `deploy`. Add your own stages around them in `akan.config.ts`, and check the result with `akan pipeline dry-run` before you push. Words used on this page Term - stage: One named step of a build, such as a test run, with one or more shell commands. - build, docker, deploy: The built-in actions Akan Cloud runs for an app; you place them with `{ use }`. - plan: What one build runs, made from your config; `akan pipeline` shows it locally. Two files - App — apps/<app>/akan.config.ts — That app's stages in order, its three actions included. - Workspace — akan.config.ts — Stages before and after every app, and the steps that close a build. Steps Add a stage to an app. ## PWA Source: /cheatsheet/dev/pwa Mirror: /llms/pages/cheatsheet/dev/pwa.md Priority: P2 Headings: - PWA - When To Use PWA - Static Manifest File - Layout Manifest Object - Required Assets - Tips PWA A PWA (Progressive Web App) runs in the browser but can be installed and launched like an app. The browser adds the icon, the app window without a toolbar, and the install prompt. When it helps. Users open the same web app again and again, and a home-screen or desktop launcher saves them time. Typical apps. Admin tools, field-work apps, internal dashboards, lightweight commerce apps and content apps. Where it starts. A web app manifest that tells the browser the app's name, icon, start URL, display mode and colors. Add It In Three Steps Put the icons in `apps/<app>/public/`. That folder is served from the site root, so `public/icon-192x192.png` loads as `/icon-192x192.png`. Declare the manifest in one of two ways: a static `manifest.json` linked from `.head()`, or `rootLayout().manifest({...})`. Deploy, check that every URL in the manifest loads, then test installation. ## Script Source: /cheatsheet/dev/script Mirror: /llms/pages/cheatsheet/dev/script.md Priority: P2 Headings: - Scripts - Create And Run - Server Lifecycle - Use Services - Lookup Helpers - Change Data Safely Script Scripts A script is a TypeScript file that boots your app's server, does one job, and exits. Reach for it when the job should live in a file rather than at a prompt: Command Form Good for - `akan script` — A file in `script/` you can review and rerun — Seed data, migrations, checks, small maintenance fixes - `akan console` — A prompt that is gone when you close it — Inspecting a service, trying a query, one small operator command **Same wiring as the app.** A script reuses the services, signals and adaptors the app already wires together. **No traffic, no schedules.** It opens no port and runs none of the app's init, interval, cron or queue jobs. **Small and disposable.** Keep one job per script, and delete it once the job is done. - Server Console — Inspect services and try queries at a prompt. ## Testing Source: /cheatsheet/dev/test Mirror: /llms/pages/cheatsheet/dev/test.md Priority: P2 Headings: - Testing - Spec File: Building Fixtures - Test File: Writing Assertions - What To Test - Command - Tips Testing In an Akan app, start testing from signals. A signal test checks the real business flow through the generated `fetch` before you spend time on UI details. Words used on this page Term - signal test: A test that calls your endpoints through the generated `fetch`, against a real test server. - fixture: A reusable function that prepares what a test needs, such as a record or a signed-in user. - agent: A test user bundled with a `fetch` that is already signed in as that user. Always two files A signal suite is always two files, and the split is not a matter of taste: Fixtures Reusable fixtures built on `sampleOf(cnst.XInput)`, each with a declared return type and no assertions. Other modules import from it. Assertions ## Authorization Source: /cheatsheet/general/auth Mirror: /llms/pages/cheatsheet/general/auth.md Priority: P2 Headings: - Authorization - The Guards That Ship - Declare The Scope - Resource Guards Fail Closed - The Acting User Comes From The Server - Guards Are Also The Agent Decision Authorization You ship the order list for a shop with several branches, and every row looks right because the branch id comes from the URL. Then a customer edits the URL, and the same endpoint hands them somebody else's orders. Authorization answers two questions in front of every endpoint: who is calling, and may they do this? Three steps answer them, the same over HTTP, a websocket or the MCP endpoint: **Middleware reads the caller.** `AccountMiddleware` from `libs/shared` verifies the token and leaves the result on the call as the account. **Guards decide.** Each guard in the `guards` array answers `canPass(context)` in declaration order, and the first refusal ends the call. **Internal arguments hand the handler its values.** `.with(Self)` and its kind fill in values the server resolved, never ones the client typed. Words used on this page Term - account: What the middleware leaves on the call. A guest's account holds neither `self` nor `me`. - self, me: The two identities an account can carry: `self` is the user, `me` is the admin. - scope: What a guard needs to answer: the caller alone (`account`) or the call's arguments (`resource`). - agent: An AI model calling through the MCP endpoint or on an OAuth token, instead of a person. ## DataList & Enum Source: /cheatsheet/general/datalist Mirror: /llms/pages/cheatsheet/general/datalist.md Priority: P2 Headings: - DataList & Enum - Enum - DataList - Which One To Use - Tips DataList & Enum Enum and DataList are two small helpers you will meet all over Akan code. Enum is for a fixed set of values; DataList is for a list of items that each have an id. A fixed set of values Status, role, type, category: a value that is always one of a few known choices. A list keyed by id Users, files, posts, selected rows: records you find and replace by id. Both are imported from `akanjs/base`. Enum Use an Enum when a value must be one of a few known choices. Declared once, it keeps forms, APIs and labels in agreement. 1. Declare It In The Constant File Declare the class above the model classes, then use it as a field type: **Always add `as const`.** Without it, `PostStatus["value"]` widens to `string` and a typo compiles. ## Edge Computing Source: /cheatsheet/general/edge Mirror: /llms/pages/cheatsheet/general/edge.md Priority: P2 Headings: - Edge Computing - Call Another Server - Send Commands - Errors Come Back - Listen To Status - Wrap A Remote Node - Very Fast Data - Run The Edge Site - Tips Edge Computing In Akan, edge computing means one Akan server calls another with the same generated `fetch` your app already uses. Add one option, `{ origin }`, and the call goes to the other server. Part - Cloud server: Decides what should happen and sends commands to the edge. - Edge server: Does the work close to the device or user, and reports status back. - fetch + { origin }: Connects both sides with typed signal calls; only `{ origin }` differs from a local call. — Example: `await fetch.startJob(jobId, { origin: edgeOrigin });` Call Another Server Every generated `fetch` call takes an options object as its last argument. Put `{ origin }` there and the call goes to that server instead of your own. **The origin ends in the API prefix.** fetch appends the endpoint path to it as-is, as in `https://edge-01.example.com/api`. **Read the prefix, never write it.** It is configurable, so build the origin with `getApiPrefix()` from `akanjs/base` instead of an `/api` literal. **The caller needs the endpoint too.** A `fetch` holds only the endpoints its own app and libs declare, so put the ones the edge serves in a lib both apps use, or run one app on both sides. A health check that pings one edge server: ## File Management Source: /cheatsheet/general/file Mirror: /llms/pages/cheatsheet/general/file.md Priority: P2 Headings: - What You Build - Minimal File Model - Upload Endpoint - File Service - Use In UI - Auto-attach To A Model Field - Remove The File With Its Owner - Grow Later - Tips File Management What You Build A file feature splits one upload in two. The bytes go to storage, and the database keeps a File record that says where they are. Where - file.constant.ts, file.document.ts: **File model.** Stores the File record with its name, url, size, status and progress. - file.signal.ts: **Upload endpoint.** Receives `Upload` files and hands them to the service. - file.service.ts: **File service.** Creates the record, streams the bytes to storage, and saves the URL. - StorageAdaptorRole: **Storage adaptor.** Where the bytes live; the default `BlobStorage` writes to local disk. - file.store.ts, File.Util.tsx: **Store and UI.** Upload from a file input and show the result once it is `active`. - localFile.getBlob: **Serve endpoint.** Ships in `@libs/util` and streams a local file back during development. Every File starts as `uploading` and becomes `active` when storage returns its URL. The sections below build the pieces in this order. **Already have `libs/shared`?** Its File module (`libs/shared/lib/file`) is the full version of this recipe, with image size, blur preview, dedupe by origin, and the `Field.Img` / `Field.File` controls. ## OAuth For Agents Source: /cheatsheet/general/mcp-auth Mirror: /llms/pages/cheatsheet/general/mcp-auth.md Priority: P2 Headings: - The Agent Has No Cookie - What The App Serves - What The Token Is - How A Client Becomes Known - Configure It Per App - Revocation Is Whole-Grant - A Person May, A Model May Not OAuth For Agents The Agent Has No Cookie You pointed Claude Code at your app's `/mcp`, and every call comes back 401. Your browser is signed in with a session cookie; a CLI agent has neither a browser nor that cookie, and `/mcp` deletes the `cookie` header anyway. So the agent needs a token, and no sign-in form hands one out. An app that uses `libs/shared` already serves an OAuth 2.1 server that issues one, in the same process as `/mcp`. One deployment plays two roles: - Resource Server — /mcp — Spends tokens. A call without one gets a 401 that tells the client where to sign in. - Authorization Server — /oauth/* — Mints tokens. It is your own app, in the same process, and it names itself as the issuer. Words used on this page Term - MCP client: The agent program that calls `/mcp`, such as Claude Code, claude.ai or Cursor. - issuer (iss): The authorization server's public origin. Clients compare it byte for byte. - aud: The token claim naming the resource it was issued for; here, the `/mcp` URL. - grant: One client's permission to act as one account: a refresh lineage and every token minted from it. ## Schema Design Source: /cheatsheet/general/schema Mirror: /llms/pages/cheatsheet/general/schema.md Priority: P2 Headings: - Schema Design - Start From The Screen - Relationship Size - Reference Or Copy - The Five Model Classes - Design Checklist Schema Design In Akan, `<model>.constant.ts` describes the shape of your data. The easiest way to design it is to start from the page or API that reads the data. One simple rule settles most cases: Keep It Together Small data that is read together stays inside one document. Split It Out Data that keeps growing moves to a model of its own. Words used on this page Term - document: One stored record of a model, such as one post. - relation: A field typed as another model, which stores only the id and is loaded by the server. - scalar: A value object declared under `lib/__scalar/` and stored inside the document. ## Text Search Source: /cheatsheet/general/search Mirror: /llms/pages/cheatsheet/general/search.md Priority: P2 Headings: - Text Search - 1. Mark The Fields - 2. Write The Filter - 3. Tune The Match - Publishing To Clients - Operating It - Gotchas Text Search Akan has full-text search built in. There is no search server to run and no index to keep in sync by hand. It takes three steps: **Mark the fields.** Give each searchable field a `text` role in `constant.ts`. **Write the filter.** Call `q.search(text)` from a filter in `document.ts`. **Call it.** Use the generated `listBySearch`, sorted by `"relevance"`. Letting clients search as well is a separate decision, covered in Publishing To Clients. Search works in every database mode. For the same text, SQLite and Postgres match the same documents, but Postgres can order them differently because its ranking does not weigh how rare a word is. Postgres setup is covered in Operating It. Words used on this page Term - text: A field option that puts the field in the search index, written as `{ text: "title" }`. - filter: A named query in `document.ts`. The service gets methods named after it, like `listBySearch`. ## Single Sign-On Source: /cheatsheet/general/sso Mirror: /llms/pages/cheatsheet/general/sso.md Priority: P2 Headings: - Single Sign-On - Register Providers - Write A Callback - Account Id - After The Callback - Tips Single Sign-On SSO lets users sign in with GitHub, Google, Facebook, Kakao or Naver instead of a password. With `libs/shared` mounted, the routes and the sign-in logic already exist: you add keys, a button and the pages the user lands on. Words used on this page Term - provider: The service that confirms who the user is: GitHub, Google, Facebook, Kakao, Naver or Apple. - callback: The route the provider sends the user back to, carrying a one-time `code`. - accountId: The one value that identifies the user on every sign-in: an email or a GitHub username. - prepare user: A user in `prepare` status, created for a newcomer. The signup page finishes it. What you do **Add the keys.** Put each provider's client ID and secret under `security.sso` in the server env file. **Register the redirect URI.** Enter `<origin>/api/user/<provider>/callback` in each provider's developer console. **Place the buttons.** Render `User.Util.SSOButtons` on the sign-in page with three destinations. ## Agent Chat Source: /cheatsheet/interface/agent-chat Mirror: /llms/pages/cheatsheet/interface/agent-chat.md Priority: P2 Headings: - Where A Turn Runs - Mounting The Chat - Every Part Is A Slot - A Tool The User Answers - Pointing At Data - The Queue And The Slash Menu - Keeping The Transcript Agent Chat Where A Turn Runs `Agent.Chat` adds a chat that drives your screens for the user. The server only relays messages; every tool runs in the user's own browser tab. Words used on this page Term - turn: Everything the agent says and does between one user message and the next. - transcript: The conversation so far, kept in the browser tab and sent to the model every turn. - relay: The `runAgentTurn` endpoint, which passes the transcript to the LLM and never runs a tool. - tool: One action a component publishes with `st.tool`, usually the handler its button calls. - approval card: A card that holds a call until the user approves it. - slot: One part of the chat you can replace in `_overrides.tsx`. - reference: Data the user pointed at with `@`, carried inside their message. ## CRUD Source: /cheatsheet/interface/crud Mirror: /llms/pages/cheatsheet/interface/crud.md Priority: P2 Headings: - CRUD With Less Code - Start With A Slice - List And Open - Create And Edit - Remove In Util - Tips CRUD CRUD With Less Code CRUD is usually the first screen you build: list records, open one, create one, edit it and remove it. In Akan the store actions and components for all five already exist, so you write the three pieces below and the pages that place them. What you write - post.signal.ts: The slice. It decides which records this screen can read and edit. — Example: `inAdmin: init({ guards: [Admin] })` - Post.Template.tsx: Draws the form fields. Create and edit use the same one. — Example: `onChange={st.do.setTitleOnPost}` - Post.Zone.tsx: Connects the slice to UI behaviour with the `Load` and `Model` components. — Example: `<Load.Units init={init} renderItem={…} />` Each task maps to the components and generated store actions that do it: Task Store key or action Component - List — Load.Units — postListInAdmin ## Endpoint Source: /cheatsheet/interface/endpoint Mirror: /llms/pages/cheatsheet/interface/endpoint.md Priority: P2 Headings: - Endpoint Actions - The Flow - Declare Endpoint - Put Rules In Service And Document - Call It From Store - Make One Util - Tips Endpoint Endpoint Actions Every model already comes with create, update and remove. When a screen needs one clear business action on top — publish, approve, reject, archive, send a notification — you write an endpoint for it. CRUD — generated Comes with every model. You write no endpoint for it. Endpoint — you write it One business action, named with a verb. The rule of thumb: **one button, one store action, one endpoint, one service method.** Words used on this page Term - endpoint: A server function the client calls by name. You declare it in `<model>.signal.ts`. - guard: A class that decides who may call an endpoint. It runs before the handler. ## Form Source: /cheatsheet/interface/form Mirror: /llms/pages/cheatsheet/interface/form.md Priority: P2 Headings: - Form From Schema - Keep The Template Simple - Create With SSR - Update Page - Edit In A Modal - Options And Tips Form Form From Schema Once the model's schema is designed, a form is a thin layer over it. The shell around the form prepares the data, and the Template only draws the fields. Words used on this page Term - Template: The client component in `<Model>.Template.tsx` that draws the form's fields. - articleForm: The store's copy of the record being written. `st.use.articleForm()` reads it. - edit shell: A wrapper such as `Load.Edit` or `Model.Edit` that fills, opens and saves the form. - fetch.slice.<name>: Tells a shell which model to save and which list a new record joins. Pick the shell by where the form opens: Shell - Load.Edit: A page that creates or edits one record, such as `page/…/new.tsx` or `page/…/edit.tsx`. ## MCP Server Source: /cheatsheet/interface/mcp Mirror: /llms/pages/cheatsheet/interface/mcp.md Priority: P2 Headings: - MCP Server - 1. Turn The Server On - 2. Write An Endpoint - 3. Slices And CRUD - 4. Publish A Screen As A Prompt - When A Prompt Cannot Run - 5. Report Progress - Authorization - Tips MCP Server Every signal you already wrote is served to AI agents at `POST /mcp`. There is no second API and nothing to add to a signal file: the same endpoint runs through the same guards, middleware and service. The chat inside your own pages is a different surface, the In-Page Agent. Words used on this page Term - MCP: Model Context Protocol: the standard AI clients like Claude Code and Cursor use to call a server. - tool: A function the model may call; each published endpoint becomes one, named by its key. - resource: A read addressed by an `akan://` URI, which a client can attach as context. - prompt: A screen published for the user to run as a slash command in the MCP client. - catalogue: The list of tools, resources and prompts a client downloads when it connects. What becomes what What you wrote tool ## Desktop Release Source: /cheatsheet/mobile/desktop-release Mirror: /llms/pages/cheatsheet/mobile/desktop-release.md Priority: P2 Headings: - Desktop Release - Signing - Installers And CPU - Native Addons - CI Recipe Desktop Release - AKAN_NATIVE_MACOS_IDENTITY: A keychain identity by name (“Developer ID Application: Name (TEAMID)”) or SHA-1. A Mac that already holds the certificate needs only this. - AKAN_NATIVE_MACOS_CERTIFICATE + _PASSWORD: A .p12 file and its password. The build imports it into a keychain of its own and deletes it afterwards: the CI way. - AKAN_NATIVE_MACOS_NOTARY_KEY + _KEY_ID + _ISSUER: An App Store Connect API key (the AuthKey_XXXX.p8 file, its key id, the issuer id): the credentials `--notarize` submits and staples with. - AKAN_NATIVE_MACOS_NOTARY_PROFILE: Instead of the key: a profile `xcrun notarytool store-credentials` saved in the keychain. - AKAN_NATIVE_WINDOWS_CERTIFICATE + _PASSWORD: A .pfx file and its password. - AKAN_NATIVE_WINDOWS_THUMBPRINT: A certificate in the Windows store by its SHA-1 thumbprint: a USB token's or an HSM's. - AKAN_NATIVE_WINDOWS_SIGN_COMMAND: Any other signer as a JSON array, run once per file with {file} replaced, e.g. signtool with Azure Trusted Signing: ["signtool","sign","/fd","SHA256","/tr","http://timestamp.acs.microsoft.com","/td","SHA256","/dlib","Azure.CodeSigning.Dlib.dll","/dmdf","metadata.json","{file}"]. - AKAN_NATIVE_WINDOWS_TIMESTAMP_URL: The RFC 3161 timestamp server. Default http://timestamp.digicert.com. A desktop app people download from the internet has to be signed so the OS opens it: Gatekeeper refuses an unsigned or un-notarized macOS app, and SmartScreen warns on an unsigned Windows program. `akan build-desktop` signs with `--sign` and notarizes with `--notarize`, using the identity the environment names; the environment alone signs nothing. It packs the file people download with `--installer true`, and picks a Windows or Linux app's CPU with `--arch`; a macOS app is Apple silicon only. A desktop app is built on its own OS: a Mac builds the macOS app, a Windows PC the Windows one. The CI recipe below runs one job per OS instead of cross-compiling. Signing ## Deep Links Source: /cheatsheet/mobile/links Mirror: /llms/pages/cheatsheet/mobile/links.md Priority: P2 Headings: - Deep Link Setup - Link Fields Deep Links Deep Link Setup A deep link opens a specific screen of the app from a URL outside it, such as a link in a message or a tapped push notification. You set it up once, in the `native` section of `akan.config.ts`: `deepLinks` names the links, and `ios` and `android` hold what verifies a domain. Two Kinds Of Link Deep link is the feature; `schemes` and `domains` are the two usual ways to build it. You can declare both: - schemes: An app-only link. It needs no verification, so it is the easy one to test during development. — Scheme link — Example: `shop://orders/1` - domains: Works like a normal web link but needs iOS and Android verification. Best for sharing, email and push URLs. — Domain link — Example: `https://shop.example.com/orders/1` Declare It Write `deepLinks` in `native`, and the values that verify a domain in its `ios` and `android` sections: **Every target takes them.** A target that sets `schemes` or `domains` replaces that list; it does not add to it. **Hosts only in `domains`.** Write `shop.example.com`; an `https://` or a path you add is dropped. **`ios.teamId` and `android.sha256CertFingerprints` serve `domains`.** If you only use scheme links, leave both out. ## Push Notifications Source: /cheatsheet/mobile/push Mirror: /llms/pages/cheatsheet/mobile/push.md Priority: P2 Headings: - Push Setup - One Native Plugin - Web Push - Android Push - iOS Push - Which APNs Environment You Built - Client Registration - Where Tokens Live - Send And Retire Dead Tokens Push Notifications Push Setup The prompt appears, a token comes back, and the server logs a send. Nothing arrives on the phone. Push is one client API, `usePushNotification()`, and two senders on the server: APNs for iOS, FCM for Android and the web. A token sent without its sender's credential is skipped with one log line, so prepare every row that applies to you. Words used on this page Term - FCM: Firebase Cloud Messaging. Akan sends to Android apps and browsers through it. - APNs: Apple's push service. The server sends to iOS apps through it directly; Firebase is not involved. - push token: The address of one app install. `register()` returns it with the `provider` that delivers to it. - provider: `apns` on iOS, `fcm` on Android and the web. The server picks the sender by it. - deviceId: A random id the app keeps in its own storage, so a rotated token replaces the old one. - VAPID key: The web push key pair. Its public half goes in the client env as `vapidKey`. ## Setup Source: /cheatsheet/mobile/setup Mirror: /llms/pages/cheatsheet/mobile/setup.md Priority: P2 Headings: - Native Setup Flow - Native Config - Native Plugins - Android Setup - iOS Setup - Desktop - Verify Setup Setup Native Setup Flow An Akan native app is your CSR web app running inside a native shell that akanjs's own runtime generates for iOS and Android, and for macOS, Windows and Linux too. The web app owns the pages and business logic. The shell owns the package ID, device permissions, plugins, native files, signing and store builds, all declared in akan.config.ts. Words used on this page Term - native runtime: @akanjs/native, shipped inside akanjs. It runs your web app in a WebView and reaches device APIs through plugins. - CSR bundle: The single-page build of your app. The native app ships it, so keep `web.csr` on. - target: One native app built from your Akan app. Its key in `native.targets` is the `--target` value. - appId: The app's permanent ID: the package name on Android and the bundle ID on iOS. - dist/native/<app>/<target>: Each run's web root and builds for the target; generated and git-ignored, with no Xcode project to edit. - plugin: A native runtime module such as camera or push. The app ships it when a permission or `native.plugins` names it. Four steps ## UI & Keyboard Source: /cheatsheet/mobile/ui Mirror: /llms/pages/cheatsheet/mobile/ui.md Priority: P2 Headings: - Page Transitions - The Back Gesture - The Frame Config - The Keyboard Inset - Anchoring The Content UI & Keyboard Page Transitions Your app runs inside a native shell, yet every screen change lands like a web page swap. The user cannot tell whether they went deeper or sideways, and the back button is the only way out. Give the page a `transition` in `.config()`. The mobile app shell then animates the change the way a native app does. Words used on this page Term - Route depth: Path segments after the language and basePath: `/chat` is 1, `/chat/[chatId]` is 2. - Safe area: Space the device itself covers, such as the notch, the status bar and the home indicator. - Inset: Space the app reserves for its own bars, such as a navbar on top or a composer below. - keyboard accessory layer: A layer that rides on top of the software keyboard and moves with it. Set the transition A detail page that slides in over its list: ## Dependency Injection Source: /cheatsheet/observability/di Mirror: /llms/pages/cheatsheet/observability/di.md Priority: P2 Headings: - Dependency Injection - Inject Services - Adapt And Plug - Read Environment - Tips Dependency Injection **The field name is the key.** `mailApi: use<MailApi | null>()` reads what was registered as `mailApi`; the type argument does not choose it. **Each key is registered once.** An app mounting `libs/util` already has `storageApi`, `emailApi` and `host`, so a second registration of those is an error. **A value may be a Promise.** It is awaited before any service or adaptor starts. **Migrate when you touch it.** Move a `use` singleton to `adapt()` only when you are already changing it. A service lists what it needs in the builder of `serve()`, and Akan fills each field before the service starts. Business code stays small, and an outside system can be swapped without touching it. Words used on this page Term - injector: A helper like `service()` or `plug()` inside `serve()` or `adapt()`. Each one fills one field. - adaptor: A class built with `adapt()` that wraps one outside tool, such as storage or a mail API. - role: A slot for a built-in adaptor, such as `StorageAdaptorRole`. The app decides what fills it. - singleton: One instance per server process, shared by everything that injects it. ## Error Handling Source: /cheatsheet/observability/error Mirror: /llms/pages/cheatsheet/observability/error.md Priority: P2 Headings: - Error Handling - Declare Errors - Throw Err - Choose Status - Use Data - Client Handling - Response Shape - Tips Error Handling An order that is already paid cannot be edited, and the user should hear why in their own language. In Akan the server throws a dictionary key, and the client translates that key and shows it. One error travels through four steps: Where What happens - order.dictionary.ts: 1. Declare: register each error sentence as an `[en, ko]` pair in `.error({})`. - order.document.ts, order.service.ts: 2. Throw: when a business rule fails, throw `new Err("order.error.notDraft")`. - HTTP · WebSocket: 3. Send: the server answers with the untranslated key, a status code and `data`. - order.store.ts: 4. Show: fetch restores it as `Err`, and the store action shows it as a translated toast. Declare Errors Start in the module's dictionary. The keys you declare in `.error({})` are the only keys `Err` accepts, so TypeScript catches a typo. The snippet leaves out the other stages of the chain: ## Logging Source: /cheatsheet/observability/logging Mirror: /llms/pages/cheatsheet/observability/logging.md Priority: P2 Headings: - Runtime Logging - Using Logger - Log Levels - File Logging & Rotation - Reading Logs - Live Tail - Request Line & Flight Recorder - Collection: NDJSON stdout - The SSE Stream - Operational Checklist Logging off Runtime Logging A customer says a refund failed around four o'clock. With only twelve replicas' worth of stdout, nothing tells you which lines belonged to that call. Akan makes every log line a record first. Lines from one request share a `traceId`, so the question above becomes one command: `akan logs myapp --trace <id>`. Words used on this page Term - LogRecord: What one Logger call becomes: level, logger name, process and, inside a request, its trace. - traceId: An id shared by every line one request writes, such as `m8x1k2-a9f3c1`. - sink: A receiver registered with `Logger.addSink`, such as the rotating file or the hub. - floor: The lowest level a sink or reader accepts. Records below it are dropped. - hub: One journal of every process's records, kept by the gateway or by a solo replica. ## Metrics Source: /cheatsheet/observability/metrics Mirror: /llms/pages/cheatsheet/observability/metrics.md Priority: P2 Headings: - Health And Metrics - Check Health - Check Metrics - How To Read - Memory Logs - Troubleshooting Order Metrics off Health And Metrics When an app feels slow or stops answering, ask the running app before you guess. Two endpoints are built in and need no setup. Where to look What it answers - GET /_akan/app/health: **Is it alive?** Whether each replica is up and ready to take requests. - GET /_akan/app/metrics: **How busy is it?** Requests in flight, WebSocket load, memory and the render queue. - akan logs <app>: **Why?** Which endpoint, queue or render path produced those numbers. **No setup, no token.** Both are plain GET routes at the root of the app port (`8282` by default), not under the API prefix. **Same shape with or without a gateway.** A solo replica answers in the gateway's shape and adds `"solo": true`. **Only checking the port?** `/_akan/bench/ping` answers a plain `ok`. ## Caching Source: /cheatsheet/performance/caching Mirror: /llms/pages/cheatsheet/performance/caching.md Priority: P2 Headings: - Server Caching - Document Cache - Service Memory - Which One? - Tips Caching Server Caching A cache keeps a short-lived copy of a value so the server can skip expensive work. Use it for data that is safe to reuse for a while: verification codes, counters, summaries and computed options. Words used on this page Term - cache adaptor: The engine that holds cached values: a SQLite file or Redis, picked by the database mode. - topic: A namespace in front of the key, such as `previewTokens`. Topic plus key names one value. - expireAt, ttl: `expireAt` is the moment a value disappears, as a Dayjs; `ttl` is its lifetime in milliseconds. - replica: One of several server processes running the same app. Four ways to cache - Document Cache — A key–value store every model class carries. Reach for it when the key is a record id. — `this.articleCache.set(topic, id, value)` - Service Memory — A value or map a service keeps between calls, shared by every replica on the same cache. — `memory(String) · memory(Map, { of })` ## Image Optimization Source: /cheatsheet/performance/image Mirror: /llms/pages/cheatsheet/performance/image.md Priority: P2 Headings: - Image Optimization - Use Image - Config - Formats And The Platform - remotePatterns - Remote Cache - Cache Hits Image Optimization Someone uploads a 4MB phone photo and it renders as a 96px avatar. The layout looks right, yet every visitor downloads four megabytes for one thumbnail. `Image` from `akanjs/ui` solves this in three steps: **The component** writes an optimizer URL for each candidate, such as `/_akan/image?url=…&w=640&q=75`. **The server** resizes and re-encodes the original once, then keeps the result on disk. **The browser** picks the candidate from `srcSet` that fits the screen and downloads only that one. The rest of this page is about not defeating that cache. What you do **Render with `Image`.** Use it for every image the UI shows. **Allow remote hosts.** Remote images stay blocked until you list them in `images.remotePatterns` of `akan.config.ts`. **Keep sizes few.** Reuse a handful of sizes so many elements share one cached file. Words used on this page ## Lazy Loading Source: /cheatsheet/performance/lazy Mirror: /llms/pages/cheatsheet/performance/lazy.md Priority: P2 Headings: - Lazy Loading - External Libraries - Large Components - Server Adapters - Server Render Or Client Only - Tips Lazy Loading Lazy loading keeps a heavy component out of the first download. Its code arrives only when the user actually reaches it, through `lazy()` from `akanjs/webkit`. Words used on this page Term - chunk: A JavaScript file the bundler splits off, downloaded only when something asks for it. - Suspense boundary: A React boundary that shows a placeholder while something inside it is still loading. - shell: The first HTML the server sends; content inside a boundary may stream in after it. What to split Component lazy() import - Split it off ## Mutating Source: /cheatsheet/performance/mutation Mirror: /llms/pages/cheatsheet/performance/mutation.md Priority: P2 Headings: - Mutating Data - Two Write Styles - Counters And Sets - Upsert - How It Becomes SQL - Tips And Pitfalls Mutating Mutating Data You need to bump a view counter, archive a batch of rows, or edit the one record a user opened. There are two ways to write, and the choice decides whether your hooks run. - Document Path — Loads the document, changes it and saves it, so hooks run and a removal takes its cascade. — `await this.updatePost(id, data);` - Query Write — Sends one atomic SQL statement and loads nothing. Fast and safe under races, but no hook runs. — `await this.Post.updateOne(filter, change);` Which one runs what If a hook or a cascade must run for each document, take a document path. The table uses three words: Term - schema.pre, schema.post: Schema hooks, registered in `_onSchema`. They run whenever a document is saved or removed. - _preCreate, _postCreate, _preUpdate, _postUpdate, _preRemove, _postRemove: Service hooks. Only the service's `create<Model>`, `update<Model>` and `remove<Model>` run them. - cascade: A removal declared on a field: documents linked to the removed one go with it. Method ## Querying Source: /cheatsheet/performance/query Mirror: /llms/pages/cheatsheet/performance/query.md Priority: P2 Headings: - Querying - Basic Filter - Optional Conditions - Range And OR - Raw Query - How It Becomes SQL - Query Habits Querying In Akan, a database query is a named filter in `<model>.document.ts`. Services and slices call it by name instead of rebuilding the same condition in every place. Building Blocks Piece - filter(): Starts one named query inside `from(cnst.Task, (filter) => …)`. - .arg(name, Type): A required input, such as `.arg("projectId", ID)`. - .opt(name, Type): An optional input. It comes after every `.arg()` and is `undefined` when left out. - .query((...args, q) => …): Gets the inputs in declared order, then `q`, and returns the condition. - q: The condition helper: `q.all`, `q.oneOf`, `q.between`, `q.when` and more. - sort: Named orders beside the built-in `latest`, `oldest` and `relevance`. Write `{}` if you add none. Basic Filter Start from the list your screen needs. A project page, for example, shows the tasks of one project that are not archived. ## Queueing Source: /cheatsheet/performance/queue Mirror: /llms/pages/cheatsheet/performance/queue.md Priority: P2 Headings: - Queueing - Queue From Endpoint - Run In Process - Replica Roles - Tips Queueing Some work is too slow to finish inside a request. Put it in a queue and answer right away; a background process picks it up and does the heavy part. **Good for** backups, exports, report generation, imports, and long AI jobs. Words used on this page Term - process: An internal declared in the signal file. A queued job runs its `exec`. - job: One queued run of a process: its arguments plus its retry state. - replica: One server process of the app. Its role is `federation`, `batch` or `all`. - serverMode: A process option that picks which replica roles run its jobs. The three steps **The endpoint records the intent.** It saves `waiting`, queues the job and returns. **The queue holds the job** until a replica that runs this process takes it. ## Realtime Source: /cheatsheet/performance/realtime Mirror: /llms/pages/cheatsheet/performance/realtime.md Priority: P2 Headings: - Realtime - Send With message - Broadcast With pubsub - Chat Flow - Design Rooms - Tips Realtime Realtime keeps one WebSocket open, so the server and the browser trade small events without a new request each time. Chat, games, live editors, dashboards and presence all run on it. Tool Direction Use it for - message — Browser → server — e.g. read receipts, cursor moves, typing status, game input - pubsub — Server → everyone subscribed to the room — e.g. a new chat message, a notification - .live() — Database → every screen showing the list — e.g. a list of saved rows, such as a chat history **A room decides who receives.** A `pubsub` event reaches only the browsers subscribed to that room. **A saved list needs no pubsub.** With `.live()` on its slice, saving the row is enough. Send With message Use `message` for small actions the browser sends to the server: a read receipt, a cursor move, typing status, or game input. A read receipt declares its arguments with `.msg()`: ## Additional P2 Mirrors - Console: /llms/pages/cheatsheet/dev/console.md - Schema Docs: /llms/pages/cheatsheet/dev/constants.md - Docker: /llms/pages/cheatsheet/dev/docker.md - Documentation: /llms/pages/cheatsheet/dev/docs.md - Kubernetes: /llms/pages/cheatsheet/dev/k8s.md - Build Pipeline: /llms/pages/cheatsheet/dev/pipeline.md - PWA: /llms/pages/cheatsheet/dev/pwa.md - Script: /llms/pages/cheatsheet/dev/script.md - Testing: /llms/pages/cheatsheet/dev/test.md - Authorization: /llms/pages/cheatsheet/general/auth.md - DataList & Enum: /llms/pages/cheatsheet/general/datalist.md - Edge Computing: /llms/pages/cheatsheet/general/edge.md - File Management: /llms/pages/cheatsheet/general/file.md - OAuth For Agents: /llms/pages/cheatsheet/general/mcp-auth.md - Schema Design: /llms/pages/cheatsheet/general/schema.md - Text Search: /llms/pages/cheatsheet/general/search.md - Single Sign-On: /llms/pages/cheatsheet/general/sso.md - Agent Chat: /llms/pages/cheatsheet/interface/agent-chat.md - CRUD: /llms/pages/cheatsheet/interface/crud.md - Endpoint: /llms/pages/cheatsheet/interface/endpoint.md - Form: /llms/pages/cheatsheet/interface/form.md - MCP Server: /llms/pages/cheatsheet/interface/mcp.md - Desktop Release: /llms/pages/cheatsheet/mobile/desktop-release.md - Deep Links: /llms/pages/cheatsheet/mobile/links.md - Push Notifications: /llms/pages/cheatsheet/mobile/push.md - Setup: /llms/pages/cheatsheet/mobile/setup.md - UI & Keyboard: /llms/pages/cheatsheet/mobile/ui.md - Dependency Injection: /llms/pages/cheatsheet/observability/di.md - Error Handling: /llms/pages/cheatsheet/observability/error.md - Logging: /llms/pages/cheatsheet/observability/logging.md - Metrics: /llms/pages/cheatsheet/observability/metrics.md - Caching: /llms/pages/cheatsheet/performance/caching.md - Image Optimization: /llms/pages/cheatsheet/performance/image.md - Lazy Loading: /llms/pages/cheatsheet/performance/lazy.md - Mutating: /llms/pages/cheatsheet/performance/mutation.md - Querying: /llms/pages/cheatsheet/performance/query.md - Queueing: /llms/pages/cheatsheet/performance/queue.md - Realtime: /llms/pages/cheatsheet/performance/realtime.md - In-Page Agent: /llms/pages/docs/arch/agentic.md - UI Recipe Layer: /llms/pages/docs/arch/ui-recipe.md