
Give a background service a defined reach
Some background work deserves its own process. A minion runs beside the application with an explicitly declared set of resources it may read or write. Choose an always-up service or work triggered by a schedule.
Platform access is separate: permission to inspect its own schedule does not grant access to application records, or to another minion’s schedule. These declarations make a background service’s intended reach visible before reading its implementation.
Example — Read task information on a schedule without changing it
A reporting minion may read tasks but has no write permission. Its tick can inspect the permitted records and its own recent scheduled runs. Reaching an undeclared resource or attempting a write through the supplied services is refused.
For engineers
This selected entry comes from Wonder Todos’ wildo.saas.config.ts. The key marketingScrapper is the runtime identity used by its initialization; the package path identifies the separate process.
marketingScrapper: {
path: './minions/marketing-scrapper',
resourceAccess: {
read: ['todos'],
write: [],
},
platformAccess: {
scopes: [MinionPlatformAccessScope.OWN_CRON_RECORDS],
},
},
Read and write are independent allow-lists. Startup rejects unknown resource identifiers and substitutes a scoped services registry before accepting ticks. Its proxy recognizes allowed service methods and refuses unrecognized access rather than exposing a newly added method by default.
OWN_CRON_RECORDS permits the attested runtime’s own schedule and run history. The platform derives that identity from the attestation; the caller does not supply another minion’s identifier to widen the query.
Choose how the process receives work
| Mode | Schedule declaration | Execution contract |
|---|---|---|
cron | Required | The platform sends signed ticks to this minion’s dedicated queue. Its registered onTick handler performs the work. |
always-up | Omitted | The runtime starts without a recurring platform schedule. Mode selection does not itself call onTick or install a repeating work loop. |
Both modes bootstrap the headless backend and subscribe to the dedicated tick queue. Under normal operation, an always-up minion receives no scheduler ticks. Its continuously running work needs its own implementation and lifecycle; selecting the mode alone is not an implementation of that work.
The configuration rejects a cron minion without a schedule and an always-up minion with one. The following example uses cron mode.
Give the scheduled process its cadence
The package’s wildo.minion.config.ts declares this selected configuration fragment:
runtime: {
type: 'docker',
language: 'typescript',
},
mode: 'cron',
schedule: '0 */6 * * *',
resources: {
cpu: '500m',
memory: '512Mi',
},
That describes a six-hour cadence. Config synchronization and generated runtime configuration connect the authored package to deployment. Its entry point loads the application and provider configuration, then initializes through defineMinionInit with the matching runtime key and handler. A package declaration alone is not a running subscriber.
Use the scoped doors handed to the tick
This is a selected, shortened portion of the application’s actual handler in minion-init.ts. The full file builds and projects the backend initialization graph before passing this handler to defineMinionInit; its logging is omitted here.
onTick: async (token, { systemAccess, minionName, ownSchedule }) => {
const todos = await systemAccess.listAsSystem<{ _id: string }>(
TasksManager_ResourceType.TODOS,
{},
);
const ownJobs = await ownSchedule.read();
},
The first call crosses organization boundaries only through the system-access contract. It still needs the minion’s resource allow-list and the target resource’s declared system-read policy. The MINION runtime profile also requires accountable access: inability to record the required system-access audit causes refusal. An allow-list is therefore one layer, not blanket database authority.
The second call exercises the independent platform permission. Removing OWN_CRON_RECORDS can leave the task read permitted while refusing the schedule read. That difference is useful when a process needs business data but no control-plane visibility.
Plan for delayed and overlapping ticks
| Boundary | Runtime behavior | Application responsibility |
|---|---|---|
| Queue setup | This minion declares its dedicated queue; the scheduler checks it exists before publishing | Restore the runtime and its broker access when the queue is absent |
| Token freshness | Signed ticks have a five-minute lifetime, with the verifier’s clock tolerance; expired instructions are refused | Request fresh work after recovery rather than replaying an expired token |
| Handler completion | Success acknowledges the tick; verification or handler failure rejects it without requeue | Inspect the business effect and explicitly recover incomplete work |
| Overlap | The consumer awaits each handler but does not supply a per-business-operation lock | Coordinate competing work and make repeatable effects safe |
reinstantiation.policy governs replacement during deployment. In Kubernetes, kill_previous selects Recreate and let_run selects RollingUpdate; neither is a per-tick mutex or a promise to cancel a previous handler. The minion handler owns overlap and backpressure.
A later cron occurrence carries a fresh signed tick. It does not replay every missed occurrence or prove that an earlier partial effect was repaired. The explicit no-requeue failure rule also does not exclude redelivery after a broker or connection interruption. Use the resulting records or artifacts to decide what needs recovery before triggering work again.
Keep the execution lane distinct
The minion starts the backend lifecycle headlessly and subscribes to its own tick queue. Incoming scheduler tokens must identify this minion. It deliberately does not consume the application’s shared job queues, so adding a minion does not add queue-worker capacity.
The provided registry and system-access doors enforce the declared reach. They are not an operating-system sandbox for arbitrary code, independent database clients or external network calls. Keep the handler on the supplied access paths and grant only the resources and platform capability its job needs.