Skip to content

Track ​

This page explains scheduled web tasks, check records, and the compatibility boundary between the current backend and the Node SDK.

Version and deployment boundary

npm @qoniai/qoni@0.9.0 uses the legacy /track/monitors route, which returned 404 in the 2026-10-08 gray acceptance test and cannot be used with the current /track/tracks backend. HTTP below describes that backend contract; Node examples describe an unpublished repair candidate (Unreleased, targeting 0.10.0), not released 0.9.0 functionality. Check your deployment's OpenAPI and SDK release notes before use. This is a breaking change and must not be described as available in npm 0.9.x. Downloads remain pinned to official 0.9.0 and do not contain the candidate.

What it solves ​

Track persists a schedule and repeats web checks through a DoAnything session. Use it for vendor pricing, policy, or partner portal patrols. Put target URLs, extraction requirements, and change criteria in natural-language instructions; your application must still verify the output against business requirements.

Core capabilities ​

The current backend supports scheduled creation, definition reads, pause/resume, immediate execution, recent check review, and soft deletion. Scheduling and task-reference boundaries are explained below.

Typical scenarios ​

When to use it ​

Use DoAnything for one task and WebSearch for public search. Current Track has no legacy extraction DSL, trigger DSL, notification channel, or alignment questions, and does not guarantee a notification per check.

Create a Track ​

http
POST /api/v1/projects/{pid}/track/tracks
Authorization: Bearer wa_...
Content-Type: application/json
HTTP fieldDescription
instructionsRequired, nonempty task instructions, up to 4000 characters; include target URLs and check requirements here
titleOptional title, up to 120 characters
scheduleRequired; neither inferred from instructions nor supplied by an SDK default

Choose one schedule:

  • Interval: {"every_seconds":3600}, integer seconds from 600 to 30 days (2592000 seconds).
  • Daily: {"daily_at":"09:00","tz":"Asia/Singapore"}, 24-hour HH:MM and a time zone; the backend starts 0–30 minutes before that time, not necessarily at 09:00.

Arbitrary cron, target_urls, profile_id, extraction_schema, trigger_dsl, stop_condition_dsl, tick_instructions, and notify_channel are unsupported. Legacy fields cannot be copied to the new resource.

Node SDK ​

The example below applies only to the unpublished repair candidate.

High-level prompt maps verbatim to HTTP instructions. The historical handle name MonitorHandle remains, representing the new Track resource.

ts
// Unpublished repair candidate; npm 0.9.0 does not support this backend contract.
const monitor = await qoni.track.create({
  token,
  prompt: "Check the title of https://example.com/ for changes; return the title and source URL.",
  title: "Example page patrol",
  schedule: { kind: "daily", at: "09:00", tz: "Asia/Singapore" },
});

const current = await monitor.get();
const recent = await monitor.runs({ limit: 10, offset: 0 });
console.log(recent);

Creation immediately starts the first check (kind: first_look). The example only reads the definition and checks; it does not call runNow() immediately. checks reports running for an in-flight check and done for successful completion; other terminal states are failed/expired/canceled. This differs from the unified RunResult.status value succeeded.

Before a manual execution, wait for the first check's exact run ID to reach a terminal state and verify that no check is in flight. A race can still occur between that read and runNow(): on HTTP 409 task_in_progress, retain the existing check, keep reading its status, and let the user explicitly request a later manual execution. Do not retry automatically or count 409 as success.

For an interval use schedule: { kind: "interval", intervalSeconds: 3600 }. The candidate validates schedule bounds locally and rejects cron, legacy DSL, targetUrls, profileId, notifications, and other unsupported fields with QoniUnsupportedError, without silently ignoring or converting them.

