Appearance
Scheduled agent tasks
Agent-controlled screenshots
For new tasks, the v3 runtime provides Playwright CLI and the opencloud-browser skill. Omit the manifest capture property when the Agent should navigate, dismiss cookie banners, wait or scroll, take a screenshot, upload it, and call the result Function. Describe those actions in the task instructions. URL field names are app-defined and follow inputSchema. Store the returned managed File ID and include it as screenshotFileId in the receipt alongside the stable submissionKey. Confirm real task completion and saved image contents; synthetic development invocations alone do not test browser interaction. Browser sessions are ephemeral within the isolated run; retain uploaded File and operation references for recovery.
Existing capture: website_screenshot declarations keep their legacy automatic pre-capture behavior and require input.url. They cannot dismiss a cookie banner. Remove that property when deliberately migrating an existing task to agent-controlled browsing; keep its result Function and stored evidence compatible. No stored-manifest migration is required for the additive workflow.
Server SDK 2.5.0 lets a short Function submit work to an independent app Agent run. It returns { runId } after durable admission. Work runs when app and provider capacity are available, even with the main chat closed. Other app work waits in the existing queue; the main model is not woken to delegate.
Declare agentTasks in the manifest, targeting a declared result Function:
yaml
runtime:
sdk:
version: 2.5.0
agentTasks:
- name: inspect-competitors
title: Check competitor campaigns
instructions: Use playwright-cli and the opencloud-browser skill to visit each URL, reject optional cookies, capture the visible offer, upload the PNG, and submit campaign observations with screenshotFileId and submissionKey.
inputSchema:
type: object
properties:
url: { type: string }
competitorId: { type: string }
required: [url, competitorId]
additionalProperties: false
resultFunction: record-observation
maxAssignments: 10
timeoutSeconds: 900
maxAttempts: 2
cron:
- name: daily-competitors
schedule: "0 9 * * *"
timezone: Europe/Prague
function: select-competitors
enabled: trueTasks use the same admission policy as ordinary Agent runs and reserve against the organisation's remaining weekly AI spend. Scheduled tasks do not consume an employee's interactive allowance. Already admitted runs retain their captured payer, weekly period and budget.
Weekly periods start Monday at 00:00 in the organisation's configured timezone. Organisation, employee and automation allowances use USD. Function inference shares the organisation's weekly AI spend pool without consuming an employee allowance. Provider usage settles the reservations; unknown usage remains reserved. Timeouts, cancellation and concurrency controls still apply. Stopping a run preserves its source files and accepted results; provider responses already in flight can report usage after cancellation is requested.
Declare both Functions as usual. The cron Function selects inputs and returns:
ts
return agentTasks.start("inspect-competitors", {
assignments: competitors.map(item => ({
id: item.id,
input: { competitorId: item.id, url: item.url },
})),
}, { idempotencyKey: "daily-competitors" });Cron supplies its trusted occurrence identity, overriding this key. Owner Function calls use their explicit stable key. Repeating a key with different work conflicts. Inputs support bounded strings, numbers and booleans, up to 50 assignments and 32 input fields. Empty batches should return without submission. agentTasks.get(runId) reads status.
The app needs an existing Agent conversation with a configured provider and the app-owner Codex harness (opencloud-codex-ai-sdk-harness-v3). Admission is production-only and owner-authorized. Dev Functions, anonymous users and other app members cannot spend Agent resources through this API. Workers cannot submit more tasks. They have the existing exact-app owner authority: resultFunction is an intended result path, not a Function allowlist.
Legacy automatic capture uses public HTTPS on port 443, a fresh browser profile, fixed 1440×1000 PNGs, a 30-second page limit, and private-network restrictions. The runtime supplies capture metadata and stable assignment submission keys. The worker uploads screenshots with sprout file upload and submits JSON with sprout function invoke --input-file. No custom submission tool is needed.
For either screenshot workflow, the result Function must explicitly accept submissionKey and screenshotFileId in its input schema. Function object schemas reject undeclared fields: omitting screenshotFileId rejects a valid worker upload before the handler executes. Declare it as schema.uuid(), resolve it with files.info({ id: input.screenshotFileId }), validate that it is a managed PNG, and persist the File ID with the observation. Include the same ID in every successful receipt, including unchanged results and recovered idempotent submissions. Do not drop the field to make invocation succeed.
Test this boundary before release using an uploaded PNG and the complete worker payload against the actual result Function in development. Assert both the persisted observation and the full receipt below. Also test an unchanged observation and replay of a submission key: neither may create a duplicate change event. A test payload without the screenshot field misses this boundary.
A new result Function returns this generic receipt only after its data is committed. Return the same receipt when replaying a submission key:
json
{
"schemaVersion": 2,
"submissionKey": "the-assignment-submission-key",
"resultId": "app-evidence-row-id",
"committed": true,
"screenshotFileId": "33333333-3333-4333-8333-333333333333"
}Use the outer assignment's platform-issued submissionKey, not an app-defined key nested inside assignment.input. Keep screenshotFileId for image results. Do not include extra fields in this strict receipt; store app-specific data in the result row. The platform matches the successful Function operation to the exact app, run, result Function and submission key.
For user-scoped Files, declare the result Function with access: "user" and use the authenticated caller's identity and normal RLS. The task's owner CLI invocation supplies that identity. access: "system" deliberately has no user identity and cannot read user-scoped Files; do not make the Function public or weaken RLS to bypass this boundary.
Existing campaign Functions may continue returning the version-1 receipt:
json
{
"schemaVersion": 1,
"submissionKey": "the-assignment-submission-key",
"observationId": "app-observation-id",
"outcome": "changed",
"calendarCommitted": true,
"notification": "queued",
"screenshotFileId": "33333333-3333-4333-8333-333333333333"
}outcome is changed, unchanged, or no_campaign; notification is queued or not_needed. Commit observation and calendar writes before returning. Queue notifications separately with durable, idempotent intent. Queued is not proof of delivery. Failed captures preserve the previous campaign.
The platform reconciles exact-app, exact-run Function operations. Legacy automatic captures also check screenshot Files against runtime capture hashes. Agent-controlled captures rely on the result Function's validation and saved evidence, so independently inspect the image content. Agent prose never proves a save. The card separates execution from result reconciliation and opens the existing details panel. Stop preserves already accepted operations and saved observations. Recovery retains receipts and verifies screenshot bytes before reuse; unavailable retained evidence needs attention.
An independent task waits for the app's active builder to release the workspace. If a builder admits a task to verify a new deployment, it must finish its turn and report that task verification is pending. Polling or sleeping inside that builder cannot make the queued task run. After the builder ends, verify the task receipt and saved data; admission alone is not a successful outcome.
Keep result Function inputs backward-compatible during redeployment: invocation uses the current active Function. Task declarations are snapshotted; Function execution is not revision-pinned. Asynchronous result-handler receipts are not part of this first version. Execution timeout applies per bounded attempt.
Use CLI 3.11.0 or later for local validation, bundling and development of these declarations. Select SDK 2.5.0 explicitly: the CLI retains SDK 2.3.0 as its default for compatibility with older installations. Server-side drafts remain available on an updated platform. Workers use the existing upload/invoke commands.