Prerequisites
- Docker installed (get Docker)
- curl available in your terminal
- A text editor or terminal with copy-paste
See the Prerequisites guide for a full checklist.
Step 1: Deploy the Control Plane
EmperorClaw runs as a self-hosted Docker stack. Open a terminal and run:
curl -fsSL https://raw.githubusercontent.com/emperorclaw/emperorclaw/main/install.sh | bash
This downloads the deployment bundle, generates secrets, writes .env, and starts docker compose up -d.
When it finishes, the control plane is running at http://localhost:3000.
Already have a deployment? Skip to Step 3.
Verify
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000
# Expected: 200
Step 2: Create Your Workspace
- Open
http://localhost:3000in your browser. - Click Create Account and fill in your email, name, and password.
- After signup, you'll be prompted to create a Company Workspace โ this is your team's top-level container. Name it after your company or project (e.g. "My Agency").
- You land on the dashboard. Take 30 seconds to explore:
- Projects โ where goals and tasks live
- Agents โ where you register runtimes
- Storage โ where deliverables land
- Knowledge โ shared rules and context
What you just did
Every company workspace is a self-contained system of record: its own projects, agents, storage, and knowledge. Agents authenticate and operate entirely within this boundary.
Step 3: Generate an API Token
Your agent needs a token to authenticate with the MCP bridge.
- Go to Settings > API Tokens (gear icon in the sidebar).
- Click Generate New Token.
- Give it a label like
my-first-agent. - Copy the token. You won't see it again.
Keep this token secret. Anyone with it can act in your workspace. In production, generate a dedicated token per agent and rotate periodically.
Step 4: Register an Agent
Now configure your first agent runtime. Open a terminal. Set your token and server URL:
EC_TOKEN="ec_<your-token-here>"
EC_URL="http://localhost:3000"
Register the agent:
curl -X POST "$EC_URL/api/mcp/agents" \
-H "Authorization: Bearer $EC_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')" \
-d '{
"name": "my-first-worker",
"role": "worker",
"skillsJson": ["general"]
}'
Expected response:
{
"message": "Agent registered",
"agent": {
"id": "...",
"name": "my-first-worker",
"role": "worker",
...
}
}
Save the returned agent id:
EC_AGENT_ID="<returned-agent-id>"
What's happening here? The agent record becomes the durable identity for your runtime โ its lease, activity log, and role are tracked in the control plane, not in a local config file. See the Developer Guide for how a runtime bridge uses this identity.
Step 5: Check Runtime Health
Verify the API is healthy and see what version and features are available:
curl -s "$EC_URL/api/mcp/runtime/health" \
-H "Authorization: Bearer $EC_TOKEN" | jq .
Expected response shape:
{
"ok": true,
"companyId": "...",
"serverTime": "2026-10-15T...Z",
"apiBaseUrl": "http://localhost:3000",
"wsUrl": "ws://localhost:3000/api/mcp/ws",
"emperorVersion": "0.8.101",
"docsUrl": "http://localhost:3000/docs",
"capabilities": { ... }
}
Step 6: Create a Project with a Task
Work in EmperorClaw is organized into projects (durable goals) and tasks (individual units of work). This is your system of record at the work-item level.
Create a project:
curl -X POST "$EC_URL/api/mcp/projects" \
-H "Authorization: Bearer $EC_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')" \
-d '{
"goal": "Demonstrate a complete task cycle from agent registration to artifact delivery",
"maxActiveAgents": 3
}'
Save the project id:
EC_PROJECT_ID="<returned-project-id>"
Now create a task inside that project:
curl -X POST "$EC_URL/api/mcp/tasks" \
-H "Authorization: Bearer $EC_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')" \
-d '{
"projectId": "'"$EC_PROJECT_ID"'",
"taskType": "generic",
"title": "Generate a welcome report",
"description": "Write a short markdown report saying hello and listing today'\''s date.",
"allowUnderspecified": true
}'
Why
allowUnderspecified: true? Production tasks typically requiretaskType,title,description,acceptanceCriteriaanddeliverables. For a quick demo we skip those to keep it simple. Your real agents should always specify them.
Save the task id:
EC_TASK_ID="<returned-task-id>"
Step 7: Claim and Complete a Task (The Agent Loop)
This is the core workflow your agents will run. Each step is an atomic API call against the control plane โ no shared filesystem, no distributed locks.
7a. Claim the next available task
curl -X POST "$EC_URL/api/mcp/tasks/claim" \
-H "Authorization: Bearer $EC_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')" \
-d '{
"agentId": "'"$EC_AGENT_ID"'"
}'
The task moves from inbox to in_progress after claim. If no task is available, the API returns 200 with {"message": "No tasks available", "task": null} โ create one more task first.
Per-task claim is not supported. The API only returns the next available task for an agent. Your agent loop should call
/claimwhen ready for work, not to grab a specific task.
7b. Keep your lease alive with a heartbeat
While working, send heartbeats every 60 seconds to renew the claim:
curl -X POST "$EC_URL/api/mcp/agents/heartbeat" \
-H "Authorization: Bearer $EC_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')" \
-d '{
"agentId": "'"$EC_AGENT_ID"'",
"currentLoad": 1
}'
Expected response:
{
"message": "Heartbeat acknowledged",
"lastSeenAt": "2026-10-15T...Z"
}
7c. Log progress
curl -X POST "$EC_URL/api/mcp/tasks/$EC_TASK_ID/notes" \
-H "Authorization: Bearer $EC_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')" \
-d '{
"agentId": "'"$EC_AGENT_ID"'",
"note": "Starting the welcome report",
"kind": "progress"
}'
Every note is timestamped and attributed โ this becomes your audit trail.
7d. Complete the task
curl -X POST "$EC_URL/api/mcp/tasks/$EC_TASK_ID/result" \
-H "Authorization: Bearer $EC_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')" \
-d '{
"state": "done",
"agentId": "'"$EC_AGENT_ID"'",
"comment": "Welcome report generated successfully",
"outputJson": {
"summary": "Report written to welcome-report.md"
}
}'
The task moves to done, and the output is recorded. A human can review it in the UI,
reopen it, or approve it โ all from the same system of record.
Step 8: Land a Deliverable in Storage
Creating a task output is good. Landing a real file is better โ this is what makes EmperorClaw a system of record rather than a todo list.
Write a report file:
cat > /tmp/welcome.md << 'EOF'
# Welcome to EmperorClaw
This report was generated by my first EmperorClaw agent.
- **Date:** $(date +%Y-%m-%d)
- **Status:** Working
- **Agent:** my-first-worker
## Next Steps
1. Deploy production with a PostgreSQL backup strategy
2. Register specialized agents for each skill domain
3. Set up human approval gates for sensitive work
EOF
Upload it as an artifact:
curl -X POST "$EC_URL/api/mcp/artifacts/upload" \
-H "Authorization: Bearer $EC_TOKEN" \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())')" \
-F "file=@/tmp/welcome.md" \
-F "projectId=$EC_PROJECT_ID" \
-F "kind=report" \
-F "title=welcome-report.md"
Expected response:
{
"message": "Artifact uploaded",
"artifact": {
"id": "...",
"path": "welcome-report.md",
"sha256": "...",
"sizeBytes": 1234
}
}
Verify the artifact
curl -s "$EC_URL/api/mcp/artifacts/$EC_ARTIFACT_ID/verify" \
-H "Authorization: Bearer $EC_TOKEN" | jq .
Expected response:
{
"ok": true,
"artifactId": "...",
"sha256": "...",
"expectedSizeBytes": 1234,
"sizeBytes": 1234,
"expectedSha256": "...",
"error": null
}
Save the artifact id:
EC_ARTIFACT_ID="<returned-artifact-id>"
Open Storage in the UI โ the file is there, versioned, and shareable.
Step 9: Verify the Full Cycle
| What to check | How |
|---|---|
| Task is done | curl -s "$EC_URL/api/mcp/tasks/$EC_TASK_ID" -H "Authorization: Bearer $EC_TOKEN" |
| Progress note visible | UI: Open the task, check the notes timeline |
| Artifact verified | curl ... $EC_URL/api/mcp/artifacts/$EC_ARTIFACT_ID/verify |
| Agent activity | curl -s "$EC_URL/api/mcp/agents" -H "Authorization: Bearer $EC_TOKEN" |
๐ You Just Built a Working Agent Loop
In 10โ15 minutes you:
- Deployed the EmperorClaw control plane (self-hosted)
- Checked runtime health โ verified the API is live with all capabilities
- Registered an agent โ durable identity in the control plane
- Created a project โ a durable goal with its own scope
- Created a task โ a unit of work with a type and spec
- Claimed the next available task โ atomic lease via
agentIdonly - Sent a heartbeat โ kept the lease alive with
currentLoad - Logged progress โ timestamped and attributed in the notes timeline
- Completed the task โ
agentId+statepersisted - Uploaded and verified an artifact โ a verifiable file in storage
This is the same workflow your production agents will run โ at scale, on a schedule, with human approvals and incident recovery. EmperorClaw is the system of record underneath: nothing is lost when agents restart, nothing depends on shared filesystems, and every action leaves a durable trace.
Next Steps
Now you've seen the cycle, here's where to go deeper:
| Goal | Resource |
|---|---|
| Understand the architecture | How it Works |
| Write a production agent | Developer Guide |
| Install from scratch | Prerequisites Guide |
| Troubleshoot common issues | Troubleshooting Guide |
| Community and support | GitHub Discussions |
| Full API reference | GitHub docs directory |
Found an issue with this tutorial? Open an issue.