MethodCandidate behavior and boundary
get()Read the Track definition
pause() / resume()Set status: paused/active; pausing does not cancel a running task
refine(patch)Change only title/schedule, preserving instructions; create a new Track for a new intent
runNow()Return a real trackId/sessionId/runId task reference; returns 409 task_in_progress while first_look or another check is in flight; HTTP 202 means accepted, so query the check's terminal state
runs({ limit?, offset? })Read the most recent 50 checks, newest first; parameters paginate locally within that window, not all history
run(runId)Find the exact run ID in the recent 50 checks; fail if absent, without falling back to arbitrary DoAnything task reads
delete()Soft-delete and stop future scheduling; do not stop the current run

There is no current Track SSE or question/intervention endpoint. Candidate events() (on iteration), interactionHandle(), track.api.events(), and track.api.intervene() throw QoniUnsupportedError locally with zero HTTP. Track scopes cannot authorize DoAnything interactions; obtain separate DoAnything authorization and handle the corresponding task.

On the first get() readback, capture current.lastTaskId (HTTP last_task_id) once as the original first-look ID. checking says whether the latest check is still in flight (backend pending/running/waiting are exposed as running). checking: false alone does not prove business success: read the original ID's terminal status and output in checks. Do not replace the captured first-look ID after pause/resume or a later readback.

Check records ​

HTTP checks.items contains only the latest 50 records. SDK runs() converts field names to camelCase while preserving status/outcome values:

HTTP field (SDK field)Output and boundary
run_id (runId)The exact task ID for this check; retain it for subsequent reads
kindfirst_look, scheduled, or manual
statusIn flight: running; terminal: done/failed/expired/canceled
outcomechanged, same, or needs_you; may be null without a report. needs_you does not provide a Track question-reply API
headlineReport summary; older records may fall back to the answer's first line; may be null
answerCheck answer, possibly null; verify its content and sources
failureFailure details for failed/expired, otherwise null; empty failure details do not imply success
created_at/ended_at (createdAt/endedAt)Creation/end timestamps; ended_at is null while unfinished
stepLatest action label for an in-flight check; may be null without a record

Failures and automatic pause ​

Response/conditionHandling
Create: 409 track_limitAt most 20 retained Tracks per project/user, including paused Tracks; delete an unneeded Track to release capacity
Execute: 409 task_in_progressThe original task is still in flight; read that ID without automatic retries
422 invalid_trackService validation found an invalid schedule or task definition; fix the input. Request-model field/type validation may also return 422
404 track_not_foundThe Track is absent, soft-deleted, or outside the caller's visible scope; do not substitute another resource ID
3 consecutive checks without a track_reportThe scheduler automatically pauses on a subsequent scheduling check; read the state and inspect the conversation/failures before deciding to resume

A successful report resets the no-report counter. done does not replace report and business-output verification. A missing run(runId) record in the recent 50 window is the candidate SDK's local not_found with no HTTP status; distinguish it from backend track_not_found.

REST lifecycle ​

http
GET    /api/v1/projects/{pid}/track/tracks
GET    /api/v1/projects/{pid}/track/tracks/{track_id}
PATCH  /api/v1/projects/{pid}/track/tracks/{track_id}
DELETE /api/v1/projects/{pid}/track/tracks/{track_id}
POST   /api/v1/projects/{pid}/track/tracks/{track_id}/run_now
GET    /api/v1/projects/{pid}/track/tracks/{track_id}/checks

PATCH accepts resource fields directly, for example {"status":"paused"}, without the old action/patch wrapper. HTTP can update instructions/title/schedule/status; the SDK's high-level refine() exposes only title/schedule to preserve intent. checks returns items, at most the recent 50 records; there is no legacy /runs/{run_id} full-history detail endpoint.

Checkpoint and next step ​

Read back the definition and schedule after creation. After runNow(), use the exact returned run ID to query checks, wait for a terminal state (done for success), then verify the output and sources. A missing check record or a 202 response alone does not prove success. After deleting the Track, still reconcile the current task's status.

Until the candidate is released, changing a parameter cannot fix the legacy route in published 0.9.0. See Qoni SDK for file artifacts and Profiles for login-state reuse boundaries.