Getting Started with agentd¶
This guide walks you through a complete workflow from first run to managing autonomous agents. By the end, you'll understand how all the agentd services work together.
Prerequisites¶
Before starting, make sure you have:
- macOS 14+ or Linux with systemd
- Rust 1.75+ - install from rustup.rs
- tmux -
brew install tmux(macOS) orapt install tmux(Linux) - curl and jq - for testing API endpoints
- Claude Code - install from claude.ai/download (required for agent orchestration)
1. First Run (~5 minutes)¶
Clone and build¶
Start the core services¶
Open three terminal windows (or tmux panes) and start the services:
Alternative: start all at once
If you've already installed with cargo xtask install-user, you can start all services with:
Verify health endpoints¶
In a new terminal, check that each service is running:
Expected output:
Expected output:
{
"status": "ok",
"service": "agentd-ask",
"version": "0.2.0",
"notification_service_url": "http://localhost:17004"
}
Expected output:
If all three respond, you're ready to go!
2. Notifications - Your First Workflow¶
The notification system is the simplest starting point. It stores and manages messages between services and users.
Create a notification¶
Using the CLI (build it first if you haven't installed):
cargo run -p cli -- notify create \
--title "Welcome" \
--message "agentd is running!" \
--priority normal
Expected output:
Notification created successfully!
================================================================================
ID: 550e8400-e29b-41d4-a716-446655440000
Title: Welcome
Message: agentd is running!
Priority: normal
Status: pending
...
================================================================================
Or using curl directly:
curl -s -X POST http://localhost:17004/notifications \
-H "Content-Type: application/json" \
-d '{
"source": {"type": "system"},
"lifetime": {"type": "persistent"},
"priority": "normal",
"title": "Build Complete",
"message": "All tests passed on main branch",
"requires_response": false
}' | jq
List notifications¶
You'll see a table of all notifications with their IDs, titles, priorities, and statuses.
Filter by status¶
# Only show pending notifications
cargo run -p cli -- notify list --status pending
# Only show actionable notifications (pending or viewed, not expired)
cargo run -p cli -- notify list --actionable
Respond to a notification¶
First, create a notification that requires a response:
cargo run -p cli -- notify create \
--title "Deploy to production?" \
--message "Main branch has 5 new commits ready for release" \
--priority high \
--requires-response
Copy the notification ID from the output, then respond:
The notification status changes from pending → responded.
Clean up¶
3. Spawning an Agent¶
The orchestrator manages AI agents running in tmux sessions. This is the core of agentd.
Create an agent¶
curl -s -X POST http://localhost:17006/agents \
-H "Content-Type: application/json" \
-d '{
"name": "explorer",
"working_dir": "'$(pwd)'",
"system_prompt": "You are a helpful coding assistant.",
"prompt": "List the top-level files and give a one-sentence summary of this project."
}' | jq
Expected output:
{
"id": "a1b2c3d4-...",
"name": "explorer",
"status": "running",
"config": {
"working_dir": "/path/to/agentd",
"shell": "zsh",
"interactive": false,
"worktree": false
},
"tmux_session": "agentd-orch-a1b2c3d4-...",
"created_at": "...",
"updated_at": "..."
}
Using the CLI:
agent orchestrator create-agent \
--name explorer \
--prompt "List the top-level files and give a one-sentence summary of this project."
Or use a YAML template (recommended for reproducible setups):
# Apply a template file
agent apply .agentd/agents/worker.yml
# Apply an entire project directory (agents + workflows)
agent apply .agentd/
See the Template Reference for the full YAML schema.
What happens under the hood¶
When you create an agent, the orchestrator:
- Creates a record in its SQLite database
- Starts a new tmux session named
agentd-orch-<agent-id> - Launches
claudeinside that session with--sdk-urlpointing back to the orchestrator's WebSocket endpoint - The Claude Code process connects to
ws://127.0.0.1:17006/ws/<agent-id> - The orchestrator sends the initial prompt via WebSocket
- Agent output is broadcast to monitoring streams at
/stream/<agent-id>
See the agent running¶
List the tmux sessions:
Attach to the agent's session to see it working:
Press Ctrl-b d to detach without killing the agent.
Monitor agent output¶
Stream real-time output with colored formatting:
# Watch a specific agent
agent orchestrator stream <agent-id>
# Watch all agents
agent orchestrator stream --all
# Raw JSON output for piping
agent orchestrator stream --all --json
Press Ctrl+C to disconnect. Messages are formatted by type: assistant text, tool usage, results, and permission requests.
Attach to an agent¶
Connect directly to the agent's tmux session for interactive debugging:
Press Ctrl-b d to detach without killing the agent.
Send follow-up messages¶
After the agent completes its first task, send it more work:
agent orchestrator send-message <agent-id> "Now count the lines of Rust code across all crates."
# Or pipe multi-line prompts from stdin:
echo "Review all files in src/ for security issues" | \
agent orchestrator send-message <agent-id> --stdin
SDK-mode agents stay alive between tasks - you can keep sending messages.
Check agent status¶
Or filter by status:
Terminate the agent¶
This kills the tmux session and marks the agent as stopped.
Restrict tool access¶
Control which tools an agent can use with tool policies:
# Set a read-only policy on a running agent
agent orchestrator set-policy <agent-id> '{"mode":"allow_list","tools":["Read","Grep","Glob"]}'
# Or set it at creation time
agent orchestrator create-agent --name safe --tool-policy '{"mode":"deny_list","tools":["Bash"]}'
# Require human approval for every tool use
agent orchestrator set-policy <agent-id> '{"mode":"require_approval"}'
# Then manage approvals as they come in
agent orchestrator list-approvals
agent orchestrator approve <approval-id>
See the Tool Policies Guide for the full reference.
4. Automated Workflows¶
Workflows connect an agent to a task source (like GitHub Issues) so the agent automatically picks up and works on new tasks.
Prerequisites¶
- A running agent (created in step 3)
- A GitHub repository you have access to
- The
ghCLI authenticated (gh auth login)
Create a worker agent¶
Create an agent without an initial prompt - the workflow will send tasks:
AGENT=$(curl -s -X POST http://localhost:17006/agents \
-H "Content-Type: application/json" \
-d '{
"name": "issue-worker",
"working_dir": "'$(pwd)'",
"system_prompt": "You are a development agent. Implement the task described in each prompt."
}')
AGENT_ID=$(echo "$AGENT" | jq -r '.id')
echo "Agent created: $AGENT_ID"
Wait about 10 seconds for the agent to connect via WebSocket.
Create a workflow¶
curl -s -X POST http://localhost:17006/workflows \
-H "Content-Type: application/json" \
-d '{
"name": "auto-issues",
"agent_id": "'$AGENT_ID'",
"trigger_config": {
"type": "github_issues",
"owner": "YOUR_ORG",
"repo": "YOUR_REPO",
"labels": ["agent"],
"state": "open"
},
"prompt_template": "Work on GitHub issue #{{source_id}}: {{title}}\n\n{{body}}\n\nURL: {{url}}",
"poll_interval_secs": 120,
"enabled": true
}' | jq
Replace YOUR_ORG and YOUR_REPO with your actual GitHub organization and repository.
How it works¶
- The scheduler polls the GitHub API every 120 seconds
- When it finds a new issue matching the labels, it renders the prompt template with the issue data
- It sends the rendered prompt to the agent via WebSocket
- After the agent completes the task, it picks up the next unprocessed issue
Monitor workflow activity¶
View dispatch history to see which issues have been processed:
Each dispatch shows: source ID (issue number), status (dispatched/completed/failed), prompt sent, and timestamps.
Pause or stop a workflow¶
# Pause (keeps the configuration, stops polling)
curl -s -X PUT http://localhost:17006/workflows/<WORKFLOW_ID> \
-H "Content-Type: application/json" \
-d '{"enabled": false}'
# Delete entirely
cargo run -p cli -- orchestrator delete-workflow <WORKFLOW_ID>
5. The Ask Service¶
The ask service monitors your environment and creates interactive notifications when it detects something worth asking about.
Trigger a check¶
Or via curl:
Expected output:
{
"checks_run": ["tmux_sessions"],
"notifications_sent": [],
"check_results": {
"tmux_sessions": {
"sessions_running": true,
"session_count": 2
}
}
}
If no tmux sessions are running, the ask service creates a notification asking if you'd like to start one. You'll see it in notifications_sent.
Answer a question¶
If the ask service created a question notification:
6. Where to Go Next¶
API Documentation¶
- Orchestrator API - Full REST and WebSocket endpoint reference
- Notify API - Notification CRUD endpoints
Production Deployment¶
For running agentd as persistent background services:
# Install binaries and service definitions
cargo xtask install-user
# Start all services (uses launchd on macOS, systemd on Linux)
cargo xtask start-services
# Check status
cargo xtask service-status
Production services use ports 7001-7006 (configured in plist/unit files), while development defaults to ports 17001-17006.
Shell completions¶
Enable tab completion for the agent CLI:
# Bash
agent completions bash > ~/.local/share/bash-completion/completions/agent
# Zsh (add ~/.zfunc to fpath in .zshrc)
agent completions zsh > ~/.zfunc/_agent
# Fish
agent completions fish > ~/.config/fish/completions/agent.fish
Or install all completions at once: cargo xtask install-completions
See Installation Guide for detailed setup instructions.
Port Reference¶
agentd uses a dual-port scheme: dev ports (17xxx) when running with cargo run, and production ports (7xxx) when installed as a LaunchAgent (macOS) or systemd unit (Linux).
| Service | Dev Port | Prod Port |
|---|---|---|
| agentd-ask | 17001 | 7001 |
| agentd-hook | 17002 | 7002 |
| agentd-monitor | 17003 | 7003 |
| agentd-notify | 17004 | 7004 |
| agentd-wrap | 17005 | 7005 |
| agentd-orchestrator | 17006 | 7006 |
| agentd-memory | - | 7008 |
| agentd-communicate | 17010 | 7010 |
The agent CLI defaults to production ports (7xxx). If your services are running on dev ports, set the URL overrides:
Or override a single service:
See Configuration Reference for the full list of environment variables.
Troubleshooting¶
agent status shows services as down when they are running¶
The agent status command checks production ports (7xxx) by default. If you're running services with cargo run (dev ports 17xxx), status checks will fail even though services are healthy.
Check which ports your services are actually on:
# Test dev ports directly
curl -s http://localhost:17004/health # notify (dev)
curl -s http://localhost:17006/health # orchestrator (dev)
# Test production ports
curl -s http://localhost:7004/health # notify (prod)
curl -s http://localhost:7006/health # orchestrator (prod)
If dev services are healthy but agent status shows them down, source the .env file to point the CLI at dev ports:
See issue #536 - a code fix is in progress to make agent status port-scheme-aware.
"Connection refused" when hitting health endpoints¶
The service isn't running, or you're checking the wrong port. Check:
# Is the process running?
ps aux | grep agentd
# Are services on dev ports (cargo run) or prod ports (installed)?
curl -s http://localhost:17004/health # dev
curl -s http://localhost:7004/health # prod
If another process holds the port, either stop it or override with AGENTD_PORT=18004 cargo run -p agentd-notify.
"tmux not found" when creating agents¶
Install tmux:
Agent shows "pending" but never starts running¶
The Claude Code CLI may not be installed or not on your PATH:
If not found, install it from claude.ai/download.
Notification service URL mismatch¶
If the ask service can't reach the notify service, set the URL explicitly:
Database errors on first run¶
The SQLite databases are created automatically. If you see permission errors:
# Check the data directory exists and is writable
ls -la ~/Library/Application\ Support/agentd-notify/ # macOS
ls -la ~/.local/share/agentd-notify/ # Linux
Agent WebSocket connection fails¶
Make sure the orchestrator is running before creating agents. The agent process needs to connect back to ws://127.0.0.1:17006/ws/<id>.
Check the orchestrator logs: