Playground
An example showcasing a fully featured product with multiple apps exposed on multiple targets.
Get
git clone git@github.com:c100k/libmodulor.git
pnpm install
Build
./scripts/examples/build.sh
Targets
server-node-express
This target uses the built-in node-express-server target,
is transpiled with tsc
and executed with Node.js.
It uses SQLite as UCDataStore.
Start the server.
(cd dist-examples/products/Playground/server-node-express && node --env-file .env index.js)
Test in your Terminal Emulator with curl.
# BuyAsset
curl -X POST -H "Content-Type: application/json" http://localhost:7443/api/v1/Trading_BuyAsset
# ❌ {"message":"Invalid credentials"}
curl -X POST -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" http://localhost:7443/api/v1/Trading_BuyAsset
# ❌ {"message":"ISIN must be filled"}
curl -X POST -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" -d '{"isin":"US02079K3059","limit":123.5,"qty":150}' http://localhost:7443/api/v1/Trading_BuyAsset
# ✅ {"parts":{"_0":{"items":[{"isin":"US02079K3059","id":"882f384b-fa46-424b-8b82-e0781ab1fbec","limit":123.5,"qty":150,"status":"pending"}],"total":1}}}
# CancelOrder
curl -X DELETE -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" -d '{"id":"882f384b-fa46-424b-8b82-e0781ab1fbec"}' http://localhost:7443/api/v1/Trading_CancelOrder
# ✅ {"parts":{"_0":{"items":[{"id":"a2285506-1afd-4649-98a6-e4443d1c6ce7","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"}],"total":1}}}
curl -X DELETE -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" -d '{"id":"882f384b-fa46-424b-8b82-e0781ab1fbec"}' http://localhost:7443/api/v1/Trading_CancelOrder
# ❌ {"message":"Cannot cancel an order that is not pending"}
# ListOrders
curl -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" http://localhost:7443/api/v1/Trading_ListOrders
# ✅ {"parts":{"_0":{"items":[{"id":"a2285506-1afd-4649-98a6-e4443d1c6ce7","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"}],"total":1}}}
Keep your server running to test the "client" targets defined below.
spa
This target uses the built-in react-web-pure target and is bundled with vite.
It is statically served by the server defined above for convenience, but it could also be served by anything else (e.g. an S3 bucket, a simple nginx server and so on).
Test in your browser at http://localhost:7443.

cli-node-core
This target uses the built-in node-core-cli target,
is transpiled with tsc
and executed with Node.js.
Test in your Terminal Emulator.
# BuyAsset
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_BuyAsset)
# ❌ ISIN must be filled
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_BuyAsset --isin US02079K3059 --limit 123.5 --qty 150)
# ✅ {"parts":{"_0":{"items":[{"isin":"US02079K3059","id":"c1ef95f1-f6e1-4616-a7a5-5584758b3a65","limit":123.5,"qty":150,"status":"pending"}],"total":1}}}
# CancelOrder
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_CancelOrder --id c1ef95f1-f6e1-4616-a7a5-5584758b3a65)
# Are you sure ? [Y,y = Yes / N,n = Cancel] : y
# ✅ {"parts":{"_0":{"items":[{"id":"c1ef95f1-f6e1-4616-a7a5-5584758b3a65","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"}],"total":1}}}
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_CancelOrder --id c1ef95f1-f6e1-4616-a7a5-5584758b3a65)
# Are you sure ? [Y,y = Yes / N,n = Cancel] : y
# ❌ Cannot cancel an order that is not pending
# ListOrders
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_ListOrders)
# ✅ {"parts":{"_0":{"items":[{"id":"a2285506-1afd-4649-98a6-e4443d1c6ce7","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"},{"id":"882f384b-fa46-424b-8b82-e0781ab1fbec","isin":"US02079K3059","limit":123.5,"qty":150,"status":"pending"},{"id":"c1ef95f1-f6e1-4616-a7a5-5584758b3a65","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"},{"id":"78509b91-0f33-43a2-b6e3-2ced5a1fa171","isin":"US02079K3059","limit":123.5,"qty":150,"status":"pending"}],"total":4}}}
cli-node-stricli
This target uses the built-in node-stricli-cli target
which is based on stricli,
is transpiled with tsc
and executed with Node.js.
It works the exact same way as the other cli target defined above.
mcp-server
This target target uses the built-in node-mcp-server target,
is transpiled with tsc
and exposes an index.js file to be used by the MCP client.
Test in Claude Desktop.
Open the config file to register the MCP server.
nano ~/Library/Application\ Support/Claude/claude_desktop_config.json
Paste the following config and adapt the absolute path.
{
"mcpServers": {
"libmodulor-playground": {
"command": "node",
"args": [
"/ABSOLUTE_PATH_TO_THE_CWD/dist-examples/products/Playground/mcp-server/index.js"
]
}
}
}
Launch Claude Desktop.
At the bottom right of the prompt, you should see a little hammer 🔨 indicating 1 MCP Tool available.
Click on it. You should see the use cases registered.
Write a prompt to buy an asset.
Dear Claude. Please buy 150 shares of Google.

