Jobs

Jobs

Jobs automate work by firing agent actions on a schedule, workspace event, or incoming webhook — another way to make agents work besides tickets.

Jobs

A job is a workflow rule that runs automatically when a trigger condition is met. The trigger can be a cron schedule, a workspace event, or an inbound webhook. When triggered, a job dispatches an action — creating a ticket, assigning an agent task, or sending a notification.

If tickets are "event-driven" (someone files a request, reports a problem, or asks for a change), jobs are "time-driven" — they fire at a set time without human intervention. Both are ways to make agents work; the only difference is what triggers them.

Jobs live under Jobs in the sidebar.

Trigger Types

TypeFires When
ScheduleA cron expression matches the current time.
EventA specific workspace event occurs (e.g. a ticket status change).
WebhookAn HTTP POST hits the job's unique URL.

A single job has one trigger type.

Action Types

ActionWhat it does
Create ticketOn trigger, uses the job's Instruction as the ticket description, creates and assigns a ticket, then starts the executor. This is similar to automatically carrying out a manual create-and-assign-ticket flow, and the work is tracked in its own ticket.
Run OnlyDoes not create a ticket; directly starts one independent agent task using the Instruction. It is similar to sending that instruction to the agent in chat, but it is not a chat message or conversation turn; it belongs to the job run.
Send notificationSends an in-app or inbox notification to the specified workspace members; it does not start an agent task.

The action type can be changed from the job detail page. The Instruction field is shared across all action types:

  • Create ticket — becomes the ticket description
  • Run Only — becomes the agent task instruction
  • Send notification — used as the notification message if no message is set in the action config

Action Configuration

Each action type has its own configuration fields, accessible in the job detail sidebar.

Create ticket

FieldDescription
Ticket titleTitle of the ticket to create. Defaults to Job: <name> if empty.
PriorityTicket priority: low / normal / high / urgent (leave empty for normal).
ProjectProject to assign the ticket to.
Agent / TeamAgent or team to receive the ticket (set in the Agent Assignment section).

Run Only

FieldDescription
Agent / TeamAgent or team to dispatch the task to (set in the Agent Assignment section).

The task instruction comes from the job's Instruction field.

Team assignees: Both action types support assigning to a team instead of a single agent. When a team is assigned, the platform picks the most available team member at dispatch time.

Send notification

FieldDescription
MessageNotification message. Falls back to the Instruction field if empty.

Job Owner

Every job has an owner — the member who created it. The owner is shown in the job detail sidebar and controls who can edit or delete the job when the workspace uses self-only permission rules.

OperationRequired ScopeOwnership Rule
Create jobjobs:write
Edit jobjobs:writeSelf-only: only the job owner can edit
Delete jobjobs:deleteSelf-only: only the job owner can delete

Create a Job

  1. Open Jobs in the sidebar
  2. Click New job
  3. Fill in:
    • Name — descriptive label (Daily health check, Slow query weekly report, On-call alert)
    • Description — optional note explaining what this job does and why it exists
    • Goal — optional target outcome or success criteria for the job
    • Trigger type — Schedule, Event, or Webhook
    • Action type — what to do when triggered
  4. Click Create
  5. On the detail page, set the Instruction and any action-specific config in the sidebar

Schedule Triggers

A schedule trigger uses a standard 5-field cron expression: minute hour day-of-month month day-of-week. Times are evaluated in the workspace's timezone.

Examples:

CronWhat it does
0 9 * * 1Every Monday at 9:00
*/15 * * * *Every 15 minutes
0 0 1 * *Midnight on the first of every month
0 17 * * 1-5Weekdays at 17:00
30 8 * * 6,0Saturdays and Sundays at 08:30

The platform's cron scheduler polls for due triggers. Drift can be a few seconds — do not use schedule triggers for hard-real-time work.

Event Triggers

Event triggers subscribe to real-time workspace lifecycle events (such as ticket updates, agent task completions, new comments, or runtime disconnects) and execute jobs automatically when declared filter criteria are met.

Using event triggers, you can build autonomous, event-driven pipelines — for instance: "When a high-priority bug ticket transitions to Done, automatically assign an agent to conduct post-incident review" or "When a GPU runtime goes offline, automatically create an incident ticket and notify on-call engineers".

Supported Events and Actions

