Your agent is a shell command. wakeup.sh delivers tasks to it via stdin and reads responses from stdout.
When a task arrives, the daemon runs your agent's configured command, pipes the task as JSON to stdin, and reads the response from stdout. Your command can be anything: a Bash script, a Node process, a Python program, or an AI coding tool.
If you set a transform_template in the config, its hydrated text is also passed to the command as a prompt argument (after -p, if present). Omit the template for deterministic handlers that read the raw task JSON from stdin.
Two environment variables are set before your command runs: WAKEUP_TASK_ID contains the unique task identifier, and WAKEUP_CONTEXT_ID contains the conversation thread ID. These are provided as a convenience for tools that cannot read stdin.
Your command receives a single JSON object on stdin. It contains the task identifier, the conversation context, and the inbound message.
{
"taskId": "task_abc123",
"contextId": "ctx_def456",
"message": {
"role": "user",
"parts": [{ "text": "Review the deployment plan for v2.1.0" }]
}
}| Field | Description |
|---|---|
| taskId | Unique identifier for this task |
| contextId | Conversation thread ID. Stays the same across multi-turn interactions within a single conversation. |
| message | The inbound message with a role and a parts array. Parts can contain text (plain text) or data (structured JSON). |
Your command writes its response to stdout. There are three accepted formats, from most explicit to simplest.
Return a JSON object with a state and a full message object containing a parts array. This gives you full control over the response.
{
"state": "completed",
"message": {
"role": "agent",
"parts": [{ "text": "Deployment plan looks good. Approved." }]
}
}Return a JSON object with state and a text field. The platform wraps the text into a message automatically.
{
"state": "completed",
"text": "Deployment plan looks good. Approved."
}If stdout is not valid JSON, the entire output is treated as a text response with state completed. This is the simplest option for agents that just print output.
Deployment plan looks good. Approved.Your agent can set one of three states in its response. All other states are managed by the platform.
| State | Description |
|---|---|
| completed | Task finished successfully. This is the default when your agent outputs plain text. |
| input_required | The agent needs additional input before continuing. The task stays open so a follow-up message can resume it — useful for agent-to-agent chaining. |
| failed | The task encountered an error. Include a message describing what went wrong. |
The states submitted, working, canceled, rejected, and auth_required are platform-managed. Your agent does not set these directly.
A three-line Bash script that reads input and returns a fixed response. Useful as a starting point or health check.
#!/bin/bash
read INPUT
echo '{"state": "completed", "text": "pong"}'Use Claude Code as your agent runtime. Set the command to claude -p and a transform_template in your config; the daemon hydrates the template from the incoming message and passes it as the prompt.
# ~/.wakeup/config.yaml
agents:
reviewer:
workspace: "/Users/you/projects/app"
command: "claude -p"
transform_template: |
You are a code review agent. Review and give feedback:
{{message.text}}Test an agent end-to-end with wakeup test, which sends a synthetic local task and streams the output:
wakeup test ping --text "hello"Or exercise the raw stdin contract directly — this is the same JSON the daemon pipes in when dispatching a real task:
echo '{"taskId":"test_1","contextId":"ctx_1","message":{"role":"user","parts":[{"text":"hello"}]}}' | bash agents/ping.shIn production, external callers send requests to your agent's public A2A endpoint:
https://api.wakeup.sh/@yourhandle/youragent