rn
This target uses the built-in react-native-pure target,
is bundled with expo
and runs on android and ios.
Make sure your environment is setup to be able to use the Android Emulator and iOS Simulator (macOS only).
android
To call the server running on your machine, the Android emulator uses the special IP address 10.0.2.2. Therefore, you need to restart you server to listen on 0.0.0.0.
(cd dist-examples/products/Playground/server-node-express && app_server_binding_host=0.0.0.0 node --env-file .env index.js)
Start the application on the android emulator.
pnpm expo start --android dist-examples/products/Playground/rn
ios
Start the application on the ios simulator.
pnpm expo start --ios dist-examples/products/Playground/rn

server-node-hono
This target uses the built-in node-hono-server target.
It is very similar to node-express-server, except that it uses hono instead of express.
It also uses SQLite as UCDataStore.
If the node-express-server is still running, stop it and start this one.
(cd dist-examples/products/Playground/server-node-hono && node --env-file .env index.js)
You can test it the exact same way as above (with curl or the different clients).
server-nextjs
This target uses the built-in server-nextjs target
and the same components as the spa target defined above. Except that they are served by Next.js.
It also uses SQLite as UCDataStore.
(cd dist-examples/products/Playground/server-nextjs && pnpm next dev)
You can test it the exact same way as above (with curl or the different clients).
The only difference is that the server listens on port 3000 instead of 7443.
Thus, you need to adapt it in the clients' container.ts. That's a good exercise to get used to the settings mechanism.
server-cloudflare-worker
This target uses the built-in edge-worker-hono-server target in its sync flavor
and is managed with wrangler.
It uses Cloudflare D1 as UCDataStore.
You need a Cloudflare account to test this target, even locally, as you need to create a D1 database. Please note that this might occur charges on your account.
Initialize the D1 database.
pnpm wrangler d1 create libmodulor-examples-playground-uc-data-store
pnpm wrangler d1 list
Adapt the {your_database_id} in dist-examples/products/Playground/server-cloudflare-worker/wrangler.jsonc.
Apply the migrations to create the schema (local and remote).
pnpm wrangler d1 execute libmodulor-examples-playground-uc-data-store --cwd ./dist-examples/products/Playground/server-cloudflare-worker --local --file=./migrations/001_init.sql
pnpm wrangler d1 execute libmodulor-examples-playground-uc-data-store --cwd ./dist-examples/Playground/server-cloudflare-worker --remote --file=./migrations/001_init.sql
Start the server locally.
pnpm run:server-cloudflare-worker
You can test it the exact same way as above (with curl or the different clients).
The only difference is that the server listens on port 8787 (or a random one assigned by wrangler) instead of 7443.
Thus, you need to adapt it in the clients' container.ts. That's a good exercise to get used to the settings mechanism.
You can even deploy it on your account.
pnpm deploy:server-cloudflare-worker
Once done, perform the exact same tests as above, simply by replacing the local address and port by the remote one.
You can inspect the requests in the Cloudflare Workers & Pages dashboard as shown below.

Explore the data
SQLite
The server-node-express, server-node-hono and server-nextjs targets rebind the UCDataStore from InMemoryUCDataStore (default) to KnexUCDataStore configured with SQLite.
Explore the data with your favorite DB tool like DBeaver or TablePlus.
open uc-data-store.sqlite

Cloudflare D1
The server-cloudflare-worker target rebinds UCDataStore from InMemoryUCDataStore (default) to CloudflareD1UCDataStore.
Explore the data with your favorite DB tool like DBeaver or TablePlus.
open dist-examples/products/Playground/server-cloudflare-worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/{hash}.sqlite
For remote data, open the Cloudflare D1 dashboard as shown below.
