Metadata-Version: 2.4
Name: cloudagent-daemon
Version: 0.2.4
Summary: Local daemon for cloudagent — bridges Claude Code subprocesses to the cloudagent backend over WebSocket.
Project-URL: Homepage, https://cloudagent.chat
Project-URL: Repository, https://codeup.aliyun.com/69bd0a4d29ad98af4065ce71/cloudagent
Project-URL: Documentation, https://codeup.aliyun.com/69bd0a4d29ad98af4065ce71/cloudagent/docs/superpowers/specs
Author-email: chaoyin <tudoucyx@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: ai-coding-agent,claude-code,cloudagent,daemon
Classifier: Development Status :: 4 - Beta
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.12
Requires-Dist: h2>=4
Requires-Dist: httpx-sse>=0.4
Requires-Dist: httpx>=0.27
Requires-Dist: mcp>=0.9
Requires-Dist: pydantic>=2.7
Requires-Dist: typer>=0.12
Requires-Dist: websockets>=12
Provides-Extra: dev
Requires-Dist: anyio>=4.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# cloudagent-daemon

Local daemon for cloudagent — runs on user's machine, bridges Claude Code
subprocesses to the cloudagent backend so that agents can work locally with
your machine's filesystem and tools.

**Architecture:** spawn-on-message model — daemon receives a `deliver` frame over
WebSocket, spawns `claude --resume <session_id>`, claude uses an MCP server
(also embedded in this daemon) to `send_message` / `list_messages` back to the
backend, and exits when its work is done.

## Quick start (no clone)

Published to PyPI as [`cloudagent-daemon`](https://pypi.org/project/cloudagent-daemon/).
Requires Python 3.12+ and Claude Code CLI on PATH.

```bash
# One-shot run (no persistent install)
uvx cloudagent-daemon start --server-url https://api.cloudagent.chat --api-key sk_machine_***
```

```bash
# Persistent install — install + start chained with && (single line)
uv tool install cloudagent-daemon && cloudagent-daemon start --server-url https://api.cloudagent.chat --api-key sk_machine_***
```

```bash
# Or via pipx
pipx install cloudagent-daemon
```

To upgrade later:

```bash
uv tool upgrade cloudagent-daemon
# or
pipx upgrade cloudagent-daemon
```

### Developer install (from source)

Contributors working off the cloudagent repo can install the unreleased dev
tip directly from the `cy` branch — requires SSH access to the codeup mirror:

```bash
uv tool install --from "git+ssh://git@codeup.aliyun.com:/69bd0a4d29ad98af4065ce71/cloudagent.git@cy#subdirectory=daemon_cli" cloudagent-daemon
```

Or editable install for local hacking:

```bash
pip install -e ./daemon_cli
```

## Quick start

1. Create a host machine in the cloudagent UI (or via REST):
   ```bash
   curl -X POST https://api.cloudagent.chat/v1/host-machines \
     -H "Authorization: Bearer <your_user_jwt>" \
     -H "Content-Type: application/json" \
     -d '{"name":"my-mac","hostname":"mbp.local","os":"darwin","daemon_version":"0.1.0"}'
   ```
   Capture the `raw_key` from the response — it starts with `sk_machine_` and
   is shown only once.

2. Login:
   ```bash
   cloudagent-daemon login --server https://api.cloudagent.chat
   # paste the sk_machine_*** key when prompted
   ```

3. Register a local agent (the agent must already exist in cloudagent with
   `runtime=local_daemon` and `host_machine_id=<your host>`):
   ```bash
   cloudagent-daemon agent register --agent-id agent_01HXX --name Frontend
   ```

4. Start the daemon:
   ```bash
   cloudagent-daemon start &
   cloudagent-daemon status
   ```

   You can also use a process manager like `launchd` (macOS) or `systemd`
   (Linux) — see "Running as a service" below.

5. From the cloudagent UI / API: send a message to the agent. The daemon will
   spawn `claude` to handle it; check `~/.cloudagent/daemon/logs/` for traces.

## One-shot mode

For ephemeral runs (CI / debug / quick demo), pass server + key inline — no
`login` step required and nothing is written to `~/.cloudagent/`:

```bash
cloudagent-daemon start \
  --server-url https://api.cloudagent.chat \
  --api-key sk_machine_***

# Output:
# Detected runtimes:
#   ✓ claude_code 2.1.137  (/opt/homebrew/bin/claude)
# Connecting to https://api.cloudagent.chat as host host_01HXX...
```

`--server-url` and `--api-key` must be passed together; passing one without
the other exits with code 2. The daemon stops on Ctrl-C / SIGTERM and leaves
no state behind. For persistent setups, use `login` once + `start` after.

## Layout

```
~/.cloudagent/
├── daemon/
│   ├── config.json              # server URL + machine API key + host_id
│   ├── state.json               # last_seq + processed message IDs (for dedup)
│   ├── daemon.pid               # PID of running daemon
│   ├── bridge.sock              # unix socket for MCP bridge IPC
│   └── logs/
└── agents/
    └── <agent_id>/
        ├── MEMORY.md            # agent's long-term memory
        ├── notes/               # agent-managed
        ├── workspace/           # agent's working directory
        └── .meta/               # daemon-managed (identity, mcp config, etc.)
```

## Commands

| Command | Description |
|---|---|
| `cloudagent-daemon login --server URL` | Auth + persist machine key |
| `cloudagent-daemon start` | Run the daemon (foreground) |
| `cloudagent-daemon status` | Print PID + connection info |
| `cloudagent-daemon stop` | Send SIGTERM, wait for clean exit |
| `cloudagent-daemon install-service` | Install + start as launchd / systemd user service (auto-restart on crash, auto-start at login) |
| `cloudagent-daemon uninstall-service` | Stop + remove the launchd / systemd service unit |
| `cloudagent-daemon agent register --agent-id ID` | Create local workspace |
| `cloudagent-daemon agent unregister --agent-id ID` | Archive workspace |

## Logs

`~/.cloudagent/daemon/logs/daemon-YYYY-MM-DD.log`. Tail with:

```bash
tail -F ~/.cloudagent/daemon/logs/daemon-*.log
```

## Troubleshooting

- **`Login failed: 401`** — the `sk_machine_***` key was revoked. Create a new
  one in the cloudagent UI (host machine settings).
- **`daemon not running` after `start &`** — check the log file. Common causes:
  config missing (`login` first), backend unreachable, no claude binary on PATH.
- **`claude: command not found`** — install Claude Code: see https://claude.ai/code
- **`agent_status: crashed`** repeatedly — check `~/.cloudagent/agents/<id>/.meta/last-spawn.json`
  for the stderr tail. Common causes: bad MCP config, claude binary version mismatch, agent's
  cwd doesn't exist.
- **`Backpressure dropped`** — your daemon was offline for too long; the
  cloudagent backend dropped queued messages past 100k.

## Running as a service

The daemon ships with `install-service` / `uninstall-service` commands that
generate and load a launchd (macOS) or systemd (Linux) **user** unit configured
to **auto-restart on crash** (KeepAlive / Restart=always) and **auto-start at
login**. This is the commercial-grade default — the daemon never self-exits
unless you explicitly run `uninstall-service` (or stop it via the OS).

### macOS / Linux

```bash
# After login (server URL + key persisted in ~/.cloudagent/daemon/config.json):
cloudagent-daemon login --server https://api.cloudagent.chat --api-key sk_machine_***
cloudagent-daemon install-service

# Or one-shot — embed creds directly in the unit file:
cloudagent-daemon install-service \
  --server-url https://api.cloudagent.chat \
  --api-key sk_machine_*** \
  --insecure   # only if your server uses a self-signed cert
```

The command writes:

- macOS: `~/Library/LaunchAgents/chat.cloudagent.daemon.plist` (KeepAlive=true)
- Linux: `~/.config/systemd/user/cloudagent-daemon.service` (Restart=always, RestartSec=5)

…then bootstraps + kickstarts (macOS) / `daemon-reload` + `enable --now` (Linux).
Logs:

```bash
# macOS
tail -F ~/.cloudagent/daemon/logs/launchd.{out,err}.log

# Linux
journalctl --user -u cloudagent-daemon -f
```

To remove:

```bash
cloudagent-daemon uninstall-service
```

## Multi-profile (managing multiple backends)

You can register the same machine with several cloudagent backends (prod / fr /
staging / dev …) by giving each its own `--profile <name>`. Each profile gets
its own service unit, config, socket, workspace, and launchd / systemd label —
they coexist on disk and run as independent processes.

```bash
# Default profile (no flag) keeps the legacy paths exactly as before:
cloudagent-daemon install-service \
  --server-url https://api.cloudagent.chat --api-key sk_machine_xxx

# Register a second backend under profile "fr":
cloudagent-daemon install-service --profile fr \
  --server-url https://api-fr.cloudagent.chat --api-key sk_machine_yyy --insecure

# Register a third under "staging":
cloudagent-daemon install-service --profile staging \
  --server-url https://api-staging.cloudagent.chat --api-key sk_machine_zzz
```

Inspect what's installed:

```bash
cloudagent-daemon list-profiles
# ● default
#     server:  https://api.cloudagent.chat
#     host_id: host_a1b2c3
#     status:  running pid=12345
# ● fr
#     server:  https://api-fr.cloudagent.chat
#     host_id: host_d4e5f6
#     status:  running pid=12350
```

All commands take `--profile <name>` (default is `default`):

```bash
cloudagent-daemon status     --profile fr
cloudagent-daemon doctor     --profile fr
cloudagent-daemon stop       --profile fr
cloudagent-daemon uninstall-service --profile fr
cloudagent-daemon agent register   --profile fr --agent-id a1
```

Profile names must match `[a-z0-9][a-z0-9-]{0,30}`. `default` is reserved.

### Per-profile filesystem layout

| Resource | Default profile | Named profile `fr` |
|---|---|---|
| Config / state | `~/.cloudagent/daemon/{config,state}.json` | `~/.cloudagent/daemon/profiles/fr/{config,state}.json` |
| IPC socket | `~/.cloudagent/daemon/bridge.sock` | `~/.cloudagent/daemon/profiles/fr/bridge.sock` |
| Workspace | `~/.cloudagent/agents/` | `~/.cloudagent/agents-fr/` |
| Logs | `~/.cloudagent/daemon/logs/launchd.{out,err}.log` | `~/.cloudagent/daemon/profiles/fr/logs/launchd.{out,err}.log` |
| launchd label | `chat.cloudagent.daemon` | `chat.cloudagent.daemon.fr` |
| systemd unit | `cloudagent-daemon.service` | `cloudagent-daemon-fr.service` |

The default profile keeps the original paths byte-for-byte — existing installs
need no migration. Named profiles only show up after their first
`install-service --profile <name>`.

The active profile pins itself in `CLOUDAGENT_DAEMON_PROFILE` for any child
process the daemon spawns (mcp_bridge, claude subprocesses), so commands you
run inside an agent shell pick up the right profile automatically.

## Spec

See `docs/superpowers/specs/2026-05-08-local-daemon-runtime-design.md`.

## License

MIT — see [LICENSE](./LICENSE).
