Inspired by OpenClaw — but in Python, and using Temporal instead of custom orchestration.
Why Temporal? Because reasons.
The end result (hopefully):
- A fully visible agent where every action is tracked.
- A potentially more secure agent.
- A simpler codebase to maintain.
- Docker and Docker Compose
cp sample.env .env
# fill in required details mainly API key
# alternatively - if you don't have a paid API key, use Ollama Cloud free tier (easiest)
LLM_PROVIDER=local
LOCAL_MODEL_URL=https://ollama.com/v1
LOCAL_MODEL_API_KEY=...
LLM_MODEL=qwen3-coder:480b-cloud
# alternatively - run scripts/start-mlx-server.sh for a local model if you machine can handle it. Don't forget to set .env appropriately ie
LLM_MODEL= # yes leave blank
LLM_PROVIDER=local
LOCAL_MODEL_URL=http://host.docker.internal:8888/v1
# terminal 1
docker-compose -f docker-compose.yaml -f docker-compose.dev.yaml up --build
# terminal 2
uv run openpaw
This will boot up a local terminal session where you can interact. Say "Hi!" in the terminal and watch it respond.
Note in terminal, the session will end after WORKFLOW_TIMEOUT_MINUTES if
no input is received.
If you want the always on agent, then for now, you need to setup WhatsApp.
cp sample.env .env
# fill in required details mainly API key and WhatsApp number
# fill in your own whatsapp number for simplicity
# you do not need a separate whatsapp number
# do not include the + in the number
MY_WHATSAPP_NUMBER=...
# alternatively - if you don't have a paid API key, use Ollama Cloud free tier (easiest)
# for Ollama
LLM_PROVIDER=local
LOCAL_MODEL_URL=https://ollama.com/v1
LOCAL_MODEL_API_KEY=...
LLM_MODEL=qwen3-coder:480b-cloud
# alternatively - run scripts/start-mlx-server.sh for a local model if you machine can handle it. Don't forget to set .env appropriately ie
LLM_MODEL= # yes leave blank
LLM_PROVIDER=local
LOCAL_MODEL_URL=http://host.docker.internal:8888/v1
# terminal 1
docker-compose -f docker-compose.yaml -f docker-compose.dev.yaml up --build
# terminal 2
docker compose logs whatsapp-listener
# Use the pairing code to pair your device.
# it might take awhile for the barcode to pop up. You should see this in the logs...
...
whatsapp-listener-1 | 09:19:53.745 [openpaw.whatsapp.listener INFO] - Starting WhatsApp listener...
whatsapp-listener-1 | 09:19:55.023 [__main__ INFO] - WhatsApp pairing code: AB1C-DEFG
...
Say "Hi!" to yourself on WhatsApp and watch it respond. You can still use the terminal.
Unlike the terminal, sessions triggered via WhatsApp run "indefinitely".
The LLM will check in on the user periodically based on HEARTBEAT_INTERVAL_MINUTES. The action taken every heartbeat can
be configured via HEARTBEAT_MESSAGE.
Read up more here.
Once you've interacted with the agent by sending a message, to view everything the agent does, go to http://localhost:8080/ and
select the openpaw namespace (top left corner).
# terminal 1
docker compose -f docker-compose.yaml -f docker-compose.dev.yaml watch
# terminal 2
docker compose logs -f worker whatsapp-listener
# View agent state files directly on host
cat ./data/state/*/state.jsonPRs are welcome! Please:
- Fork the repo and create a branch from
main - Install dev dependencies:
uv sync --extra dev - Make your changes and add tests
- Ensure lint and tests pass:
uv run ruff check src tests uv run pytest tests/ -v
- Open a pull request
Code style is enforced via ruff.
MIT — see LICENSE.