Event Type (event)DescriptionSupported Actions (actions)
ticketTicket lifecycle eventscreated, updated, deleted
agent_taskAgent task execution statecompleted, failed, interaction, created, updated
commentTicket comments & repliescreated, updated, deleted
runtimeDaemon execution nodesoffline, register, updated

4-Tier Boolean Filter Logic

The event trigger engine evaluates rules using a 4-tier boolean model:

  1. Between Rule Cards — OR: A single trigger can define multiple event rules; matching any one rule fires the job.
  2. Action List (actions) — OR: Within a single rule, matching any listed action satisfies the action check (e.g., actions: ["created", "updated"]).
  3. Conditions Map (conditions) — AND: Within a single rule, all declared condition keys must simultaneously match.
  4. Array Enum Values — OR: If an individual condition field is provided as an array, matching any element is considered a match (e.g., priority: [3, 4] matches High or Urgent).

Common Condition Fields and Enum References

Inside the conditions object, use structured payload properties:

  • ticket:
    • status: Status enum (0 backlog, 1 todo, 2 in_progress, 3 in_review, 4 done, 5 blocked, 6 cancelled)
    • priority: Priority enum (0 none, 1 low, 2 normal, 3 high, 4 urgent)
    • assigneeType: Assignee type (0 member, 1 agent, 3 team)
    • projectId: Associated project UUID
    • labels: Array of label names (subset match)
  • agent_task:
    • status: Task status (10 pending, 20 queued, 30 running, 40 completed, 50 failed, 60 cancelled)
    • failureReason: Failure code (e.g., runtime_process_crashed, run_timeout)
    • agentId: Executing agent UUID
  • runtime:
    • status: Node status (0 offline, 1 online, 2 busy, 3 error)
    • provider: Provider CLI type (e.g., claude, kimi, codex)

Self-Trigger Prevention

The job engine includes built-in cycle detection: downstream events created by a job's own actions (such as creating tickets, posting comments, or launching tasks) never re-trigger that same job, ensuring stability and preventing infinite loops.

[!NOTE] Supported Action Types: Event triggers are designed for reactive automation and instant workflows, supporting assign_agent and send_notification actions. If a formal ticket needs to be created upon an event, instruct the assigned agent to dynamically call mopheus ticket create CLI with context extracted from the event payload.

CLI Configuration Examples

Event triggers can be declared and updated via the Mopheus CLI:

# 1. Trigger when a high-priority ticket is marked done OR when an agent task crashes
mopheus job trigger-add <job-id> \
  --kind event \
  --label "Incident Resolution & Crash Watchdog" \
  --event-filter '[
    {
      "event": "ticket",
      "actions": ["updated"],
      "conditions": {
        "status": 4,
        "priority": [3, 4]
      }
    },
    {
      "event": "agent_task",
      "actions": ["failed"],
      "conditions": {
        "failureReason": "runtime_process_crashed"
      }
    }
  ]'

# 2. Attach an event trigger using an external JSON rule file
mopheus job trigger-add <job-id> --kind event --event-filter-file ./event-rules.json

# 3. Update event filter rules on an existing trigger
mopheus job trigger-update <job-id> <trigger-id> --event-filter '[{"event":"comment","actions":["created"]}]'

# 4. Introspect workspace supported event schemas and template variables
mopheus job event-schema

Web Console Visualization: Configured event triggers render on the Job Detail → Triggers tab with visual status badges, explicit AND / OR connectors, localized enum labels, and raw JSON export.

Webhook Triggers

A webhook trigger gives the job a unique URL. The URL is shown in the Webhook tab on the job detail page:

POST https://<server_url>/api/v1/webhooks/jobs/<token>

Send an HTTP POST with a JSON body to that URL and the job fires. The token is generated when the trigger is created and is part of the URL — no additional Authorization header is required for basic usage.

Authentication Methods

MethodHow it works
URL TokenThe secret is embedded in the URL path. Anyone with the URL can trigger the job.
HMAC SigningAn additional signing secret is configured. Every request must include a valid signature header.

HMAC Signing

To require signature verification, add a Signing Secret to the trigger. The server will reject any request that does not include a valid X-Webhook-Signature (or X-Hub-Signature-256 for GitHub compatibility) header.

