- scheduler: added handoff v4 canonical artifacts with explicit artifact, canonicalization, execution-binding, and scheduler-binding versions
- discovery: added Draft 2020-12 schema access for the complete handoff v4 artifact through CLI, JSON-RPC, and the public handoff module
- validation: handoff v4 artifacts now reject missing required identity fields, invalid nested types, and unknown properties before semantic verification
- negotiation: v4 now requires scheduler schema 29 or newer plus an exact live artifact, canonicalization, digest, and binding contract; partial or mismatched runtimes, including contracts with extra keys, fall back to v3
- negotiation: every apply, including basic v0.1 manifests, probes the live runtime so v4 coverage is complete; static fallback enforcement features are disabled until explicitly advertised
- scheduler: complete non-lossy create, replace-style update, null clear, and adopt projections now carry the immutable artifact payload and digest
- scheduler: adoption rebinds the artifact after the final origin is selected, and apply preserves direct-compile hashes for the caller's explicit compile environment while host variables are merged only for scheduler process spawn
- scheduler: direct main and isolated delegation negotiates v4 before compiling and binds its one-off lifecycle before artifact construction; v4 JSON columns use the same undefined-to-null canonicalization as their artifact binding
- scheduler: update and adoption validate the persisted v4 artifact, compiled identity, and current execution projection before preserving runtime overrides; the CLI adapter requests opt-in artifact hydration only after exact v4 negotiation, while legacy-safe listing remains flag-free
- security: JWT, detached-signature, and certificate proofs bind the exact v4 artifact, replay identifier, validity, key, and revocation result
- security: v4 proofs reject inverted validity intervals, bind asserted key IDs to the key or certificate that actually verified, and require an explicit not-revoked result from the runtime checker
- security: JWT artifact claims and trusted context now require the exact
lowercase
sha256:<64 hex>representation before v4 binding can succeed - security: detached-signature and certificate artifact bindings now require the same canonical digest representation, and every v4 proof method accepts replay claims only from an explicit, non-conflicting claimed result
- security: JWKS-provided raw JWK objects are normalized before stable public key identity derivation, while private JWK material remains forbidden
- security: credential handoff compiles to exactly one runtime medium without persisting values, and delegation binds the exact source run and scope
- evidence: the complete AgentCLI evidence payload and verification envelope are available to the scheduler runtime for signed or provider-verified terminal evidence
- evidence: payload and provider-configuration hashes are explicit required nullable fields and are retained in the sanitized scheduler declaration for exact artifact parity while raw provider configuration remains absent
- evidence: persisted declarations must match artifact evidence semantics and hashes; explicitly v4 evidence records require a canonical artifact digest, child records require complete source-run lineage, and terminal status and structured-output hashes must exactly match the surrounding audit record
- validation: v4 command argument counts and aggregate argument digests are recomputed, and every declared evidence block requires a canonical payload hash even when the authored profile omits an explicit payload object
- inspect: added immutable artifacts, runtime events, provider sessions, and credential presentations to the scheduler inspection surface, with every entity enumerated in JSON help and structured command discovery
- conformance: added shared positive and negative v4 fixtures and exact digest parity tests with OpenClaw Scheduler
- examples: added a public scheduler manifest for exercising negotiated v4 apply and schema discovery
- compatibility: handoff versions 1 through 3 and manifest versions 0.1 and 0.2 retain their existing behavior
- scheduler: post-success verification for shell tasks now runs from the task working directory while retaining the runtime-provided execution environment, and expanded verifier commands are checked against the scheduler's storage limit before apply
- tests: added quoted-path, runtime-environment, expanded-length, and cross-version integration regressions for scheduler handoff
- security: manual approvals now bind the canonical manifest and complete effective execution configuration, enforce
approver_scopeandtimeout_s, reject unexpected unsigned records, and fail without writing a grant when signing fails - security: approval checks now run before proof commands, provider calls, sandbox probes, credential materialization, signing, and all other live side effects
- security:
exec --dry-runis now a static preview that performs no proof, provider, network, sandbox, signing, evidence, verification, or audit side effects - security: JWT, detached-signature, and certificate authorization proofs require cryptographic verification and canonical manifest binding;
verify.required: falseno longer permits presence-only or claims-only success - security: evidence uses a complete versioned canonical payload, persists the verification envelope, binds manifest and effective execution metadata, and detects cross-execution transplantation
- security: sandbox, allowed-path, and network restrictions fail closed when unavailable; child processes inherit only a small operational allowlist and require every other ambient variable to be explicitly declared or provider-materialized
- security: identity providers validate configuration before network access, enforce delegation and handoff capabilities, use safer endpoint and file handling, and clean up materialized credentials across failure paths
- validation: v0.2 nested objects reject unknown fields, provider-specific structural validation runs during manifest validation, and the default schema output is JSON Schema Draft 2020-12 with
--legacyopt-in - CLI and JSON-RPC: strict flag parsing rejects unknown, duplicate, missing-value, and misplaced flags; RPC responses use stable result/error envelopes and add read-only targets, paths, audit, approvals, and registry discovery methods
- execution: disabled tasks and branches are skipped by
agentcli run; audit identifiers are collision-resistant and malformed audit lines are skipped with warnings - conversion and merge: v0.1 conversion maps unverifiable legacy attestations to
method: "none"; merge preserves same-version semantics and v0.2 profile collections, rejects mixed manifest versions, and detects conflicting profile definitions - scheduler: live capability values override static fallback values, handoff v3 preserves governed approval and output fields, auto-reject jobs compile disabled, and apply refuses inline
shell.envorshell.stdin - examples: repaired invalid runtime timeout placement and fail-closed proof and credential-cache declarations; all published JSON examples are validated in the test suite
- maintenance: minimum Node version is now 22.13.0 and CI also tests Node 24 with a pinned
openclaw-schedulerintegration checkout - dependencies: pinned patched
brace-expansionandflattedreleases;npm auditreports no known vulnerabilities
- fix:
verifyApprovalSignaturenow performs a tamper check against the storedsignature.signed_payload. Previously the canonical payload was rebuilt from the current grant but then discarded; post-sign edits toapprover,reason,expires_at, ortask_hashfields inapprovals.ndjsonwould not be detected (the ssh provider only checks signature-against-signed_payload). The rebuilt payload is now compared tosignature.signed_payloadand divergence returnsverified: falsewith reason "grant fields do not match signed payload (possible tampering)" - tests: new tamper-detection test (ssh-signed grant, then mutate
approver/reason/expires_atin the stored record and assert each edit fails verification) and new multi-workflow disambiguation tests (grantApproval throws without--workflowon multi-workflow manifests, throws on unknown workflow id, and correctly scopes grants per workflow with distinct task hashes) - docs: clarify that
contract.max_cost_usdis enforced by runtimes that track cost-attributed operations; declarative-only for shell-targetagentcli exec(no cost signal to enforce against) - docs: add recommendation that production-grade isolation on Linux / Windows should run
agentcli execinside a container until native OS sandbox adapters ship; manifest declaration remains valid metadata
- fix: concurrent
agentcli execcalls on the same gated task no longer double-consume a single approval. A newclaimApprovalprimitive performs find-then-consume atomically under an fs-lockfile at~/.agentcli/state/approvals.ndjson.lock(openSyncwx+Atomics.waitbackoff); stale locks (older than 30s) are broken;approval_lock_timeoutis raised after 5s of contention enforceApprovalGateinsrc/exec.jsnow callsclaimApprovalinstead of the separatefindValidApproval+consumeApprovalpair; signature verification still runs after the atomic claim and a bad signature refuses execution (the grant is already consumed and its use is audited)claimApprovaladded to the barrel export (src/index.js)- 4 new concurrency tests: worker-thread race (N=8 parallel claims, exactly 1 winner), distinct-grant parallelism, stale-lock recovery, lock-timeout behavior
- local approval gate enforcement in
agentcli exec: tasks withapproval.policy: "manual"refuse to execute unless a matching, unconsumed, unrevoked, unexpired approval record is present (detailedcode: approval_required; closederror_type: validation_error) approval.policy: "auto-reject"refuses execution even when an approval record exists (detailedcode: approval_auto_rejected; closederror_type: validation_error)- approval grants are bound to a canonical task hash over
{workflow_id, task_id, shell.program, shell.args, shell.cwd, identity.ref, approval.policy, approval.risk_level}; drift in any of those fields invalidates prior approvals --dry-runbypasses the approval gate (no approval consumed, no gate enforced)- successful gated executions include
approval_used: {approval_id, approver, reason, risk_level, granted_at, expires_at, signature_verified, signature: {method, key_fingerprint}}in both the result payload and the audit record - approvals are single-use, consumed before
spawnSync(fail-closed: crashed executions still consume the grant) - new
agentcli approve <manifest> <task-id>command with--workflow,--by,--reason,--ttl-s,--signer,--signing-keyflags; grants ssh-signed by default over canonical approval payload - new
agentcli approvals listcommand with--status pending|consumed|expired|revoked|all,--workflow,--taskfilters - new
agentcli approvals revoke <approval-id>command with--byand--reasonflags - new
--approval-id <id>flag onexecto target a specific pending grant when more than one matches - new append-only state file at
~/.agentcli/state/approvals.ndjson(grant, consume, revoke events); path exposed byagentcli paths - new module
src/approvals.jsexportsgrantApproval,listApprovals,findValidApproval,consumeApproval,revokeApproval,computeTaskApprovalHash,approvalPolicyRequiresApproval,approvalPolicyAutoRejects,verifyApprovalSignature - approval signature verification reuses existing ssh allowed-signers chain (
~/.agentcli/state/allowed_signers); tampered grants are refused with detailedcode: approval_signature_invalidand closederror_type: validation_error - scope: local single-machine enforcement only; durable multi-actor cron-triggered approvals remain owned by openclaw-scheduler
- identity step-up verification for sensitive commands via signed JWT authorization proofs
- actor context module (
buildActorContext,buildStepUpContext) for canonical actor chain metadata - JWT verifier expanded: JWKS URI fetch with caching, key selection by
kid/alg, issuer and audience validation,verify.requiredenforcement, audit-safe claim extraction - OPA authorization request now supports
actorandstep_upinclude fields - evidence payload and attestation now include
actor_context stripe-identity-step-up.jsonexample with matching OPA policy and testing guide- pre-execution failure audit records now include
declared_identityandactor_context auth_profilefield on tasks for scheduler dispatchsfdc-ops.jsonexample: Salesforce CLI with org status, SOQL queries, metadata, deployment validation, and deploy with approvalservicenow-ops.jsonexample: ServiceNow CLI with incidents, P1 monitoring, change requests, problems, CMDB, and incident creation
agentcli runcommand for local shell-only workflow DAG execution with trigger edges, contains:/regex: conditions, and on_failure handlers evaluated in-processagentcli signing providerscommand lists registered signing providers and their attestation methods- delegation capability warnings surfaced in scheduler dispatch responses (previously silently swallowed)
- neon-ops.json example: neonctl with readonly/admin identity split, branch lifecycle pipeline, operations monitoring
- supabase-ops.json example: Supabase CLI with readonly/deploy split, db-push -> functions-deploy -> health-verify pipeline
- vercel-ops.json example: Vercel CLI with preview -> promote pipeline, approval gates, health verification
- stripe-projects.json expanded with full project lifecycle (init, add services, pull credentials, status check, migrations)
- publish-on-tag CI workflow for automated npm releases
- fix: vercel project rm uses pipe instead of unsupported --yes flag
- signing provider abstraction (
src/signing/) with pluggable provider interface (resolve, sign, verify) --signerflag forexeccommand to select signing provider (ssh,none);AGENTCLI_SIGNERenv varsshsigning provider extracted from monolithic attestation module intosrc/signing/ssh.jsnonesigning provider for explicit opt-out (--signer none)verifycommand dispatches verification to the provider that produced the attestation (bymethodfield)- spec.md distinguishes manifest-time attestation (
identity.attestation) from execution-time attestation (produced byexec) signerfield in exec output and audit records identifies which signing provider was usedmethodfield in verify output identifies the attestation method that was verified- barrel export includes
registerProvider,getProvider,listProviders,resolveProvider,resolveProviderForMethod registerTarget()for library consumers to add custom compile targets without forkinginitcommand scaffolds a valid manifest in cwd;--tool <program>wraps a specific CLI;--outputfor custom path; warns if tool not on PATHregistry list|add|show|removecommands for managing reusable manifest templates in~/.agentcli/registry/import <directory>discoversagentcli.jsonorpackage.json"agentcli"field and adds to registrymerge <manifest1> <manifest2>combines workflows from multiple manifests; rejects duplicate workflow idsoutput.formatfield (json,ndjson,text) on tasks; whenjsonorndjson,execparses stdout and includesresult.structured- structured parse failures are non-fatal (fall back to null, emit warning)
- audit records include
result.structured_presentboolean (not content) when output.format is active - barrel export includes
createManifestScaffold,writeManifest,listRegistry,addToRegistry,showRegistryEntry,removeFromRegistry,importManifest,mergeManifests,registerTarget identityblock on workflows, tasks, andon_failurehandlers for chain-of-trust execution (principal, run_as, attestation)contractblock on workflows, tasks, andon_failurehandlers for execution boundary declarations (sandbox, allowed_paths, network, max_cost_usd, audit)- identity and contract inherit from workflow to task level, with task-level key-by-key override (same pattern as model_policy)
skill-pathCLI command prints the resolved path to the bundled SKILL.md for agent auto-discovery--prettyflag for colorized JSON output across all commandsregistrydirectory in agentcli home for reusable manifest templatesskill_pathandregistryincluded inagentcli pathsoutput- standalone compile target declares
identity: trueandcontracts: truecapabilities - openclaw-scheduler compile target emits
identity_principal,identity_run_as,identity_attestation,contract_sandbox,contract_allowed_paths,contract_network,contract_max_cost_usd,contract_auditfields - SKILL.md enhanced with discovery instructions, identity/contract guidance, and template registry documentation
execCLI command executes shell-target tasks directly from a manifest with identity verification, contract enforcement, and audit logging -- works with or without a scheduler runtimeauditCLI command reads the local execution audit log with--limitsupportexecpre-flight contract enforcement rejectsshell.cwdoutside declaredallowed_pathsexecadvisory warnings for sandbox and network contract constraints not yet enforced at OS levelexecwrites append-only NDJSON audit records to~/.agentcli/state/audit.ndjsongoverned bycontract.auditpolicy (always, on-failure, none)execoutput includes execution_id (SHA-256 derived), identity resolution, contract, timing, exit code, output hash, and audit statusexecsupports--dry-runfor contract pre-flight without spawning,--timeoutoverride,--workflowfor multi-workflow manifestsexechandles on_failure expanded tasks (e.g.agentcli exec manifest.json root.failure)execcryptographically signs every execution with the user's SSH key (ssh-keygen -Y sign), producing an attestation that ties the execution to the key holderexecauto-discovers SSH signing keys from~/.ssh/(id_ed25519 > id_ecdsa > id_rsa) or explicitAGENTCLI_SIGNING_KEY/--signing-keypathexec --signer nonedisables attestation signing when not neededverifyCLI command cryptographically verifies an execution audit record against SSH key signatures usingssh-keygen -Y verifyverifyauto-generatesallowed_signersfile from~/.ssh/*.pubwhen not present- attestation payload is canonical deterministic JSON covering execution_id, timestamp, source, command_hash, and principal
- attestation in audit records includes method, key_fingerprint, namespace, signed_payload, and full SSH signature
auditandallowed_signerspaths added toagentcli pathsoutputresolveIdentityandresolveContractexported from compiler/shared.js for library consumers- barrel export includes
executeTask,readAuditLog,writeAuditRecord,generateExecutionId,resolveIdentity,resolveContract - spec.md documents Identity and Contract sections with inheritance and enforcement semantics
identity-contract.jsonexample manifest demonstrating workflow/task-level identity and contract usageversionCLI command (agentcli version,--version,-v) returns package and manifest spec version as structured JSONagentcli.versionJSON-RPC method for agent version discovery- unknown-key warnings on workflows, tasks, and
on_failureblocks to catch typos - validation now rejects non-object values for optional blocks (
model_policy,intent,output,budgets,delivery,reliability,runtime,approval,context,session) - CLI
inspect --sanitizevalidates the value before dispatching, matching the JSON-RPC path - JSON-RPC batch requests (arrays) now return a clear error message instead of generic "Invalid Request"
- barrel export (
src/index.js) now includesinspectSchedulerState,listInspectableEntities,describeTarget,sanitizeForAgent,expandManifestShorthands,applyFieldMask,parseFieldMask - all Node.js built-in imports normalized to
node:prefix - eslint
no-unused-varstightened fromoffto error with underscore-prefix exceptions - AGENTS.md includes a discovery flow section for first-time agent integrations
- SECURITY.md links to GitHub Security Advisories for private reporting
- protocol docs note batch request limitation and document
agentcli.version AGENTCLI_OUTPUTenv var now rejects unknown values instead of silently falling back to json- CLI error output includes
error_typefield (validation_error,unknown_command,invalid_argument,parse_error,internal_error) for structured agent error handling approvalPolicyForTaskreturns null forauto,timeout_s, andrisk_levelwhen no approval block is present (previously defaulted toreject/3600/medium)execution_read_onlyanddelete_after_runemit null instead of0when not explicitly set, matching the nullable schema declarationloadJsonInputwraps JSON parse errors with source context (file path or stdin)- triggered-task sentinel cron extracted to named constants (
TRIGGERED_SENTINEL_CRON,TRIGGERED_SENTINEL_TZ) - JSON-RPC
agentcli.applyadoptByvalidation now uses the standardInvalidParamsErrorpath serveJsonRpchandles output stream errors gracefully and checks writability before writes- ndjson mode returns empty output for zero-item result sets (standard ndjson semantics)
- task schema now declares
required: ['cron']on schedule andrequired: ['parent', 'on']on trigger - task schema includes a
notefield documenting the schedule/trigger mutual exclusion constraint - barrel export includes
resolveManifestCandidatefor library consumers - capabilities doc clarifies the mapping between doc group names and code-level
capabilities/featuresfields - removed broken
"./compile"export path pointing to non-existentsrc/compile.js - removed undocumented
"./compile/shared"export that exposed internal compiler infrastructure resolveIntentpreservesnullforread_onlywhen intent block exists butread_onlyis absent (previouslyBoolean(undefined)producedfalse)pickSchema,describeTarget, andgetTargeterrors now carrycode: 'invalid_argument'for consistent CLI error typinginspectSchedulerStateerrors carrycode: 'invalid_argument'for database-not-found and missing-path cases- trigger condition validation rejects whitespace-only suffixes after
contains:andregex:prefixes - non-object
scheduleortriggervalues now produce a clear type error before the mutual exclusion check - capabilities doc documents the
"model+thinking"feature value - JSON-RPC
agentcli.compileresult now includestargetfield matching CLI output shape agentcli serveforwardsAGENTCLI_SCHEDULER_PREFIXandAGENTCLI_SCHEDULER_BINto RPC defaultsdelivery.modeschema marked asnullable: trueto match validation behaviorrpcRequest.idschema accepts['string', 'number']per JSON-RPC 2.0 specstandalonePlanschema includescapabilitiesandexplainfields matching compiled outputrpcResponse.idschema accepts['string', 'number']matchingrpcRequest.idper JSON-RPC 2.0 specparseFieldMaskrejects non-string--fieldsvalues with a clear error instead of crashing with TypeError- validation now requires
trigger.on(previouslycheckEnumsilently skipped null/absent values) approvalPolicyForTaskreturnsnullforautowhen approval block is present but has no explicit policy (previously defaulted to'reject';policy: 'manual'still defaultsautoto'reject')approvalPolicyForTaskuses??instead of||fortimeout_sandrisk_levelto correctly handle falsy-but-valid valuesloadJsonInputremoves redundantexistsSync(input)fallback that ignored the caller-providedcwd- JSON-RPC generic error handler uses fallback message when
err.messageis absent standalonePlanschemaversionfield addsconst: '0.2'matching compiled output- barrel export includes
loadJsonInput,writeJsonOutput, andresolveSafeOutputPathfor library consumers - AGENTS.md documents
--jsonflag anderror_typefield in structured error output normalizedTaskPlannormalizes all||operators to??for nullable field defaults (agent_id,schedule.tz,delivery.mode/channel/to,reliability.guarantee/overlap_policy,intent.mode,output.offload/retrieve,context.retrieval/limit,session.preferred_key,schedulerModel,approver_scope)- CLI
inspect --limitvalidates the flag value before dispatching, matching the JSON-RPCinspectLimitpath - non-object
scheduleortriggertype errors no longer emit a redundant "must define exactly one" mutual exclusion error - schema fields validated as tokens (
agent_id,model_policy.*,delivery.channel/to,session.preferred_key,approval.approver_scope,shell.program) now carryformat: 'token'annotation in the machine-readable schema - capabilities doc documents
approvalsas a feature key andtrue/falseas valid feature values alongside string levels resolveManifestCandidateresolves relative paths against the injectedcwdinstead ofprocess.cwd(), fixing incorrect resolution for library consumers- spec.md
on_failureMAY-define list now includesid - spec.md documents
trigger.delay_sandon_failure.delay_sconstraints (integer >= 0) - protocol.md documents
agentcli.schemaandagentcli.describeresult envelope shapes - protocol.md documents
agentcli.applydryRundefault (false= live execution) - AGENTS.md clarifies
--jsonscope (all commands exceptserve) approvalPolicyForTaskwithpolicy: 'manual'now always compilesrequiredto1regardless of an explicitrequired: false(policy takes precedence per spec)approvalPolicyForTaskusesNumber(Boolean(...))for non-manual policies to safely coerce unexpected input typessafeLinein JSON-RPC server wrapsstream.writein try/catch to handle destroyed streams during mid-write- protocol.md documents result envelope shapes for
agentcli.validate,agentcli.compile,agentcli.apply, andagentcli.inspect - conformance.md Profile C now requires
agentcli.versionandagentcli.describe - spec.md documents synthesized
on_failureid pattern (<parent_id>.failure) and name pattern (<parent_name> Failure Handler) - added subpath exports for
./describe,./sanitize,./fields, and./ioinpackage.json - protocol.md documents
explainfield inagentcli.compileandagentcli.applyresult envelopes - CLI usage string documents kebab-case schema name aliases (
scheduler-job,standalone-plan,rpc-request,rpc-response) parseArgsin CLI usesObject.create(null)for flags to prevent prototype pollutionschedulerJobschema documents SHA-256 derivation inidfield notestandalonePlanschema includes workflow sub-structure withtasksandedgesfields- spec.md documents
on_failuretarget inference fromshellpresence - protocol.md lists valid targets for
agentcli.schemaandagentcli.describemethods - protocol.md clarifies
dryRunsemantics: "Whentrue, no scheduler writes are executed (preview mode)" - protocol.md corrects
explainfield location inagentcli.compileresult (nested insideoutput, not top-level) spawnSchedulerJsonerrors inapply.jsnow carry structuredcodeproperties (scheduler_error,parse_error) for consistent agent error handling
Initial public draft release.
Includes:
- manifest schema and validation
- structured shell execution (
shell.program,shell.args,shell.env,shell.cwd,shell.stdin) instead of rawcommandstrings - standalone compile target
openclaw-schedulercompile target with POSIX shell rendering forpayload_message- scheduler inspection with field masks and sanitization
- stdio JSON-RPC
- publication docs for spec, protocol, conformance, capabilities, versioning, and adoption
- schema deduplication with shared field definitions
--adopt-by namefor one-time migration of existing scheduler jobs to agentcli management--jsonflag for structured JSON output from all commands including help- TTY detection on stdin to prevent interactive terminal hangs
approval.autoandapproval.approver_scopedocumented in spec- JSON-RPC
agentcli.applysupportsadoptByparameter
Breaking changes from pre-release git snapshots:
commandfield removed from tasks andon_failure; useshell.programandshell.argsinstead- shell targets now reject
payload_kindvalues other thanshellCommand - shell targets reject
prompt; non-shell targets rejectshell