Communicating Between Steps
Cloche offers three mechanisms for passing data between steps: environment variables injected by the daemon, a KV store accessible from both host and container steps, and a shared run folder for large files. Which one to use depends on what you’re passing and where it needs to go.
Environment Variables
The daemon injects a set of CLOCHE_* environment variables into every step. These provide context about the current run — IDs, paths, and output locations — rather than user data.
Host steps
| Variable | Description |
|---|---|
CLOCHE_PROJECT_DIR |
Absolute path to the project directory on the host. |
CLOCHE_RUN_ID |
Run ID for this workflow execution (e.g. a133:develop). |
CLOCHE_STEP_OUTPUT |
Path where this step should write its output. |
CLOCHE_PREV_OUTPUT |
Path to the output file from the immediately preceding step. |
CLOCHE_TASK_ID |
Task ID assigned by the daemon (set for the main phase). |
Container steps
| Variable | Description |
|---|---|
CLOCHE_RUN_ID |
Run ID for this workflow execution (e.g. a133:develop). |
CLOCHE_TASK_ID |
Task ID assigned by the daemon. Set when the run is associated with a task. |
CLOCHE_ATTEMPT_ID |
Attempt identifier for this container run. |
CLOCHE_PROJECT_DIR |
Working directory inside the container (/workspace). |
CLOCHE_AGENT_COMMAND |
Overrides the default agent command inside the container. |
CLOCHE_ADDR |
Daemon gRPC address (e.g. host.docker.internal:50051). Used by clo. |
ANTHROPIC_API_KEY |
Passed through from the host environment if set. |
KV Store
The KV store is the primary way to pass user data between steps. It is backed by the daemon’s gRPC API and is accessible from both host scripts and container steps, making it the natural choice for cross-boundary communication.
- Host scripts use
cloche get <key>andcloche set <key> <value> - Container steps use
clo get <key>andclo set <key> <value>
Both commands require CLOCHE_TASK_ID (and CLOCHE_ATTEMPT_ID if set), which the daemon injects automatically.
# In a host script step:
cloche set pr_id 1234
# In a later container step:
pr_id=$(clo get pr_id)
Values are scoped to the run and persist for its lifetime. Any step in the run can read keys written by any earlier step.
Reading from stdin or files
cloche set and clo set accept - to read from stdin, or -f <file> to read from a file:
cloche set description - # read from stdin (trailing newlines trimmed)
cloche set config -f config.json # read from file
Auto-seeded keys
The daemon writes several keys automatically before each step runs:
Run-level (set once at run start):
| Key | Value |
|---|---|
task_id |
Task identifier |
attempt_id |
Attempt identifier |
workflow |
Current workflow name |
run_id |
Run identifier |
Step-level (updated before each step):
| Key | Value |
|---|---|
prev_step |
Name of the step that triggered this one (empty for the entry step) |
prev_step_exit |
Result of that step (empty for the entry step) |
Step result tracking (set after each step completes):
| Key | Value |
|---|---|
<workflow>:<step>:result |
Result of the completed step (e.g. develop:implement:result = success) |
Sub-workflow results (set after a workflow_name step targeting a container workflow completes):
| Key | Value |
|---|---|
child_run_id |
Run ID of the child container workflow; used to locate the cloche/<run-id> git branch with extracted results |
All auto-seeded keys are writable — scripts can overwrite them with cloche set if needed.
Listing keys
Inside a container, clo keys lists all keys in the current attempt namespace.
Shared Run Folder
KV values are limited to 1 KB. For larger data — diffs, logs, generated files — write to the shared run folder and pass the filename through the KV store.
The run folder is at .cloche/runs/{CLOCHE_RUN_ID}/. It is a bind mount shared between the host and the run’s containers, so files written on either side are visible to the other. The daemon creates this directory at run start.
# Host script — write a large review payload
output_dir=$(cloche get temp_file_dir)
generate-feedback > "$output_dir/review-feedback.md"
cloche set review_feedback_path "$output_dir/review-feedback.md"
# Container step — read it back
feedback_path=$(clo get review_feedback_path)
cat "$feedback_path"
The built-in KV key temp_file_dir is set automatically by the daemon and points to .cloche/runs/<run-id>. Use it rather than constructing the path yourself.
When a workflow run exits, the daemon deletes its run folder automatically. Do not store anything in .cloche/runs/ that needs to outlive the run. If a step produces artifacts that should persist (e.g. a built binary or a report), copy them to a location outside the run folder before the workflow completes.
Example: Passing Task Data Through a Pipeline
A common pattern is for a host script step to extract data from a task, write it to the shared run folder, and pass the filename via the KV store for downstream steps to consume:
# .cloche/scripts/prepare-prompt.sh (host script step)
# Read the task description from the tracker
task_id="$CLOCHE_TASK_ID"
description=$(gh issue view "$task_id" --json body -q .body)
# Write it to the shared run folder (handles files > 1 KB)
output_dir=$(cloche get temp_file_dir)
prompt_file="$output_dir/task_prompt.md"
echo "$description" > "$prompt_file"
# Store the path so downstream steps can find it
cloche set task_prompt_path "$prompt_file"
A container step later in the pipeline reads it back:
# Inside a container step (or in a prompt template via clo)
prompt_path=$(clo get task_prompt_path)
cat "$prompt_path"
This keeps large payloads out of the KV store (which is limited to 1 KB values) while still using it as the coordination mechanism.
Which mechanism to use
| Need | Mechanism |
|---|---|
| Run context (IDs, paths) | Environment variables — already injected |
| Small values between steps (< 1 KB) | KV store (cloche set / clo get) |
| Large files between steps (> 1 KB) | Shared run folder + KV store for the path |