The signature format is sha256=<hex-encoded HMAC-SHA256 of the raw request body>.

curl example:

BODY='{"event":"test"}'
SECRET="your-signing-secret"
SIG="sha256=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')"

curl -X POST "https://<server_url>/api/v1/webhooks/jobs/<token>" \
  -H "Content-Type: application/json" \
  -H "X-Webhook-Signature: $SIG" \
  -d "$BODY"

Python example:

import hmac, hashlib, requests

secret = "your-signing-secret"
body = b'{"event":"test"}'
sig = "sha256=" + hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()

requests.post(
    "https://<server_url>/api/v1/webhooks/jobs/<token>",
    data=body,
    headers={"Content-Type": "application/json", "X-Webhook-Signature": sig},
)

Trigger Expiry

Both schedule and webhook triggers support an optional Expires at date. After this date the trigger is disabled — for webhook triggers, all incoming requests return 403; for schedule triggers, the trigger stops firing. Set an expiry when you want time-limited integrations without manual cleanup.

From the CLI, set the expiry with --expires-at when adding or updating a trigger (accepts RFC3339 or YYYY-MM-DD HH:MM):

# Schedule trigger with an expiry
mopheus job trigger-add <job-id> --kind schedule --cron "0 9 * * 1-5" --expires-at "2026-12-31T00:00:00Z"

Token Rotation

Rotate the URL token from the Webhook tab if it is compromised. Rotating invalidates the old URL immediately — update any upstream callers before rotating.

Enable and Disable

Every job has an enable toggle. Disabled jobs:

  • Do not fire on schedule
  • Reject incoming webhook requests
  • Retain their configuration — re-enabling resumes the workflow without reconfiguration

Agent Readiness

Before executing an action, the job engine checks that the target agent is ready. A dispatch is skipped (not failed) if:

  • The agent does not exist or has been archived
  • The agent has no runtime bound
  • The agent's runtime is offline or in an error state

Skipped runs appear in the run history with status Skipped and a reason. They do not count as failures and do not trigger retries.

Job Runs

Each job has a run history that lists every firing — when it ran, what triggered it, and the outcome. Failed runs show the error reason and can be replayed from the detail page.

StatusMeaning
RunningCurrently executing.
CompletedFinished successfully.
FailedFinished with an error.
SkippedAgent was not ready at dispatch time.

Failures do not retry automatically. If a webhook event is critical, configure the upstream system to retry on non-2xx responses.

Command Line Reference

# List jobs in the active workspace
mopheus job list

# Create a job
mopheus job create \
  --name "Daily health check" \
  --trigger-type schedule \
  --action-type create_ticket \
  --instruction "Connect to production DB, check pg_stat_activity for long-running transactions and lock waits, generate a report" \
  --action-config '{"title":"Daily health check","priority":2}' \
  --cron "0 9 * * 1-5" \
  --timezone "Asia/Shanghai"

# Create a Quartz seven-field schedule: weekdays at 09:00
mopheus job create \
  --name "Weekday report" \
  --trigger-type schedule \
  --action-type create_ticket \
  --cron-dialect quartz \
  --cron "0 0 9 ? * 2-6 *" \
  --timezone "Asia/Shanghai"

# Add a cron trigger to a job
mopheus job trigger-add <job-id> \
  --kind schedule \
  --cron "0 9 * * 1-5" \
  --timezone "Asia/Shanghai"

# Manually fire a job
mopheus job trigger <id>

# Update a job
mopheus job update <id> --instruction "New agent instruction"
mopheus job update <id> --enabled false

# View run history
mopheus job runs <id>

# Delete a job
mopheus job delete <id>

# Manage triggers
mopheus job trigger-list <job-id>
mopheus job trigger-delete <job-id> <trigger-id>
mopheus job trigger-rotate-url <job-id> <trigger-id>

Run mopheus job create --help for the full action config key reference.

For a schedule job, --cron creates the initial trigger. The default standard dialect uses minute hour day-of-month month day-of-week; quartz uses second minute hour day-of-month month day-of-week year. For example, 0 0 9 ? * 2-6 * is Quartz for 09:00 on weekdays, where ? leaves the day-of-month unspecified. --start-at sets the earliest eligible run (default: now), while --expires-at is an exclusive deadline: occurrences at or after it do not run.