Skip to content

task

Tasks are operations executed on devices — they are produced by many flows (ndcli sync apply, VPN configuration, backup runs, recurring scheduled tasks, and user-initiated runs via ndcli run). The task command surface is for inspecting and cancelling them. To issue a command to one or more devices, use ndcli run. To manage recurring tasks, use ndcli schedule tasks.

Each task records where it came from, and, for one a person started, who asked and from which client. See Where a task came from.

TypeDescription
PINGCheck device connectivity (issued by ndcli run ping)
SHUTDOWNPower off the device (issued by ndcli run poweroff)
REBOOTReboot the device (issued by ndcli run restart)
RESTARTRestart the NetDefense agent service (issued by ndcli run plugin-reload)
PLUGIN_INSTALL(Re)install the NetDefense agent plugin (issued by ndcli run plugin-install)
FIRMWARE_UPGRADEUpgrade the device’s OPNsense firmware — a minor point release or a major series jump (issued by ndcli run firmware-upgrade)
FIRMWARE_TRACKOne step of a firmware track: pin a device at its installed release, move it to its track’s release and update it, or put back the setting it had. NetDefense creates these; ndcli run can’t
PULLPull configuration from device
SYNCSync configuration to device
BACKUPRun a configured backup
CONNECTOpen a remote-access tunnel session to the device

A FIRMWARE_TRACK task is created by NetDefense when you move a device into or out of a track, and at each of a track’s windows. Nobody can create one with ndcli run. List them with ndcli task list --type FIRMWARE_TRACK. A page that holds a completed one gets an extra Result column, such as advance success 26.1.11 → 26.7 (major upgrade).

ndcli task describe shows a completed one as a result block:

Firmware track result:
Action: advance on the regular track
Outcome: held
Reason: a reboot is pending on the device (held_reboot_pending)
Target: 26.1.10
Pinned: 26.1.8
Drift: no

Action is enroll, advance or unenroll. The block exists only for a completed step, and its Outcome is success, noop, held or released. A step that failed, or never got an answer from the device, shows its plain Message. Its outcome, failed or failed_no_response, appears in ndcli firmware history, and a failed one in the Last Result column of ndcli firmware status too. A major upgrade adds a Kind line and Note lines, and Drift says whether the pin had been changed outside NetDefense. With -f json, the block is also returned as firmware_track_result, beside the task as NetDefense sent it. The reasons are explained in Firmware Tracks.

To stop the steps that are queued for a release or a series, halt it, switch major upgrades off for the track, or disable Firmware.

StatusDescription
PENDINGTask created and waiting for dispatch
SCHEDULEDTask deferred via --at; activates when its time arrives
IN_PROGRESSTask currently executing on the device
COMPLETEDTask completed successfully
FAILEDTask did not succeed, for example because the device reported an error, or took the task and sent no final answer by its deadline
CANCELEDTask was cancelled before dispatch, or because its device was deleted
EXPIREDThe task’s deadline passed before it reached the device, so it never ran

Note the spelling: the status value is CANCELED, with a single L. From ndcli 1.36.0, --status also accepts CANCELLED.

An EXPIRED task’s message says why it never reached the device, such as Task expired before delivery: the device was offline (last seen 2026-10-17T14:03:22Z). A task can also expire while its device is online. ndcli task describe prints the message as NetDefense stored it, with the time in UTC. See Expired or failed for every reason.

Every task records its source. From ndcli 1.40.0, task list and task describe show it, and -f json carries it as origin.

SourceCreated bytask list shows
MANUALA person: ndcli run, a sync, a pull, a remote-access session, or a command from the web app or the MCP serverThe person and the client, such as ana@example.com · CLI, or Manual
SCHEDULEA scheduled task firingSchedule nightly-backup
FIRMWAREA step of a firmware trackfast track, or Firmware track

A task a person started also records:

  • Who asked (requested_by): the account’s email and name, read when you look at the task. If the account has since been deleted, both are null and the task reads Deleted account. A task that a schedule or a track created has no requester.
  • The client (client): how the request arrived. WEB is the web app, CLI is ndcli, MCP is the MCP server, and API is a personal access token, whatever sent the request, ndcli with NDCLI_TOKEN set included. From ndcli 1.40.0 the MCP server is told apart from ndcli; a task started through an older one is recorded as CLI. The client describes the request. It never grants or limits anything, and a request that arrived another way has none.

