Your First Task
This guide walks you through creating a cron task that runs every minute, uses the key-value store, and returns a value. By the end you will understand the task directory layout, the task.yaml spec, and how to trigger and inspect runs.
1. Create the task directory
Each task lives in its own directory inside a source. If you followed the quickstart, you already have ~/dicode-tasks/ configured as a local source.
mkdir -p ~/dicode-tasks/hello-cron2. Write task.yaml
Create ~/dicode-tasks/hello-cron/task.yaml:
apiVersion: dicode/v1
kind: Task
name: Hello Cron
description: A simple task that counts how many times it has run.
runtime: deno
trigger:
cron: "* * * * *"
timeout: 30sThis tells dicode to run the task every minute using the Deno runtime with a 30-second timeout.
3. Write the task script
Create ~/dicode-tasks/hello-cron/task.ts:
export default async function main({ kv, output }) {
// Read the run counter from the persistent KV store
const prev = (await kv.get("run_count")) as number | null;
const count = (prev ?? 0) + 1;
// Persist the updated counter
await kv.set("run_count", count);
console.log(`Hello from dicode! Run #${count}`);
// Return a value -- visible in `dicode run` output and the web UI
return { count, message: `This task has run ${count} time(s)` };
}Key points:
- The default export receives the SDK globals:
params,kv,input,output, and more. kv.get()/kv.set()persist data in SQLite across runs. Each task has its own KV namespace.console.log()writes to the run log, visible viadicode logs.- The return value is stored with the run and shown in CLI output.
4. Add the task to your taskset
Update ~/dicode-tasks/taskset.yaml to include the new task:
apiVersion: dicode/v1
kind: TaskSet
name: my-tasks
tasks:
- hello-cron5. The daemon picks it up
Because ~/dicode-tasks is a local source with file watching enabled (the default), the daemon detects the new files and registers the task automatically. This typically takes under 100ms.
Verify it appears:
dicode listYou should see output like:
ID TRIGGER LAST STATUS NAME
hello-cron cron - Hello Cron6. Trigger a manual run
You do not have to wait for the cron schedule. Trigger the task immediately:
dicode run hello-cronThe CLI waits for the run to complete, streams the logs, and prints the return value:
Hello from dicode! Run #1
run abc123: success
{
"count": 1,
"message": "This task has run 1 time(s)"
}7. Check the logs
Every run gets a unique run ID. To see the logs for a specific run:
dicode logs <run-id>2026-04-10T12:00:00Z [info] Hello from dicode! Run #1You can also check the latest status:
dicode status hello-cronWhat happened under the hood
- Source watcher detected the new
task.yamlviafsnotifyand notified the reconciler. - Reconciler parsed the spec, validated it, and registered the task in the in-memory registry.
- Trigger engine scheduled a cron job based on the
"* * * * *"expression (or you triggered it manually withdicode run). - Deno runtime spawned a sandboxed Deno subprocess with the task script. The SDK globals (
kv,params, etc.) communicate with the daemon over a per-run Unix socket using the IPC protocol. - SQLite stored the run result, logs, KV data, and return value.
Using params
Tasks can accept parameters. Add a params section to task.yaml:
params:
name:
description: Who to greet
default: "world"Then use them in your script:
export default async function main({ params }) {
const name = await params.get("name");
console.log(`Hello, ${name}!`);
return { greeting: `Hello, ${name}!` };
}Pass params from the CLI:
dicode run hello-cron name=dicodePython alternative
The same task in Python using the uv runtime (no system Python required):
task.yaml:
apiVersion: dicode/v1
kind: Task
name: Hello Cron (Python)
description: A simple Python task that counts runs.
runtime: python
trigger:
cron: "* * * * *"
timeout: 30stask.py:
count = (kv.get("run_count") or 0) + 1
kv.set("run_count", count)
log.info(f"Hello from dicode! Run #{count}")
result = {"count": count, "message": f"This task has run {count} time(s)"}Python tasks have the SDK globals injected as module-level variables: log, params, env, kv, input, output. To return a value, assign to the result variable.
You can add inline dependencies using PEP 723:
# /// script
# dependencies = ["requests>=2.31"]
# ///
import requests
data = requests.get("https://api.github.com").json()
log.info(data["current_user_url"])
result = dataNext steps
- Configuration Reference -- full
dicode.yamloptions - Runtimes -- Deno, Python, Docker, and Podman details
- Triggers -- cron, webhook, manual, chain, and daemon triggers
- SDK Globals --
kv,params,output,input,mcp,dicode - Secrets -- inject secrets into task environment variables