Tasks
Tasks are notifications that appear in the StartOS UI prompting the user to run a specific action. They are commonly used to surface important information after install or restore, request required configuration, or coordinate setup with dependency services.
Own Tasks
Use sdk.action.createOwnTask() to prompt the user to run one of your service’s own actions.
await sdk.action.createOwnTask(effects, getAdminCredentials, 'critical', {
reason: i18n('Retrieve the admin password'),
})
Parameters
| Parameter | Type | Description |
|---|---|---|
effects | Effects | Provided by the calling context |
action | ActionDefinition | The action to prompt the user to run |
severity | 'critical' | 'important' | 'optional' | How urgently the task is surfaced in the UI |
options | { reason: string } | Human-readable explanation shown to the user |
Severity Levels
- critical — Blocks the service from starting until the user completes the task. Use for essential setup like retrieving generated passwords or selecting a backend.
- important — Prominently displayed but does not block the service. Use for post-install reminders like disabling registrations.
- optional — Informational, least prominent.
Common Patterns
Prompt on Install Only
Generate a password and prompt the user to retrieve it. Skip on restore (password already exists) and container rebuild:
export const initializeService = sdk.setupOnInit(async (effects, kind) => {
if (kind !== 'install') return
const adminPassword = utils.getDefaultString({ charset: 'a-z,A-Z,0-9', len: 22 })
await storeJson.merge(effects, {
adminPassword,
smtp: { selection: 'disabled', value: {} },
})
await sdk.action.createOwnTask(effects, getAdminCredentials, 'critical', {
reason: i18n('Retrieve the admin password'),
})
})
Prompt on Install and Restore
Useful when the user should always be reminded of credentials, even after restoring from backup:
export const initializeService = sdk.setupOnInit(async (effects, kind) => {
if (kind === null) return // Skip on container rebuild
if (kind === 'install') {
const adminPassword = utils.getDefaultString({ charset: 'a-z,A-Z,0-9', len: 22 })
await storeJson.merge(effects, { adminPassword })
}
await sdk.action.createOwnTask(effects, getAdminCredentials, 'critical', {
reason: i18n('Retrieve the admin password'),
})
})
Prompt for Required Configuration
Ask the user to configure something before the service can function:
await sdk.action.createOwnTask(effects, manageSmtp, 'high', {
reason: i18n('Configure email settings to enable notifications'),
})
Dependency Tasks
Use sdk.action.createTask() to prompt the user to run an action on a dependency service. The action must be imported from the dependency’s package.
import { someAction } from 'dependency-package/startos/actions/someAction'
export const setDependencies = sdk.setupDependencies(async ({ effects }) => {
await sdk.action.createTask(effects, 'dependency-id', someAction, 'critical', {
input: {
kind: 'partial',
value: { /* fields matching the action's input spec */ },
},
when: { condition: 'input-not-matches', once: false },
reason: i18n('Configure the dependency for use with this service'),
})
return {
'dependency-id': {
kind: 'running',
versionRange: '>=1.0.0:0',
healthChecks: ['dependency-id'],
},
}
})
Parameters
| Parameter | Type | Description |
|---|---|---|
effects | Effects | Provided by the calling context |
packageId | string | The dependency’s service ID |
action | ActionDefinition | Imported from the dependency’s package |
severity | 'critical' | 'important' | 'optional' | How urgently the task is surfaced |
options | object | See below |
Options
| Field | Type | Description |
|---|---|---|
input | { kind: 'partial', value: Partial<InputSpec> } | Pre-fill fields in the action’s input form |
when | { condition: 'input-not-matches', once: boolean } | Re-trigger until the action’s input matches the provided values |
reason | string | Human-readable explanation shown to the user |
replayId | string (optional) | Overrides the default idempotency key (see below) |
Note
The dependency must be listed in your
package.jsonso the action can be imported (e.g.,"synapse-startos": "file:../synapse-wrapper"). See Dependencies for more on cross-service integration.
Idempotency and replayId
Tasks are idempotent by default. The SDK computes a default replayId of [package-id]:[action-id], so calling createOwnTask / createTask multiple times with the same action does not create duplicate tasks — subsequent calls are no-ops against the same replay key. You can safely re-run your init function on every container rebuild without accumulating stale tasks.
Provide a custom replayId only when you need to intentionally create multiple distinct tasks for the same action (e.g., one-per-peer setup prompts). Each unique replayId becomes a separate task.
To cancel a task programmatically, clear it by its replay key:
await sdk.action.clearTask(effects, 'my-service:get-admin-credentials')