Every task also belongs to a run (run_id): eight letters or digits shared by the tasks that one request created, such as the tasks of one ndcli run on several devices or of one ndcli sync apply, or that one firing of a scheduled task created. A schedule with several scheduled tasks fires one run for each. List a run with task list --run, and read its code from ndcli task describe on any of its tasks. The Tasks page of the web app gathers a run’s tasks under one header.

Dispatched is when NetDefense sent the task to the device. Completed is when it reached its final status: COMPLETED, FAILED, EXPIRED or CANCELED. Duration is the time between the two, so it counts what the device needed, not the time the task waited. A task that was never sent, such as one that expired or was canceled before it ran, has no Dispatched and no Duration. When the device answers a task after it failed with a timeout, its answer takes the place of the timeout, and Completed moves with it.

A task created before NetDefense began recording these has no requester, client or run, and usually no Dispatched or Completed. For one a person started, task describe says Source: Manual (who started it is not recorded), and -f json has null in the new fields. Such tasks leave the list with the rest of your history: see Task retention.

NetDefense automatically removes finished tasks (COMPLETED, FAILED, EXPIRED and CANCELED) once they are older than your plan keeps them: 30 days on the default plan. The Tasks page of the web app states your organization’s period under its title. More precisely, a finished task is removed once its creation time, its expiry time and its last update are all further in the past than that period. PENDING, SCHEDULED and IN_PROGRESS tasks are never removed. Removal runs in the background about once an hour, so a task can stay visible a little past the period.

Once removed, a task no longer appears in ndcli task list, on the Tasks page of the web app or on the dashboard, and looking up its task code returns “not found”. Removing a BACKUP task leaves its backup alone, whether a schedule or run backup started it: backup files live in your organization’s own storage, and NetDefense does not delete them. Recurring scheduled tasks and their schedules are not affected either.

CommandDescription
task listList tasks
task describeShow task details
task cancelCancel a pending or scheduled task

List tasks in your organization.

Terminal window
ndcli task list [flags]
FlagTypeDefaultDescription
--devicestringFilter by device name (regex); --device-exact takes exact names
--statusstringFilter by status. For several values, repeat the flag or separate them with commas (e.g., --status FAILED --status EXPIRED); that needs ndcli 1.36.0 or later
--typestringFilter by task type. For several values, repeat the flag or separate them with commas (e.g., --type SYNC --type BACKUP); that needs ndcli 1.36.0 or later
--expiredboolFilter by expired status
--created-afterstringFilter by created date
--created-beforestringFilter by created date
--sort-bystringcreated_at:descSort as field:direction. The fields are created_at, updated_at, expires_at, scheduled_at, status, type and device, and the direction is asc or desc
--pageint1Page number
--per-pageint30Items per page (max 100)

These flags need ndcli 1.40.0 or later, and a control plane that applies them: see An older control plane. They narrow the list together with the flags above.

FlagTypeDescription
--exclude-typestringLeave out these task types, for example CONNECT to hide remote-access sessions. Repeat the flag or separate the values with commas. It applies together with --type, and all isn’t accepted
--originstringOnly tasks from these sources: MANUAL, SCHEDULE or FIRMWARE. Repeat the flag or separate the values with commas, or give all for no filter
--schedulestringOnly the tasks that the scheduled tasks of this schedule created. The schedule’s exact name
--device-exactstringOnly the tasks of the devices with exactly these names. Repeat the flag or separate the values with commas. A deleted device isn’t found by its old name here
--searchstringOnly the tasks whose code or device name contains this text, whatever the case. Plain text, not a pattern. A deleted device’s name counts
--scheduled-afterstringOnly the tasks set to run at or after this time, the ones deferred with ndcli run --at. A task with no scheduled time never matches. See Date Filter Formats
--scheduled-beforestringOnly the tasks set to run at or before this time
--include-activeboolWith --created-after or --created-before, also list every PENDING, SCHEDULED and IN_PROGRESS task, whenever it was created. The other filters still apply to them, so a reboot booked three days ago for tomorrow stays in a 24-hour list
--runstringOnly the tasks of one run: its code, eight letters or digits
--requested-bystringOnly the tasks that the account with this email asked for, whatever the case. A task that a schedule or a track created never matches

A type, status or origin that ndcli doesn’t know is refused before anything is sent, and so is a run code that isn’t eight letters or digits.

--created-after, --created-before, --scheduled-after and --scheduled-before accept:

  • Relative: 30m, 2h, 7d, 2w (minutes, hours, days, weeks ago). --scheduled-after and --scheduled-before also take +30m, +2h or +7d, for that long from now
  • ISO 8601: 2024-01-15T10:30:00Z. A time with an offset, such as 2024-01-15T10:30:00-03:00, is converted. A time without an offset is read as UTC

