diff --git a/apps/dashboard/src/components/apps/app-activation.tsx b/apps/dashboard/src/components/apps/app-activation.tsx
index 63b4871bc..815d4e192 100644
--- a/apps/dashboard/src/components/apps/app-activation.tsx
+++ b/apps/dashboard/src/components/apps/app-activation.tsx
@@ -10,9 +10,16 @@ import type { AppSummary } from '#queries/apps.ts';
*/
export function AppActivation({ app }: { app: AppSummary }) {
return (
-
-
Activation
-
{activationSummary(app)}
+
+
+ Activation
+ {activationSummary(app)}
+
+ {app.activation === 'on-request' && (
+
+ Background work pauses during sleep. Activation isn’t configurable for now.
+
+ )}
);
}
diff --git a/apps/dashboard/src/components/deploy/deploy-dialog-content.tsx b/apps/dashboard/src/components/deploy/deploy-dialog-content.tsx
index 343cb9de6..ce1dda14a 100644
--- a/apps/dashboard/src/components/deploy/deploy-dialog-content.tsx
+++ b/apps/dashboard/src/components/deploy/deploy-dialog-content.tsx
@@ -79,6 +79,6 @@ export function DeployDialogContent({
function describeDeploy(newApp: boolean): string {
return newApp
- ? 'The binary is uploaded to the store, then released as what the app runs.'
+ ? 'New apps sleep after five minutes without incoming traffic. Background jobs and timers do not run while asleep; activation cannot currently be changed.'
: 'The app is released again with whatever this leaves it set to. A binary replaces the one it runs; without one, it keeps it.';
}
diff --git a/apps/www/public/llms.txt b/apps/www/public/llms.txt
index 42844574d..b11eb7b82 100644
--- a/apps/www/public/llms.txt
+++ b/apps/www/public/llms.txt
@@ -66,8 +66,11 @@ listen on it, on `0.0.0.0`.
One microVM per app: no horizontal scaling, no load balancing. A deploy stops the old VM before
starting the new one, so it is a few seconds of downtime rather than blue/green. An app sleeps
-after five minutes idle and wakes on the next request in ~120 ms. It fits a single-binary app that
-owns its own state; it does not fit anything that has to be several machines.
+after five minutes without incoming traffic and wakes on the next request in ~120 ms.
+Background jobs, timers, scheduled emails and outbound polling do not run while it sleeps.
+Owners cannot change activation through the CLI, API or dashboard. Apps that need background
+work to run on schedule are not currently a fit. It fits a single-binary app that owns its own
+state; it does not fit anything that has to be several machines.
## Links
diff --git a/packages/cli/src/commands/apps/update.ts b/packages/cli/src/commands/apps/update.ts
index c69a5e75a..0c9752c8d 100644
--- a/packages/cli/src/commands/apps/update.ts
+++ b/packages/cli/src/commands/apps/update.ts
@@ -10,7 +10,7 @@ import { updateApp } from '#lib/update.ts';
export const command = defineCommand('apps update', {
description:
- 'Change how the app starts and run it again on the binary it already has. Nothing is uploaded, and whatever no flag names is left as it is.',
+ 'Change how the app starts and run it again on the binary it already has. Nothing is uploaded, and whatever no flag names is left as it is. Activation cannot currently be changed: on-request apps sleep without incoming traffic, and background jobs and timers do not run while asleep.',
options: {
args: {
schema: z.string().optional(),
diff --git a/packages/cli/src/commands/run/[command].ts b/packages/cli/src/commands/run/[command].ts
index 320861e47..1c69aacff 100644
--- a/packages/cli/src/commands/run/[command].ts
+++ b/packages/cli/src/commands/run/[command].ts
@@ -80,6 +80,12 @@ export const command = defineCommand('run [command]', {
? await completeOptions({ api, options: given, binarySource, args })
: given;
+ if (resolved.app === undefined) {
+ ui.step(
+ 'New apps sleep after five minutes without incoming traffic. Background jobs and timers do not run while asleep; activation cannot currently be changed.',
+ );
+ }
+
emit(await deploy({ ...resolved, api, ui, binary, args, detach }));
},
});
diff --git a/skills/deploy-to-nibrun/SKILL.md b/skills/deploy-to-nibrun/SKILL.md
index c7bc0d91d..4cb910ec8 100644
--- a/skills/deploy-to-nibrun/SKILL.md
+++ b/skills/deploy-to-nibrun/SKILL.md
@@ -232,6 +232,10 @@ nib apps update --app my-app --extra-public-port --env 'ANNOUNCED_IP=${NIBRUN_PU
Worth saying out loud before recommending it:
+- **New apps sleep after five minutes without incoming traffic.** The next request wakes them.
+ Background jobs, timers, scheduled emails and outbound polling do not run while an app sleeps,
+ and outbound work does not keep it awake. Owners cannot change activation through the CLI, API
+ or dashboard. An app that needs background work to run on schedule is not currently a fit.
- **One microVM per app, one size.** No horizontal scaling, no load balancing, no resizing.
- **A deploy is a replace.** The old VM is stopped before the new one starts, because they share
one volume — so there are a few seconds of downtime, and no blue/green or canary.