Author a Task
A task reads state and returns a decision. Flow handles authorized transaction submission. This example targets a contract you control with value() and setValue(uint256); it assumes that contract is already deployed on your selected network and permits the profile's Safe to update it.
Scaffold
thyme new update-valueThis creates index.ts, args.json, storage.json, and .env.example. The generated task intentionally skips until you implement it.
Implement one call
import { defineTask, z } from '@thyme-labs/sdk'
import { encodeFunctionData, parseAbi } from 'viem'
const abi = parseAbi([
'function value() view returns (uint256)',
'function setValue(uint256 nextValue)',
])
export default defineTask({
schema: z.object({
targetAddress: z.address(),
nextValue: z.string().regex(/^[0-9]+$/),
}),
async run(ctx) {
const nextValue = BigInt(ctx.args.nextValue)
const current = await ctx.client.readContract({
address: ctx.args.targetAddress,
abi,
functionName: 'value',
})
if (current === nextValue) {
return { canExec: false, message: 'Value already matches' }
}
ctx.logger.info(`Updating value from ${current} to ${nextValue}`)
return {
canExec: true,
calls: [{
to: ctx.args.targetAddress,
data: encodeFunctionData({ abi, functionName: 'setValue', args: [nextValue] }),
}],
}
},
onSuccess(ctx, tx) {
ctx.storage.lastConfirmedTransaction = tx.txHash
ctx.storage.lastConfirmedValue = ctx.args.nextValue
ctx.logger.info(`Confirmed ${tx.txHash}`)
},
onFail(ctx, failure) {
ctx.logger.error(`Submission outcome: ${failure.stage}: ${failure.reason}`)
},
})onSuccess records a confirmation checkpoint. An onFail timeout means the outcome may still be unknown; inspect its hashes before retrying. Callbacks run separately from the original task invocation, so share durable data through storage and payloads.
Supply local inputs
Set targetAddress in args.json to your deployed contract address and nextValue to a decimal string, such as "42". Set RPC_URL for its network and SIMULATE_ACCOUNT to the intended profile address.
thyme run update-value
thyme run update-value --simulate
thyme run update-value --simulate-callbacksThe CLI does not sign or submit transactions. Simulation checks are useful but do not reproduce every account or sponsorship rule; see local testing.
Declare required permissions
{
"calls": [
{ "target": { "arg": "targetAddress" }, "function": "setValue(uint256)" }
]
}Only the state-changing call needs declaration; reading value() with ctx.client does not submit a transaction. The selected profile must independently authorize the declared target and selector.
CLI 0.10.0 has a known local manifest-loading bug. Save this file after completing the local runs above; keep it in the uploaded release. It does not prevent cloud manifest enforcement.
Review before upload
Confirm the ABI and chain, use bounded network requests, validate required secrets, return a precise skip reason, and keep storage JSON-compatible. The Roles path executes every returned call atomically in one transaction — if any call reverts, none of them take effect; see runtime limits.
Continue with uploading and creating an executable.