From ndcli 1.40.0, a relative time is counted from the current moment whatever timezone your computer is set to. Earlier releases moved the window by the computer’s offset from UTC.

The table has the columns ID, Type, Status, Device and Created. These are added when the page has something to show in them:

  • Source: where the task came from and, for a task a person started, who and from which client, as in Where a task came from. A control plane that doesn’t say leaves the column out.
  • Duration: how long the task took, such as 3s, 1m 12s, 2h 05m or 1d 02h, or - when that isn’t known. The column shows when at least one task on the page was sent and has finished.
  • Result: the result of a firmware track step.

A device that was deleted has (deleted) after its name, and a waiting task whose device isn’t connected has (offline).

╭──────────┬────────┬─────────────┬──────────────────┬─────────────────────────┬──────────────────┬──────────╮
│ ID │ Type │ Status │ Device │ Source │ Created │ Duration │
├──────────┼────────┼─────────────┼──────────────────┼─────────────────────────┼──────────────────┼──────────┤
│ Pq3Lm8Xa │ PING │ ● COMPLETED │ fw-branch-01 │ ana@example.com · CLI │ 2026-10-18 11:02 │ 3s │
│ Pq3Lm8Xb │ PING │ ● COMPLETED │ fw-branch-02 │ ana@example.com · CLI │ 2026-10-18 11:02 │ 2s │
│ tQSd9RCV │ BACKUP │ ● COMPLETED │ fw-branch-01 │ Schedule nightly-backup │ 2026-10-18 00:00 │ 1m 12s │
│ Dl2Gn6Hk │ SYNC │ ○ FAILED │ fw-old (deleted) │ Deleted account · MCP │ 2026-10-16 07:00 │ 39s │
│ Mn4Op5Qr │ REBOOT │ ○ SCHEDULED │ fw-branch-02 │ ana@example.com · WEB │ 2026-10-18 06:00 │ - │
╰──────────┴────────┴─────────────┴──────────────────┴─────────────────────────┴──────────────────┴──────────╯

With -f simple, each task is one line: • Pq3Lm8Xa - PING [COMPLETED] · ana@example.com · CLI · took 3s. With -f detailed, each task is a block of fields, including its source, requester, client and run, and when it was sent and finished. With -f json, each task has the keys listed under task describe.

Terminal window
ndcli task list
ndcli task list --created-after 1h
ndcli task list --device fw-prod-01
ndcli task list --status FAILED
ndcli task list --type SYNC
ndcli task list --status SCHEDULED --sort-by created_at:asc
# Multi-value: show both FAILED and EXPIRED tasks
ndcli task list --status FAILED --status EXPIRED
# Multi-value: show SYNC and BACKUP tasks from the last 24h
ndcli task list --type SYNC --type BACKUP --created-after 24h
# The last day, hiding remote-access sessions, with every task that is still active
ndcli task list --created-after 24h --include-active --exclude-type CONNECT
# What the nightly-backup schedule created
ndcli task list --schedule nightly-backup
# Failed tasks that schedules created
ndcli task list --origin SCHEDULE --status FAILED
# Everything one person asked for in the last week
ndcli task list --requested-by ana@example.com --created-after 7d
# The tasks of one run
ndcli task list --run R7x2Kp9Q
# Tasks set to run within the next 24 hours
ndcli task list --status SCHEDULED --scheduled-before +24h
# The tasks of exactly one device
ndcli task list --device-exact fw-branch-01

The filters added in ndcli 1.40.0 are applied by the control plane. One that doesn’t have a filter yet ignores it without a word, which would hand you a list that looks filtered and isn’t. So ndcli checks that the control plane applied each filter you gave. When one wasn’t applied, ndcli prints no list and exits with status 1. The error reads Error: [SERVER_TOO_OLD] …: it says the control plane predates the filter, names it, and says that no list is shown. With -f json, the error is {"error": {"code": "SERVER_TOO_OLD", "message": "…"}} on standard error, and standard output stays empty. Run the command again without that filter. --run and --requested-by are the newest, so a control plane that applies the other filters may still refuse these two.

Plain ndcli task list and ndcli task describe work against an older control plane. They leave out the columns it has nothing for, and -f json has null in the fields it doesn’t send.


Show detailed information about a specific task.

