YouBothAgent▾
You — Business rules and flows you own. Read these yourself.
Both — Know the idea; your agent follows the details.
Agent — Conventions and references your agent follows. Look up as needed.
CLI Reference▾
AkanJS Reference▾
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
TermDescription
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
Server
no "use client"
Tool
st.tool
App shell
System.Provider
✓
✓
The app frame Akan wraps around your root
_layout.tsx.System.Reconnect
✓
✓
The connection-lost overlay
Provider mounts after .reconnect().Controls you place
System.ThemeToggle
✓
✓
Switches the color theme and publishes
applyTheme.System.SelectLanguage
✓
✓
Switches the URL's language and publishes
setLanguage.System.DevModeToggle
✓
Turns developer-only UI on and off.
Tab
✓
✓
Tabs whose panels stay on the server, published as a tool only with a
namespace.Developer tools and primitives
Signal.*
The API explorer, for an admin or docs screen.
ClientSide
✓
A
Suspense boundary with a loading fallback.animated
react-spring's animated
div, g and progress.✓YesNo
- Auto means you never write it.
Providerwraps every page, and it mountsReconnectwhen the root layout calls.reconnect(). - Server means you add no
"use client"yourself. A page, layout or View renders these directly; the parts that need the browser carry their own.Signalparts andanimatedneed a file that starts with"use client". - Tool means the in-page agent can use it too. Placing
ThemeToggleorSelectLanguageis enough for the agent to switch the theme or the language the same way the user does.
Related pages
Root Layout Stages→
.theme(), .fonts(), .reconnect() and the rest that fill System.Provider.Override Slots→
Restyle the toast stack through the
Toast and ToastItem slots.Constant Schema Docs→
Constant.Doc, the model explorer that sits beside Signal.In-Page Agent→
How the tools a control publishes let the agent drive the screen.
System
The app shell. Akan mounts
Provider for you, and Provider mounts Reconnect when you turn it on. ThemeToggle, SelectLanguage and DevModeToggle are controls you place yourself.Props / API
System.Provider{ appName, params, of, children, className?, env?, theme?, prefix?, manifest?, head?, fonts?, layoutStyle?, reconnect?, wsConnect?, dictionary?, allDictionary? }
The frame around your root
_layout.tsx, filled from its rootLayout() stages.System.Root{ st, children }
Deprecated: it renders
children and ignores st, so render the children directly.System.ThemeToggle{ themes?: string[] }
Sets
data-theme to one of themes: a switch for two, a dropdown for three or more.System.SelectLanguage{ className?, languages?: string[] }
A dropdown that swaps the
/:lang segment of the current URL and keeps the rest.System.Reconnect{}
When the socket drops and a ping fails, it covers the screen, then reloads once reconnected.
System.DevModeToggle{}
A switch for the store's
devMode flag, kept in localStorage across reloads.- Set the frame from the root layout.
.theme(),.fonts(),.manifest(),.layoutStyle(),.reconnect()and.wsConnect()becomeProvider's props, andenvcomes fromenv/env.client.ts. Reconnectis a local-development aid. It stays off until the root layout calls.reconnect(), and it renders only whenAKAN_PUBLIC_ENVislocal.ThemeToggleneeds at least two themes. Withthemesleft out or holding one entry it renders nothing. The choice is kept in thethemecookie.languagesdefaults to the app's locales. A code the app does not serve is dropped from the menu, because choosing it would lead to a 404.devModeis what developer-only UI reads. Admin screens check it before showing developer affordances, andOnly.Devfrom@libs/shared/uirenders its children only while it is on.- The toast stack is not a member on purpose.
Providermounts it and keeps themsg.*wiring, the store read, the body-level portal and the dismiss timers. That is why the override slots are the surface,ToastandToastItem, not the part that decides when a toast appears and goes away.
Usage
ClientSide
A small React
Suspense boundary. It shows loading while anything inside it suspends, such as a lazy() component still fetching its chunk.Props / API
childrenReactNode
The content that may suspend.
loadingReactNode
The fallback shown meanwhile; nothing is shown when it is left out.
- It does not make its children client-only. It is a plain
Suspensewith no"use client", so children that can render on the server still do. - In the example,
StoreMapis alazy()export. It comes from aui/StoreMap/index_.tsxboundary, soloadingcovers the chunk download.
Usage
Signal
The API explorer, split into parts. It reads the serialized signal the server ships with the app — every endpoint, its arguments, guards and return model — and renders a document you can also call endpoints from.
Props / API
Signal.Doc.Zone · .Explorer · .Setting · .AuthModal · .DocSignals · .DocSignal
Zone({ refName }) documents one signal; Explorer({ include?, exclude? }) puts them all behind a sidebar.Signal.RestApi.Endpoints · .Endpoint · .Interface · .Try
The HTTP side:
Endpoints lists queries and mutations, or only the ones named in endpoints.Signal.WebSocket.Endpoints
The same list for websocket endpoints, each row handed to
PubSub or Message.Signal.PubSub.Endpoint · .Interface · .Try
One subscription: its room, its payload shape, and a Try that shows frames as they land.
Signal.Message.Endpoint · .Interface · .Try
The same three parts for a one-way message endpoint.
Signal.Listener.Result
Result is the live pane a Try writes into, showing byte payloads as a short hex preview.Signal.Object.Type · .Detail · .Schema
A model from its constant class: a type chip, its field table, or a titled schema.
Signal.Argcomponent · .Table · .Param · .Query · .FormData · .ID · .Int · .Float · .String · .Boolean · .Date · .Json · .Upload
The one real component:
Arg({ argType, value, onChange }) renders one scalar's input.- Reach for a member, never a root.
Signal.Docand its siblings are namespaces, so writeSignal.Doc.ZoneorSignal.RestApi.Endpoints. OnlySignal.Argis a component itself. - Render it straight from a page. Every member crosses the client boundary on its own, and
fetchdefaults to the app's own, so no"use client"wrapper is needed. Passfetchonly to document another app's proxy. - Only mounted signals appear. The explorer reads
fetch.serializedSignal, so a signal the app did not mount is reported as unregistered instead of rendering empty. - One setting for the whole screen. The guard filter and the JWT chosen in
Doc.Settinglive in the store, so every endpoint list and every REST Try on the page follows them. - Each REST row shows its guards and its MCP status. A badge says whether the endpoint is published as an MCP tool, and a refused one says why.
Usage
Tab
A tab set split into parts so the panels stay on the server. Only the provider and the menu hold state, and
Tab.Panel renders what it is given, so the markup inside a panel never reaches the bundle.Props / API
Tab{ className?, defaultMenu?, namespace?, children? }
The provider holding the selected menu, which starts at
defaultMenu or, left out, at none.Tab.Menus{ className?, children }
The
role="tablist" row the menu buttons sit in.Tab.Menu{ menu, children, className?, activeClassName?, disabledClassName?, disabled?, tooltip?, scrollToTop? }
One tab button, keyed by
menu rather than value.Tab.Panel{ menu, children?, className?, loading?: "eager" | "lazy" | "every" }
The body shown while its
menu is selected; loading decides when it mounts.loadingdecides when a panel mounts."eager", the default, renders every panel up front and hides the others."lazy"mounts a panel on its first selection and keeps it;"every"mounts it on each selection and unmounts it on leave.namespacepublishes the tab to the in-page agent.namespace="product"adds thetabsInProductstate and theswitchTabInProducttool. Without it the tab set publishes nothing.- A disabled menu cannot stay selected. Disabling the active
Tab.Menumoves the selection to the first other enabled menu, andscrollToTopscrolls the window up on click. - Copy this shape. Never write one
"use client"file with a modeuseStateand every panel inlined in it: every panel's markup then ships as JavaScript.
Usage
animated
A small re-export of react-spring's animated elements, the ones Akan UI components animate with. Drive them with a spring hook in your own animated surfaces.
Props / API
animated.divreact-spring animated div
An animated
div.animated.greact-spring animated g
An animated SVG group,
g.animated.progressreact-spring animated progress
An animated
progress element.- Use it in a
"use client"file. The spring hooks that drive it run only in the browser, and its members are not available to a server component. - Only
div,gandprogressare wrapped. For another tag, use react-spring's ownanimatedin aui/file, the same way you importuseSpring.
Usage