This document defines the agentcli manifest draft standard version 0.2.
Version 0.2 is backward-compatible with 0.1. All v0.1 manifests remain valid.
New features introduced in v0.2 are noted inline.
Normative language in this document uses:
- MUST
- MUST NOT
- SHOULD
- MAY
The manifest format is designed to:
- be generated and consumed as raw JSON
- preserve workflow intent independently from a specific runtime
- support both human operators and agent integrations
- compile cleanly into backend-specific artifacts
A manifest MUST be a JSON object with:
versionworkflows
A manifest MAY also contain:
identity_profiles(v0.2)authorization_proof_profiles(v0.2)authorization_profiles(v0.2)evidence_profiles(v0.2)
version MUST equal 0.1 or 0.2.
workflows MUST be a non-empty array.
identity_profiles, if present, MUST be an array (see Identity Profiles below).
authorization_proof_profiles, if present, MUST be an array (see Authorization Proof Profiles below).
authorization_profiles, if present, MUST be an array (see Authorization Profiles below).
evidence_profiles, if present, MUST be an array (see Evidence Profiles below).
Each workflow MUST contain:
idnametasks
Each workflow MAY also define:
model_policyidentitycontractauthorization_proof(v0.2)authorization(v0.2)evidence(v0.2)child_credential_policy(v0.2)
Rules:
idMUST match^[A-Za-z0-9][A-Za-z0-9._-]*$idMUST be unique within the manifesttasksMUST be a non-empty array
Each task MUST contain:
idnametarget
Rules:
idMUST be unique within its workflowidMUST match^[A-Za-z0-9][A-Za-z0-9._-]*$- a task MUST define exactly one of
scheduleortrigger
Each task MAY also define:
identity(v0.2, see Identity below)authorization_proof(v0.2, see Authorization Proof Profiles below)authorization(v0.2, see Authorization Profiles below)evidence(v0.2, see Evidence Profiles below)child_credential_policy(v0.2)
enabled, if present, MUST be a boolean.
If omitted, implementations SHOULD treat the task as enabled by default.
This field expresses the desired active state when compiled into a runtime that supports dormant or disabled jobs.
target.session_target MUST be one of:
mainisolatedshell
target.payload_kind MAY be one of:
systemEventagentTurnshellCommand
If omitted, implementations MAY infer payload_kind from session_target.
target.agent_id, if present, MUST be a restricted token and SHOULD avoid whitespace or shell-significant punctuation.
model_policy, if present, MUST be an object.
It MAY define:
providermodelthinking
Workflow-level model_policy acts as a default for tasks in that workflow.
Task-level model_policy overrides workflow-level fields key by key.
intent, if present, MUST be an object.
intent.mode, if present, MUST be one of:
executeplan
intent.read_only, if present, MUST be a boolean.
This block expresses whether a task is allowed to act or should remain planning-only / read-only when compiled into a backend that supports execution boundaries.
output, if present, MUST be an object.
It MAY define:
preview_bytesoffloadretrieveformat
output.preview_bytes, if present, MUST be an integer greater than or equal to 64.
output.offload, if present, MUST be one of:
autoalwaysnever
output.retrieve, if present, MUST be one of:
inlineon-demand
output.format, if present, MUST be one of:
jsonndjsontext
If omitted, implementations SHOULD treat the output as unstructured text.
When json, exec SHOULD parse stdout as JSON and include the parsed value in the result as result.structured. When ndjson, exec SHOULD parse each line of stdout as JSON. Parse failures are non-fatal; implementations SHOULD fall back to null and emit a warning.
This block expresses how large outputs should be previewed, whether backends should prefer offloading or inline retention, and the expected output format from the wrapped tool.
budgets, if present, MUST be an object.
It MAY define:
max_iterationsmax_fanoutmax_context_itemsmax_pending_approvalsmax_queued_dispatches
Each of these, if present, MUST be an integer greater than or equal to 1.
If target.session_target is shell, shell MUST be present.
shell MUST be an object with:
program
It MAY also define:
argsenvcwdstdin
shell.program MUST be a restricted token.
shell.args, if present, MUST be an array of non-empty strings.
shell.env, if present, MUST be an object whose keys match ^[A-Za-z_][A-Za-z0-9_]*$ and whose values are strings.
shell.cwd, if present, MUST be a non-empty string.
shell.stdin, if present, MUST be a string.
The legacy command string field is not supported. Implementations MUST reject manifests that include command and SHOULD direct users to shell.program and shell.args.
Backend targets that flatten shell execution into a single string (such as payload_message in openclaw-scheduler) SHOULD render it as a POSIX-safe shell command with single-quoted arguments. The rendered form is intended for machine consumption, not human display.
Otherwise, prompt MUST be present.
If present, schedule MUST contain:
cron
It MAY also contain:
tz
If tz is omitted, implementations SHOULD default to UTC.
schedule represents a root invocation.
If present, trigger MUST contain:
parenton
It MAY also contain:
delay_scondition
trigger.on MUST be one of:
successfailurecomplete
trigger.delay_s, if present, MUST be an integer greater than or equal to 0.
trigger.parent MUST reference a different task id within the same workflow. Self-referential triggers are not permitted.
trigger.condition, if present, MUST start with exactly one of:
contains:regex:
For contains: conditions, the suffix MUST be a non-empty string.
For regex: conditions, the suffix MUST be a valid regular expression.
on_failure, if present, MUST be an object.
It is a control-plane shorthand for synthesizing a triggered child task with:
trigger.parent= the enclosing task idtrigger.on=failure
on_failure.id, if present, MUST be unique within the workflow after shorthand expansion.
If on_failure.id is omitted, implementations SHOULD synthesize <parent_task_id>.failure.
If on_failure.name is omitted, implementations SHOULD synthesize <parent_task_name> Failure Handler.
on_failure MAY define:
idnameenabledpromptorshelltargetdelay_sconditiondeliveryreliabilityruntimemodel_policyintentoutputbudgetsapprovalcontextsessionidentitycontractdelete_after_run
on_failure.delay_s, if present, MUST be an integer greater than or equal to 0.
If on_failure.target is omitted, the session target is inferred: shell when on_failure.shell is present, isolated otherwise. The agent_id is inherited from the parent task's target when not explicitly set.
If the inferred or explicit session_target is shell, on_failure.shell MUST be present.
Otherwise, on_failure.prompt MUST be present.
delivery.mode, if present, MUST be one of:
announceannounce-alwaysnone
delivery.channel and delivery.to, if present, MUST be restricted tokens.
reliability.guarantee, if present, MUST be one of:
at-most-onceat-least-once
reliability.overlap_policy, if present, MUST be one of:
skipallowqueue
reliability.max_retries, if present, MUST be an integer greater than or equal to 0.
runtime.timeout_ms, if present, MUST be an integer greater than or equal to 1.
This field is intended for backend execution controls like per-task run timeouts. Control-plane implementations SHOULD preserve it across compile targets even when a given backend ignores it.
approval is backend-portable intent, not a guarantee that every backend exposes the same gate semantics.
approval.policy, if present, MUST be one of:
manualauto-approveauto-reject
approval.risk_level, if present, MUST be one of:
lowmediumhigh
approval.timeout_s, if present, MUST be an integer greater than or equal to 1.
approval.auto, if present, MUST be one of:
approvereject
This field provides a direct override for the auto-resolution behavior when an approval gate times out. When policy is auto-approve or auto-reject, the corresponding auto value is implied. Explicit auto takes precedence over inference from policy.
approval.approver_scope, if present, MUST be a restricted token identifying the scope or group that may approve the gate.
approval.required is supported for compatibility, but approval.policy SHOULD be preferred in new manifests.
agentcli exec enforces approval.policy directly, without a scheduler:
- When
approval.policyismanual(or legacyapproval.required: truewith nopolicy),execMUST refuse execution unless a matching, unconsumed, unrevoked, unexpired approval record exists in~/.agentcli/state/approvals.ndjson. The error type isapproval_required. - When
approval.policyisauto-reject,execMUST refuse execution unconditionally. Approval records cannot override this policy. The error type isapproval_auto_rejected. - When
approval.policyisauto-approveor absent,execproceeds without requiring an approval record. exec --dry-runMUST bypass the gate without consuming any approval record.
A matching approval record is one whose task_hash equals the canonical hash of the current task over these fields: workflow_id, task_id, shell.program, shell.args, shell.cwd, identity.ref, approval.policy, approval.risk_level. Any drift in those fields invalidates prior grants.
Approvals are single-use. The matching grant MUST be consumed (written as a consume event in approvals.ndjson) before the process is spawned; crashed or failed executions still consume the grant.
Successful gated executions MUST include an approval_used object in both the result payload and the audit record, carrying approval_id, approver, reason, risk_level, granted_at, expires_at, signature_verified, and signature.{method, key_fingerprint}.
Grants SHOULD be signed. If a grant carries a signature field, exec MUST verify it against the configured allowed-signers file. A failing signature MUST refuse execution with error type approval_signature_invalid.
This local mechanism is scoped to single-machine exec invocations. Durable multi-actor cron-triggered approvals remain the responsibility of the runtime target (e.g. openclaw-scheduler).
context.retrieval, if present, MUST be one of:
nonerecenthybrid
context.limit, if present, MUST be an integer greater than or equal to 1.
If both context.limit and budgets.max_context_items are present, implementations SHOULD prefer context.limit.
session.preferred_key, if present, MUST be a restricted token.
identity, if present, MUST be an object.
It MAY define:
principalrun_asattestation
identity.principal, if present, MUST be a restricted token identifying the authorizing user or service.
identity.run_as, if present, MUST be a restricted token identifying the runtime identity the agent should assume.
identity.attestation, if present, MUST be a non-empty string carrying proof of authorization (such as a signed token or certificate reference). This is a manifest-time attestation: a pre-existing proof baked into the manifest declaring that the principal is authorized to define this workflow. Examples include a CI-issued JWT, a signed deployment token, or a certificate reference.
Manifest-time attestation is distinct from execution-time attestation, which is produced by exec at runtime (see Cryptographic Attestation below). The two serve complementary roles:
- Manifest-time: "this manifest was authorized by principal X" (static, embedded in the manifest)
- Execution-time: "this specific execution was performed by person Y at time T" (dynamic, recorded in the audit log)
Workflow-level identity acts as a default for tasks in that workflow.
Task-level identity overrides workflow-level fields key by key.
This block establishes the chain of trust: agents executing CLI tasks carry the declared principal's authorization, and backends MAY enforce that the run_as identity is permitted for the given principal.
In v0.2, identity MAY additionally define:
ref-- a reference to a named identity profile (see Identity Profiles below)scope-- a provider-defined scope selector used by scoped identity providers and child handoff flowssubject-- an object describing the subject kind and attributesauth-- an object describing the authentication modetrust-- an object describing the trust levelpresentation-- an object describing credential presentation bindings
When ref is present, the identity is resolved by looking up the named profile from the top-level identity_profiles array. Inline fields (subject, auth, trust, presentation) override profile-level values key by key.
identity.scope, if present, MUST be a non-empty string.
identity.subject.kind, if present, MUST be one of:
agentserviceworkloadusercompositedelegated-agentunknown
identity.auth.mode, if present, MUST be one of:
noneservicedelegatedon-behalf-ofimpersonationexchange
identity.trust.level, if present, MUST be one of:
untrustedrestrictedsupervisedautonomous
identity.presentation, if present, MUST be an object. It MAY define:
bindings-- an array of objects describing how credentials are presented to tools (e.g., environment variable injection, header injection)handoff-- how identity context is transferred across task boundaries; if present, MUST be one ofnone,downscope,transaction-tokencleanup-- when credential cleanup runs; if present, MUST be one ofalways,on-success,on-failure,neverdefault_redaction-- if present, MUST be a boolean indicating whether credential values are redacted by default in audit output
Workflow-level v0.2 identity fields act as defaults for tasks in that workflow. Task-level fields override workflow-level fields key by key.
v0.2
child_credential_policy, if present on a workflow or task, MUST be one of:
noneinheritdownscopeindependent
Workflow-level child_credential_policy acts as a default for tasks in that workflow.
Task-level child_credential_policy overrides the workflow-level value.
v0.2
identity_profiles, if present, MUST be a top-level array of identity profile objects.
Each identity profile MUST contain:
id-- a unique identifier within the manifest
Each identity profile MAY contain:
provider-- the identity provider name (e.g.,ssh,oidc-client-credentials,spiffe)subject-- an object withkindand provider-specific attributesauth-- an object withmodeand provider-specific configurationtrust-- an object withlevelpresentation-- an object withbindings,handoff,cleanup, anddefault_redaction
subject.kind MUST be one of: agent, service, workload, user, composite, delegated-agent, unknown.
auth.mode MUST be one of: none, service, delegated, on-behalf-of, impersonation, exchange.
trust.level MUST be one of: untrusted, restricted, supervised, autonomous.
Identity profiles are referenced from workflow-level or task-level identity.ref fields. Profiles provide reusable identity declarations that avoid repetition across workflows and tasks.
See execution-identity.md for full architectural details.
v0.2
authorization_proof, if present on a workflow or task, MUST be an object.
It MUST define:
ref-- a reference to a named authorization proof profile
It MAY additionally define:
claims-- an object describing expected claimsverify-- an object describing verification requirements
Authorization proof describes the method by which a task proves it is authorized to act. The proof is produced at manifest time or execution time and verified before execution proceeds.
Authorization proof supports the following methods:
jwt-- a JSON Web Token carrying signed claimsdetached-signature-- a cryptographic signature over the manifest or payload (e.g., SSH signature, PKCS#7)certificate-- an X.509 or SPIFFE certificate presented as proof of identitynone-- no authorization proof is required
authorization_proof_profiles[].method, if present, MUST be one of the above values.
Workflow/task authorization_proof blocks are scoped overlays on reusable authorization_proof_profiles[] entries. Implementations MUST verify the referenced proof before executing a task when verify is present and the resolved profile method is not none. Verification failure MUST prevent execution.
See execution-identity.md for full architectural details.
v0.2
authorization, if present on a workflow or task, MUST be an object.
It MUST define:
ref-- a reference to a named authorization provider
It MAY additionally define:
provider_config-- provider-specific configuration (e.g., OPA endpoint, Cedar policy store)on_error-- behavior when the authorization provider is unreachable; MUST be one ofdeny,warnrequest-- an object describing the authorization request shapedecision-- an object describing the normalized decision output
Authorization profiles integrate with external policy engines (such as OPA, Cedar, or Topaz) to evaluate whether a resolved identity is permitted to execute a given task.
Implementations MUST normalize the provider response into a decision object containing at minimum:
allowed-- booleanreason-- human-readable explanation
When on_error is omitted, implementations MUST default to deny.
See execution-identity.md for full architectural details.
v0.2
evidence, if present on a workflow or task, MUST be an object.
It MAY define:
ref-- a reference to a named evidence providerpayload-- an object describing the evidence payload and its binding to the executionverify-- an object describing verification requirements
Evidence profiles describe how execution evidence is produced, bound to a specific execution, and made verifiable after the fact. Evidence is the execution-time counterpart to authorization proof.
evidence.payload, if present, MUST be an object. It MAY define:
binding-- how the evidence is bound to the execution context (e.g.,execution_id,command_hash)context-- additional context included in the evidence record
evidence.verify, if present, MUST be an object describing how the evidence can be independently verified.
Implementations SHOULD produce evidence for every execution when evidence is declared. Evidence records MUST be included in the audit trail.
See execution-identity.md for full architectural details.
v0.2
In addition to the v0.1 contract fields, contract MAY define:
required_trust_level-- the minimum trust level required for task execution; MUST be one ofuntrusted,restricted,supervised,autonomoustrust_enforcement-- how trust level mismatches are handled; MUST be one ofnone,advisory,strict
When required_trust_level is present and trust_enforcement is strict, implementations MUST reject execution if the resolved identity's trust level is below the required level. The trust ordering from lowest to highest is: untrusted < restricted < supervised < autonomous.
When trust_enforcement is advisory, implementations MUST emit a warning but SHOULD proceed with execution.
When trust_enforcement is none (the default), the field is recorded for audit only and trust mismatches do not affect execution.
v0.2
Identity, authorization proof, authorization, and evidence are resolved through a three-stage merge:
- Profile resolution -- if
refis present, the named profile is loaded from the top-levelidentity_profiles(or equivalent provider registry). - Workflow-level defaults -- workflow-level declarations act as defaults.
- Task-level overrides -- task-level declarations override workflow-level fields key by key.
At each stage, explicit fields take precedence over inherited fields. The ref field is resolved first, then inline fields override the resolved profile values.
This merge order ensures that shared configuration is declared once at the profile or workflow level while individual tasks retain full control when needed.
contract, if present, MUST be an object.
It MAY define:
sandboxallowed_pathsnetworkmax_cost_usdaudit
contract.sandbox, if present, MUST be one of:
nonepermissivestrict
contract.allowed_paths, if present, MUST be an array of non-empty strings representing filesystem paths the execution may access.
contract.network, if present, MUST be one of:
unrestrictedrestrictednone
contract.max_cost_usd, if present, MUST be a number greater than or equal to 0.
contract.audit, if present, MUST be one of:
noneon-failurealways
Workflow-level contract acts as a default for tasks in that workflow.
Task-level contract overrides workflow-level fields key by key.
Contracts are intent declarations. Backends interpret and enforce them according to their own capabilities. A backend that does not support sandboxing MAY ignore sandbox but SHOULD log a warning.
delete_after_run, if present, MUST be a boolean.
When true, the compiled job is removed from the scheduler after its first successful execution. This field applies to both top-level tasks and on_failure handlers.
A restricted token is a string matching the pattern ^[A-Za-z0-9@:_./-]+$. This covers file paths, model identifiers, agent IDs, delivery channels, and session keys without allowing shell metacharacters or control characters.
Implementations MUST reject invalid manifests.
Implementations MAY emit warnings for:
- approval settings that compile ambiguously for some backends
- approval gates on root scheduled tasks
- backend-specific behavior shims
- planning/read-only intent on targets that only support advisory enforcement
- conflicting context budgets
A conforming implementation MAY support direct task execution via an exec command. When supported:
execMUST only execute tasks withtarget.session_targetequal toshell. Prompt-based tasks require an agent runtime and are not executable by agentcli directly.execMUST resolve identity and contract by inheriting from the workflow level, with task-level fields overriding key by key.execMUST perform pre-flight contract checks before spawning a process. Ifcontract.allowed_pathsis declared and the effective execution cwd (shell.cwdwhen set, otherwise the caller cwd) is not under any allowed path,execMUST reject the execution with a contract violation error.execSHOULD enforcecontract.sandboxandcontract.networkwhen a supported local sandbox backend is available.execSHOULD emit advisory warnings for contract constraints it cannot enforce on the current machine (for example,sandbox: strictornetwork: noneon an unsupported OS).execMUST respectruntime.timeout_msas a process execution timeout.execMUST record an audit trail governed bycontract.audit:always: write an audit record for every executionon-failure: write an audit record only when the exit code is non-zeronone: do not write an audit record- If
contract.auditis not set,execSHOULD default toalways
- The audit record MUST include: execution_id, timestamp, source (workflow_id, task_id), identity (principal, run_as, attestation presence), contract, command metadata (program, args, cwd, env key names, stdin presence), and result (exit code, duration, output size, output hash).
- The audit record MUST NOT include environment variable values or stdin content, as these may contain secrets.
execsupports--dry-runto perform validation and contract checks without spawning a process.execworks independently of any scheduler runtime. It reads a manifest, resolves a task, and executes it directly.
exec SHOULD cryptographically sign each execution to produce an execution-time attestation. This is distinct from the manifest-time identity.attestation field (see Identity above).
exec uses a pluggable signing provider to produce attestations. The provider is resolved in order of precedence:
--signer <name>flagAGENTCLI_SIGNERenvironment variable- Default:
ssh
A conforming implementation MUST support at least:
ssh-- signs with the user's SSH key viassh-keygen -Y signnone-- explicitly disables signing
Implementations MAY support additional providers (e.g. oidc, x509, kms) that implement the same interface: resolve credentials, sign a canonical payload, and verify an attestation record.
The canonical attestation payload is deterministic JSON (sorted keys) containing: version, execution_id, timestamp, source, command_hash, and principal.
The command_hash is a SHA-256 hash of the program name, arguments, and working directory. It MUST NOT include environment variable values or stdin content.
The built-in ssh provider:
- Builds the canonical attestation payload.
- Signs the payload with
ssh-keygen -Y sign -f <key> -n agentcli. - Stores the signature, key fingerprint, namespace, and signed payload in the audit record.
The signing key is resolved in order of precedence:
--signing-key <path>flagAGENTCLI_SIGNING_KEYenvironment variable- Auto-discovery from
~/.ssh/(id_ed25519, then id_ecdsa, then id_rsa)
If no signing key is available or signing fails (e.g. passphrased key not loaded in ssh-agent), exec MUST proceed without attestation and record the reason.
Verification uses ssh-keygen -Y verify against an allowed_signers file mapping principals to public keys. The verify command auto-generates this file from ~/.ssh/*.pub when not present.
The verify command resolves the signing provider from the method field in the attestation record (e.g. ssh-signature dispatches to the ssh provider). This allows each provider to implement its own verification logic.
- Who: the holder of the signing credential authorized this execution
- What: the exact command (via command_hash)
- When: the timestamp (included in signed payload)
- Integrity: the audit record has not been tampered with
This enables agents to inherit the user's identity with cryptographic proof, allowing downstream systems to verify that a specific human authorized a specific execution.
The exec command establishes the chain of custody: the audit log records who authorized the execution (identity), what constraints were declared (contract), what was executed (command), and what happened (result). The attestation makes this chain cryptographically verifiable.
The two attestation layers work together:
- Manifest-time (
identity.attestation): proves the manifest was authorized - Execution-time (audit record): proves each run was performed by a specific identity
This spec does not require a single runtime.
A conforming control-plane implementation MUST support:
- schema access
- manifest validation
- at least one compile target
A target adapter MAY add backend-specific constraints, but MUST NOT silently reinterpret the meaning of schedule, trigger, or task ordering.
Custom compile targets MAY be registered via the library API using registerTarget(). A target MUST provide a name and a compile(manifest, options) function. The target registry rejects duplicate names.
init creates a valid manifest in the current directory. When --tool <program> is specified, the generated manifest wraps that program as a shell target. Implementations SHOULD check whether the tool exists on PATH and emit a warning if not found.
Tools MAY ship an agentcli.json manifest in their root directory. Alternatively, tools distributed as npm packages MAY declare an "agentcli" field in package.json pointing to the manifest path relative to the package root.
The import command discovers manifests from a directory using this convention, validates them, and adds them to the local registry.
The registry (~/.agentcli/registry/) stores reusable manifest templates as named JSON files. The registry command supports:
list-- enumerate templates with workflow summariesadd <path>-- validate and store a manifestshow <name>-- retrieve a stored manifestremove <name>-- delete a template
The merge command combines workflows from multiple manifests into a single manifest. Workflow ids MUST be unique across all input manifests. The merged result MUST pass validation.