Terminal window
ndcli task describe [task-id]
ArgumentRequiredDescription
task-idYesTask code (8-char base62)

Shows:

  • Task code, type and status
  • The device, followed by (deleted) when it was removed. For a waiting task it also says whether the device is connected and when it was last seen, such as fw-branch-01 (offline, last seen 2026-10-17 19:41:10)
  • The organization
  • Source: where the task came from, as in Where a task came from. A task that a scheduled task created adds Schedule, Spec (the scheduled task’s code and kind) and Next run, which reads disabled while it is paused. A task a person started adds Requested by and Client. Any task that belongs to a run adds Run
  • Creation, expiry and (when set) scheduled times, then Dispatched, Completed and Duration, and Responded, when the device’s answer was recorded
  • Result or error message
Task ID: Pq3Lm8Xa
Type: PING
Status: COMPLETED
Device: fw-branch-01
Organization: acme-corp
Source: Manual
Requested by: Ana Lima <ana@example.com>
Client: CLI
Run: R7x2Kp9Q
Created: 2026-10-18 11:02:11
Expires: 2026-10-18 11:07:11
Dispatched: 2026-10-18 11:02:12
Completed: 2026-10-18 11:02:15
Duration: 3s
Responded: 2026-10-18 11:02:15
Message:
pong

A line appears only when the task has something for it. Times are in your configured display timezone.

With -f json, the task is printed as the control plane sent it, with a few keys of ndcli’s own added. Times are UTC and end in Z, and a key that the control plane doesn’t send is null. These keys describe where the task came from and how it ran:

KeyMeaning
originMANUAL, SCHEDULE or FIRMWARE
scheduleFor a task that a scheduled task created: its name, spec_code, kind, next_run_at (null while it is disabled) and firmware_track. null for any other task, and when the schedule or the scheduled task has been deleted
requested_byThe email and name of the account that asked. null for a task nobody asked for, and both fields null once the account is deleted
clientWEB, CLI, MCP or API. null when none is recorded
run_idThe run’s code
dispatched_atWhen NetDefense sent the task to the device. null until then
completed_atWhen the task reached its final status. null while it has none
duration_secondsAdded by ndcli: the seconds from dispatched_at to completed_at, or null when either is missing
started_atAdded by ndcli: the same instant as dispatched_at. It had no value before ndcli 1.40.0, so read dispatched_at in new scripts
device_deletedtrue when the device has been removed
device_online, device_last_seen_atFor a PENDING or SCHEDULED task: whether its device is connected, and when it was last seen, which can lag by about two minutes. null for any other task
last_response_atWhen the device’s answer was recorded. null when it never answered
Terminal window
ndcli task describe abc12345
ndcli task describe abc12345 -f json
  • Finished tasks are removed once they are older than your plan keeps them (30 days on the default plan); looking up a removed task’s code returns “not found”. See Task retention.

Cancel a pending or scheduled task.

Terminal window
ndcli task cancel [task-id]
ArgumentRequiredDescription
task-idYesTask code to cancel
Terminal window
ndcli task cancel abc12345
  • Only tasks with PENDING or SCHEDULED status can be cancelled.
  • Tasks already IN_PROGRESS cannot be cancelled.
  • Cancelled tasks have status CANCELED.

The three commands have tools in the MCP server: ndcli.task.list, ndcli.task.describe and ndcli.task.cancel. Their arguments follow the flags, with an optional organization. ndcli.task.cancel changes nothing until it is called with confirm=true, and returns a preview without it.

ndcli.task.list takes every filter above, and needs ndcli 1.40.0 or later for the newer ones. An argument is the flag’s name with underscores for hyphens, such as exclude_type, device_exact and created_after, and the one that differs is run_id, for --run. Where a flag takes several values, the argument is a list.

Each task in the list, and the one ndcli.task.describe returns, carries origin, schedule, device_deleted, device_online, device_last_seen_at, last_response_at, requested_by, client, run_id, dispatched_at, completed_at and duration_seconds, with the meanings under task describe. started_at isn’t among them, so read dispatched_at. Times are UTC, and a key that the control plane doesn’t send is null.

A task started through the MCP server on your login is recorded with the client MCP from ndcli 1.40.0, so the web app shows it as Manual · MCP. A server from an older release is recorded as CLI, and one running on NDCLI_TOKEN as API.

When the control plane doesn’t apply a filter yet, ndcli.task.list returns no list. Its error has the code SERVER_TOO_OLD and names the filter: call the tool again without that argument. See An older control plane.