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.
General▾
Interface▾
Observability▾
Performance▾
Native▾
Development▾

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:
CommandForm
↳ Good for
akan scriptA file in script/ you can review and rerun
Seed data, migrations, checks, small maintenance fixes
akan consoleA 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.

Create And Run

Put the file directly in the app's script/ folder, then pass its name to akan script.
  1. Create apps/koyo/script/hello.ts. The next section shows what goes in it.
  2. From the workspace root, pass the app name and the file name. This runs apps/koyo/script/hello.ts:
Terminal
Arguments
Both arguments may be left out, and the command then asks. They are positional, so the app comes first:
appStringoptional
The app name, needed with a file name. Left out, it asks from a list or uses the only app.
filenameStringoptional
A file directly in script/; the .ts suffix is optional. Leave it out to pick from a list.
  • No subfolders. A name containing / or .. is refused, so keep every script at the top of script/.
  • It runs from the app folder. The working directory is apps/koyo/, so relative paths start there.

Server Lifecycle

Every script has the same frame: start the server, do the job, and stop the server in finally. The smallest script looks like this:
apps/koyo/script/hello.ts
  • server is the app's own. It comes from apps/koyo/server.ts, so the script boots the same modules the app does.
  • start() wires the app but opens no port. Under akan script it connects the databases and creates the adaptors, services and signals, and stops there.
  • stop() belongs in finally. Even when the job throws, database connections, timers and adaptors are cleaned up.

Use Services

Do the work through services rather than direct database writes. A service already knows the domain rules, the database access and its other dependencies.
This script finishes every ice cream order still left in served:
apps/koyo/script/finishServedOrders.ts
  • server.get(srv.IcecreamOrderService) finds the service by its class, so every method is typed.
  • listByStatuses comes from the model's byStatuses filter. Every filter gives the service a list<Filter> like it.
  • finishIcecreamOrder runs the same state check the app does, so an order that is not served is refused.

Lookup Helpers

Once server.start() resolves, server hands out any service, signal or adaptor the app registered. Prefer a class to a name string, which is not type-checked.
Finds byCall
↳ What you get
Classserver.get(srv.IcecreamOrderService)
A service, signal or adaptor instance, fully typed.
Roleserver.get(StorageAdaptorRole)
The storage adaptor the app actually uses, whatever its implementation.
refNameserver.getService("icecreamOrder")
A service.
refNameserver.getSignal("icecreamOrder")
A signal, when the script should run signal logic.
refNameserver.getAdaptor("blobStorage")
An adaptor, for infrastructure work.
  • A refName is the name a module registers under. For a service or signal it is the camelCase module name, such as icecreamOrder; for an adaptor it is the key passed to adapt().
  • A lib's classes sit under the lib's name, as in srv.shared.UserService.
  • Import StorageAdaptorRole from akanjs/service. A role finds the adaptor even after the app swaps in its own implementation.

Change Data Safely

A script that changes data should show what it is about to do before it does it. Three habits cover most of it:
  1. Print the target environment first. getEnv().environment names the environment the script is about to change.
  2. Make a dry run the default. It only shows what would change. Read an env var such as APPLY=1, and change nothing without it.
  3. Write through service methods. The domain rules then stay in one place instead of being copied into the script.
Here is the script from above with the first two habits added:
apps/koyo/script/finishServedOrders.ts
Run it once to read the count, then again to apply it:
Terminal
  • AKAN_PUBLIC_ENV picks the environment. The server reads the matching env/env.server.<env>.ts, and a new workspace's .env sets it to local.
  • A return inside try still reaches finally, so the dry run stops the server too.

Released under the MIT License

Connect your AI to these docs

MCPhttps://akanjs.com/mcp
Copyright © 2026 Akan.js All rights reserved.System managed bybassman