System Tasks

System tasks are reusable task handlers that can run on demand, from recurring schedules, or inline as workflow/pipeline steps. They handle AI-powered content operations (alt text, meta descriptions, internal linking), media processing (image generation, optimization), and agent housekeeping (daily memory synthesis). All system tasks share a common base class with standardized job management, effect tracking, and undo support.

Overview

The system tasks framework consists of:

  1. SystemTask base class — abstract base with job completion, failure handling, rescheduling, and undo
  2. SystemAgentServiceProvider — registers task handlers and Action Scheduler hooks
  3. TaskRegistry — central registry of available task types
  4. TaskScheduler — enqueues a task run through datamachine/execute-workflow
  5. SystemTaskStep — pipeline step type that bridges system tasks into pipeline workflows
  6. RecurringScheduleRegistry — optional schedule bindings that say when a task should run

Note: GitHubIssueTask was extracted to the data-machine-code extension plugin (see PR #926). It is no longer part of core data-machine.

SystemTask Base Class

Note: GitHubIssueTask was extracted to the data-machine-code extension plugin (see PR #926). It is no longer part of core data-machine.

Note: GitHubIssueTask was extracted to the data-machine-code extension plugin (see PR #926). It is no longer part of core data-machine.

php
abstract class SystemTask {
    public function getWorkflow(array $params): array;
    abstract public function executeTask(int $jobId, array $params): void;
    abstract public function getTaskType(): string;
}

Source: inc/Engine/AI/System/Tasks/SystemTask.php Since: v0.22.4

php
[
    'steps' => [
        [
            'type' => 'system_task',
            'flow_step_settings' => [
                'task_type' => $this->getTaskType(),
                'params'    => $params,
            ],
        ],
    ],
]

All system tasks extend this abstract class:

Job Lifecycle Methods

MethodDescription
completeJob(int $jobId, array $result)Store result in engine_data and mark job as completed. Logs success.
failJob(int $jobId, string $reason)Store error in engine_data and mark job as failed. Logs error.
reschedule(int $jobId, int $delaySeconds)Reschedule for later execution via Action Scheduler. Tracks attempt count with a default max of 24 attempts.

Task Metadata

getWorkflow() is the scheduling contract. The default implementation returns a single system_task workflow step using the canonical flow_step_settings.task_type key:

php
public static function getTaskMeta(): array {
    return [
        'label'           => 'Human-readable task name',
        'description'     => 'What this task does',
        'setting_key'     => 'wp_option_key_to_enable',  // null if always available
        'default_enabled' => true,
        'trigger'         => 'How it gets triggered',
        'trigger_type'    => 'cron|event|tool|manual',
        'supports_run'    => false,                       // Can be manually triggered?
    ];
}

AI Model Resolution

executeTask() is the imperative body called by SystemTaskStep. System task step settings use task_type; configs that still use the older task key must be upgraded before they run.

php
$system_defaults = $this->resolveSystemModel($params);
$provider = $system_defaults['provider'];
$model    = $system_defaults['model'];

Tasks declare UI metadata via the static getTaskMeta() method:

Editable Prompts

Tasks that need an AI provider use resolveSystemModel():

This resolves the effective model from agent-specific configuration, falling back to the global system context defaults.

php
public function getPromptDefinitions(): array {
    return [
        'generate' => [
            'label'       => 'Generation Prompt',
            'description' => 'Prompt used for generation',
            'default'     => 'Generate a {{type}} for: {{context}}',
            'variables'   => [
                'type'    => 'What to generate',
                'context' => 'Input context',
            ],
        ],
    ];
}

Since: v0.41.0

  1. Check datamachine_task_prompts option for a per-task override
  2. Fall back to the default template from getPromptDefinitions()

Tasks with AI prompts can expose editable prompt templates via getPromptDefinitions(). Each prompt has a key, label, description, default template, and named variables for interpolation:

MethodDescription
resolvePrompt(string $key)Get the effective prompt template (override or default)
interpolatePrompt(string $template, array $variables)Replace {{variable}} placeholders
buildPromptFromTemplate(string $key, array $variables)Resolve + interpolate in one call

Resolution chain:

php
// Set an override
SystemTask::setPromptOverride('alt_text_generation', 'generate', 'Custom prompt...');

// Clear all overrides for a task (revert to defaults)
SystemTask::resetPromptOverrides('alt_text_generation');

// Get all overrides
SystemTask::getAllPromptOverrides();

Convenience methods:

Undo System

Override management:

Overrides are stored in the datamachine_task_prompts WordPress option, keyed by task_type then prompt_key.

Opting In

Since: v0.33.0

  1. Returning true from supportsUndo()
  2. Recording effects in engine_data.effects[] during execution

Effect Types

Tasks that modify WordPress content can opt into undo support. The system provides generic handlers for common effect types, so most tasks don’t need custom reversal logic.

Effect TypeWhat It UndoesHow
post_content_modifiedContent changes to a postRestores from WP revision (revision_id in effect)
post_meta_setPost meta updatesRestores previous value or deletes the meta key
attachment_createdMedia library additionsDeletes the attachment (force delete)
featured_image_setFeatured image assignmentsRestores previous thumbnail or removes it

A task supports undo by:

Effect Recording

The base class provides undo handlers for four standard effect types:

php
$effects[] = [
    'type'           => 'post_content_modified',
    'target'         => ['post_id' => 42],
    'revision_id'    => 123,
    'previous_value' => null,  // optional, for meta/featured image
];

Undo Execution

Unknown effect types are skipped (not failed), so tasks with mixed reversible/irreversible effects degrade gracefully.

php
$result = $task->undo($jobId, $engineData);
// {
//     'success'  => true,      // false if any effect failed to revert
//     'reverted' => [...],     // successfully reversed effects
//     'skipped'  => [...],     // unknown effect types
//     'failed'   => [...],     // effects that couldn't be reversed
// }

CLI

bash
# Undo a job's effects
wp datamachine jobs undo <job_id> [--task-type=<type>] [--dry-run] [--force]

SystemAgentServiceProvider

During execution, tasks record effects as an array in engine_data:

Effects are reversed in reverse order (last effect undone first). The undo method returns a structured result:

Task Registration

Source: inc/Engine/AI/System/SystemAgentServiceProvider.php Since: v0.22.4

Task KeyClass
agent_callAgentCallTask
dispatch_messageDispatchMessageTask
emit_data_packetsEmitDataPacketsTask
image_generationImageGenerationTask
image_optimizationImageOptimizationTask
alt_text_generationAltTextTask
internal_linkingInternalLinkingTask
daily_memory_generationDailyMemoryTask
meta_description_generationMetaDescriptionTask
retention_*Retention cleanup task classes

Action Scheduler Hooks

HookHandlerDescription
datamachine_task_process_batchhandleBatchChunkProcesses a batch chunk
datamachine_system_agent_set_featured_imagehandleDeferredFeaturedImageRetries featured image assignment (up to 12 × 15s = 3 minutes)
datamachine_recurring_<schedule_id>closure → TaskScheduler::schedule()One hook per registered recurring schedule. Fires on the cadence defined by the schedule and enqueues a DM workflow job for the bound task.

Recurring Task Schedule Management

Registers all task infrastructure on instantiation:

  • If the schedule’s enabled_setting resolves to true and no AS action is pending → schedule via RecurringScheduler::ensureSchedule().
  • If the setting resolves to false → unschedule.

Hooks the datamachine_tasks filter to register built-in task types:

SystemTaskStep

Schedules are registered separately from task handlers via the datamachine_recurring_schedules filter (see recurring-scheduler.md). On action_scheduler_init the service provider reconciles every registered schedule with Action Scheduler:

Recurring hooks are schedule-scoped because one task can have multiple schedules with different params or cadences. Task-scoped legacy hooks (datamachine_recurring_<task_type>) are unscheduled when the schedule-scoped hook is reconciled.

Source: inc/Core/Steps/SystemTask/SystemTaskStep.php

How It Works

  1. Reads flow_step_settings.task_type to determine the task type
  2. Creates a child DM job for independent tracking
  3. Injects pipeline context (e.g., post_id from a preceding Publish step) into task params
  4. Executes the task handler synchronously
  5. Reads the child job result and returns it as a DataPacket

Configuration

A pipeline step type that bridges system tasks into the pipeline engine. This allows any system task to be used as a step in a pipeline workflow.

  • Task Type (select dropdown, stored as task_type) — chooses from registered task types via TaskRegistry
  • Params (JSON editor) — task-specific parameters, defaults to {}

Step Type: system_task Position: 70

Settings

Configured via the pipeline step UI with two fields:

Bundle, workflow, and agent-generated configs must use task_type.

Built-In Tasks

DailyMemoryTask

Source: inc/Core/Steps/SystemTask/SystemTaskSettings.php

Defines the admin UI fields. The task dropdown is populated from TaskRegistry::getHandlers(), using each task’s getTaskMeta()['label'] for display.

Type: daily_memory_generation Source: inc/Engine/AI/System/Tasks/DailyMemoryTask.php Undo: No

PropertyValue
Settingdaily_memory_enabled
TriggerDaily at midnight UTC (cron)
Manual runYes
Promptsdaily_memory

InternalLinkingTask

Automated MEMORY.md maintenance. The task gathers same-day job/chat context into activity_section, performs deterministic overflow archiving for very large files, and otherwise uses the single daily_memory prompt to split persistent knowledge from session-specific content. Safety and conservation checks prevent lossy rewrites.

See Daily Memory System for complete documentation.

PropertyValue
Settinginternal_linking_auto_enabled
TriggerManual (via CLI or ability)
Manual runNo
Promptsgenerate
Default links per post3

Type: internal_linking Source: inc/Engine/AI/System/Tasks/InternalLinkingTask.php Undo: Yes (post_content_modified via WP revision, post_meta_set)

  1. Get post categories and tags
  2. Parse post into core/paragraph blocks
  3. Find related posts scored by taxonomy overlap + title similarity
  4. Filter out posts already linked in the content
  5. For each related post, find a candidate paragraph and send to AI with linking instructions
  6. Validate the AI inserted a link (URL detection)
  7. Apply block replacements and record effects for undo
  8. Store link metadata in _datamachine_internal_links post meta

MetaDescriptionTask

Semantically weaves internal links into post content. Finds related posts via shared taxonomy terms (categories and tags) with title similarity scoring. For each related post, identifies a candidate paragraph block and uses AI to insert an anchor tag naturally into the text via block-level editing (ReplacePostBlocksAbility).

Process:

PropertyValue
Settingmeta_description_auto_generate_enabled
TriggerManual
Manual runNo
Promptsgenerate
Max length155 characters

AltTextTask

Type: meta_description_generation Source: inc/Engine/AI/System/Tasks/MetaDescriptionTask.php Undo: Yes (post_meta_set — restores previous excerpt)

Generates AI-powered SEO meta descriptions for WordPress posts. Gathers post title, content excerpt (up to 1500 characters), categories, and tags as context. Normalizes the AI response (strips quotes and markdown formatting, truncates at word boundary to 155 characters) and saves to post_excerpt.

PropertyValue
Settingalt_text_auto_generate_enabled
TriggerAuto on image upload (event)
Manual runYes
Promptsgenerate

ImageGenerationTask

Type: alt_text_generation Source: inc/Engine/AI/System/Tasks/AltTextTask.php Undo: Yes (post_meta_set — restores previous alt text)

Generates AI-powered alt text for WordPress image attachments using a vision model. Sends the actual image file (with MIME type) plus contextual information (attachment title, caption, description, parent post title) to the AI. Normalizes the response (capitalizes first character, ensures trailing period) and saves to the _wp_attachment_image_alt post meta.

  • featured — sets as the post’s featured image. If the pipeline hasn’t published the post yet, schedules a deferred retry (up to 12 × 15s = 3 minutes).
  • insert — inserts a core/image block into the post content, using smart auto-placement to find the largest gap between existing image blocks.
PropertyValue
SettingNone (always available)
TriggerAI tool call
Manual runNo
PromptsNone
Max attempts24
JPEG quality85

ImageOptimizationTask

Type: image_generation Source: inc/Engine/AI/System/Tasks/ImageGenerationTask.php Undo: Yes (attachment_created, featured_image_set, post_content_modified)

Handles async image generation through the Replicate API. Polls a prediction ID for status (startingprocessingsucceeded/failed/canceled), rescheduling itself every 5 seconds up to 24 attempts (~120 seconds). On success, downloads the image, converts to JPEG (quality 85), and sideloads into the WordPress media library. Supports two modes:

PropertyValue
SettingNone (default disabled)
TriggerOn-demand via CLI or ability
Manual runNo
PromptsNone (not an AI task)

AgentCallTask

Type: image_optimization Source: inc/Engine/AI/System/Tasks/ImageOptimizationTask.php Undo: Yes (attachment_file_modified, file_created)

Compresses oversized images and generates WebP variants using WordPress’s native image editor (Imagick or GD). No external API dependencies. Follows a diagnose-then-fix pattern: ImageOptimizationAbilities::diagnoseImages() identifies issues, and this task fixes individual images. Compresses JPEG/PNG/WebP in-place at a configurable quality level, then optionally generates a .webp sibling file.

PropertyValue
SettingNone (always available)
TriggerOn-demand via CLI, REST, or pipeline step
Manual runYes
PromptsNone (not an AI task)

Task Registration

Type: agent_call Source: inc/Engine/AI/System/Tasks/AgentCallTask.php Undo: No

php
add_filter('datamachine_tasks', function(array $tasks): array {
    $tasks['my_custom_task'] = MyCustomTask::class;
    return $tasks;
});

Dispatches a structured agent invocation through a target transport. Webhook fire-and-forget delivery preserves the historical agent ping behavior under the generic agent_call contract. When dispatched as a pipeline step via SystemTaskStep, it can forward pipeline context and use queue modes so one configuration can be reused across queued runs.

Architecture Diagram

php
CLI                    Pipeline Engine            AI Tool Call
                     |                          |                         |
                     v                          v                         v
              TaskScheduler              SystemTaskStep              TaskScheduler
                      |                          |                         |
                      v                          v                         v
              getWorkflow() ----> system_task step <----- TaskRegistry
                      |                          |
                      v                          v
              execute-workflow             executeTask()
                                                 |
                                                 v
                                           SystemTask body
                                                 |
                    +----------------------------+-------------------+
                    |                            |                   |
                    v                            v                   v
             completeJob()                 failJob()          reschedule()
                    |                            |                   |
                    v                            v                   v
              Jobs table                   Jobs table        Action Scheduler
            (engine_data)                (failed status)     (retry in N sec)

Source Files

FilePurpose
inc/Engine/AI/System/Tasks/SystemTask.phpAbstract base class with job lifecycle, undo, and prompt management
inc/Engine/AI/System/SystemAgentServiceProvider.phpTask registration, Action Scheduler hooks, schedule management
inc/Engine/AI/System/Tasks/DailyMemoryTask.phpDaily memory synthesis and MEMORY.md cleanup
inc/Engine/AI/System/Tasks/InternalLinkingTask.phpAI-powered internal link insertion
inc/Engine/AI/System/Tasks/MetaDescriptionTask.phpAI-powered SEO meta description generation
inc/Engine/AI/System/Tasks/AltTextTask.phpAI-powered image alt text generation
inc/Engine/AI/System/Tasks/ImageGenerationTask.phpAsync image generation via Replicate API
inc/Engine/AI/System/Tasks/ImageOptimizationTask.phpImage compression and WebP generation
inc/Engine/AI/System/Tasks/AgentCallTask.phpSend structured agent invocation payloads
inc/Core/Steps/SystemTask/SystemTaskStep.phpPipeline step type bridging system tasks
inc/Core/Steps/SystemTask/SystemTaskSettings.phpAdmin UI settings for the SystemTask step