From 3807a53ca24f646e7628237707d2a14b458e45a7 Mon Sep 17 00:00:00 2001 From: Dan Lewis Date: Mon, 26 Jan 2026 21:00:04 -0900 Subject: [PATCH 1/2] feat(cli): add --url flag for agent command This option allows specifying a custom Gateway WebSocket URL (e.g., ws://gateway:18789), which is critical for Docker environments where localhost resolution differs between containers. Changes: - Add --url/-u option to agent command - Update gateway connection logic to prioritize --url flag - Add documentation and tests --- docs/cli/agent.md | 27 ++++++++++++++----- docs/tools/agent-send.md | 24 ++++++++++------- src/cli/program/register.agent.ts | 5 ++++ src/commands/agent-via-gateway.test.ts | 36 ++++++++++++++++++++++++++ src/commands/agent-via-gateway.ts | 2 ++ 5 files changed, 78 insertions(+), 16 deletions(-) diff --git a/docs/cli/agent.md b/docs/cli/agent.md index a42ee3a05..b7fb5bbe1 100644 --- a/docs/cli/agent.md +++ b/docs/cli/agent.md @@ -1,10 +1,10 @@ --- -summary: "CLI reference for `moltbot agent` (send one agent turn via the Gateway)" +summary: "CLI reference for `clawdbot agent` (send one agent turn via the Gateway)" read_when: - You want to run one agent turn from scripts (optionally deliver reply) --- -# `moltbot agent` +# `clawdbot agent` Run an agent turn via the Gateway (use `--local` for embedded). Use `--agent ` to target a configured agent directly. @@ -12,11 +12,26 @@ Use `--agent ` to target a configured agent directly. Related: - Agent send tool: [Agent send](/tools/agent-send) +## Options + +| Flag | Description | +|------|-------------| +| `--url ` | Gateway WebSocket URL (for Docker setups where gateway is on a different host/container) | +| `--local` | Run embedded agent locally instead of via gateway | +| `--deliver` | Send the agent's reply back to the channel | +| `--json` | Output result as JSON | +| `--timeout ` | Override agent command timeout | + +See `clawdbot agent --help` for the full list of options. + ## Examples ```bash -moltbot agent --to +15555550123 --message "status update" --deliver -moltbot agent --agent ops --message "Summarize logs" -moltbot agent --session-id 1234 --message "Summarize inbox" --thinking medium -moltbot agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports" +clawdbot agent --to +15555550123 --message "status update" --deliver +clawdbot agent --agent ops --message "Summarize logs" +clawdbot agent --session-id 1234 --message "Summarize inbox" --thinking medium +clawdbot agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports" + +# Docker: connect CLI container to gateway container +docker compose run --rm clawdbot-cli agent --agent main --message "test" --url ws://clawdbot-gateway:18789 ``` diff --git a/docs/tools/agent-send.md b/docs/tools/agent-send.md index f102ce06e..3724a8188 100644 --- a/docs/tools/agent-send.md +++ b/docs/tools/agent-send.md @@ -1,11 +1,11 @@ --- -summary: "Direct `moltbot agent` CLI runs (with optional delivery)" +summary: "Direct `clawdbot agent` CLI runs (with optional delivery)" read_when: - Adding or modifying the agent CLI entrypoint --- -# `moltbot agent` (direct agent runs) +# `clawdbot agent` (direct agent runs) -`moltbot agent` runs a single agent turn without needing an inbound chat message. +`clawdbot agent` runs a single agent turn without needing an inbound chat message. By default it goes **through the Gateway**; add `--local` to force the embedded runtime on the current machine. @@ -21,7 +21,7 @@ runtime on the current machine. - Output: - default: prints reply text (plus `MEDIA:` lines) - `--json`: prints structured payload + metadata -- Optional delivery back to a channel with `--deliver` + `--channel` (target formats match `moltbot message --target`). +- Optional delivery back to a channel with `--deliver` + `--channel` (target formats match `clawdbot message --target`). - Use `--reply-channel`/`--reply-to`/`--reply-account` to override delivery without changing the session. If the Gateway is unreachable, the CLI **falls back** to the embedded local run. @@ -29,16 +29,20 @@ If the Gateway is unreachable, the CLI **falls back** to the embedded local run. ## Examples ```bash -moltbot agent --to +15555550123 --message "status update" -moltbot agent --agent ops --message "Summarize logs" -moltbot agent --session-id 1234 --message "Summarize inbox" --thinking medium -moltbot agent --to +15555550123 --message "Trace logs" --verbose on --json -moltbot agent --to +15555550123 --message "Summon reply" --deliver -moltbot agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports" +clawdbot agent --to +15555550123 --message "status update" +clawdbot agent --agent ops --message "Summarize logs" +clawdbot agent --session-id 1234 --message "Summarize inbox" --thinking medium +clawdbot agent --to +15555550123 --message "Trace logs" --verbose on --json +clawdbot agent --to +15555550123 --message "Summon reply" --deliver +clawdbot agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports" + +# Docker: connect CLI container to gateway container +docker compose run --rm clawdbot-cli agent --agent main --message "test" --url ws://clawdbot-gateway:18789 ``` ## Flags +- `--url `: Gateway WebSocket URL (for Docker setups where gateway is on a different host/container) - `--local`: run locally (requires model provider API keys in your shell) - `--deliver`: send the reply to the chosen channel - `--channel`: delivery channel (`whatsapp|telegram|discord|googlechat|slack|signal|imessage`, default: `whatsapp`) diff --git a/src/cli/program/register.agent.ts b/src/cli/program/register.agent.ts index 6e5bbc210..ca17f955e 100644 --- a/src/cli/program/register.agent.ts +++ b/src/cli/program/register.agent.ts @@ -45,6 +45,7 @@ export function registerAgentCommands(program: Command, args: { agentChannelOpti "--timeout ", "Override agent command timeout (seconds, default 600 or config value)", ) + .option("--url ", "Gateway WebSocket URL (defaults to gateway.remote.url when configured)") .addHelpText( "after", () => @@ -66,6 +67,10 @@ ${formatHelpExamples([ 'moltbot agent --agent ops --message "Generate report" --deliver --reply-channel slack --reply-to "#reports"', "Send reply to a different channel/target.", ], + [ + 'docker compose run --rm clawdbot-cli agent --agent main --message "test" --url ws://clawdbot-gateway:18789', + "Connect from CLI container to gateway container (Docker).", + ], ])} ${theme.muted("Docs:")} ${formatDocsLink("/cli/agent", "docs.molt.bot/cli/agent")}`, diff --git a/src/commands/agent-via-gateway.test.ts b/src/commands/agent-via-gateway.test.ts index 3b6672f35..096da0569 100644 --- a/src/commands/agent-via-gateway.test.ts +++ b/src/commands/agent-via-gateway.test.ts @@ -123,4 +123,40 @@ describe("agentCliCommand", () => { fs.rmSync(dir, { recursive: true, force: true }); } }); + + it("passes url option to callGateway", async () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdbot-agent-cli-")); + const store = path.join(dir, "sessions.json"); + mockConfig(store); + + vi.mocked(callGateway).mockResolvedValue({ + runId: "idem-1", + status: "ok", + result: { + payloads: [{ text: "hello" }], + meta: { stub: true }, + }, + }); + + try { + await agentCliCommand( + { + message: "hi", + to: "+1555", + url: "ws://clawdbot-gateway:18789", + }, + runtime, + ); + + expect(callGateway).toHaveBeenCalledTimes(1); + expect(callGateway).toHaveBeenCalledWith( + expect.objectContaining({ + url: "ws://clawdbot-gateway:18789", + }), + ); + expect(agentCommand).not.toHaveBeenCalled(); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } + }); }); diff --git a/src/commands/agent-via-gateway.ts b/src/commands/agent-via-gateway.ts index b8401e2a1..8cc53cc7a 100644 --- a/src/commands/agent-via-gateway.ts +++ b/src/commands/agent-via-gateway.ts @@ -50,6 +50,7 @@ export type AgentCliOpts = { runId?: string; extraSystemPrompt?: string; local?: boolean; + url?: string; }; function parseTimeoutSeconds(opts: { cfg: ReturnType; timeout?: string }) { @@ -118,6 +119,7 @@ export async function agentViaGatewayCommand(opts: AgentCliOpts, runtime: Runtim }, async () => await callGateway({ + url: opts.url, method: "agent", params: { message: body, From 360c95dca75e1d4834ff7ea209e8c86e2b06adf9 Mon Sep 17 00:00:00 2001 From: Dan Lewis Date: Mon, 26 Jan 2026 21:04:25 -0900 Subject: [PATCH 2/2] fix(docs): correct docker pairing instructions and update error message Docker networking makes connections appear remote, forcing pairing. The previous docs led users to a broken UI path. Changes: - Remove instructions to use non-existent 'Settings -> Token' UI - Document correct CLI-based pairing workflow for Docker - Update gateway error message to suggest correct fix --- docs/install/docker.md | 30 +++++++++++++++++-- .../server/ws-connection/message-handler.ts | 2 +- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/docs/install/docker.md b/docs/install/docker.md index 8ca80e53b..1688b1fac 100644 --- a/docs/install/docker.md +++ b/docs/install/docker.md @@ -11,8 +11,8 @@ Docker is **optional**. Use it only if you want a containerized gateway or to va ## Is Docker right for me? -- **Yes**: you want an isolated, throwaway gateway environment or to run Moltbot on a host without local installs. -- **No**: you’re running on your own machine and just want the fastest dev loop. Use the normal install flow instead. +- **Yes**: you want an isolated gateway environment (for security or reproducibility), or you prefer not to install dependencies on your host. +- **No**: you trust the software and want the fastest dev loop. Use the normal install flow instead. - **Sandboxing note**: agent sandboxing uses Docker too, but it does **not** require the full gateway to run in Docker. See [Sandboxing](/gateway/sandboxing). This guide covers: @@ -50,7 +50,18 @@ Optional env vars: After it finishes: - Open `http://127.0.0.1:18789/` in your browser. -- Paste the token into the Control UI (Settings → token). +- The dashboard will show **"Pairing Required"** (because Docker containers appear as remote devices). +- To approve the pairing: + +```bash +# List pending requests (find your browser request) +docker compose run --rm clawdbot-cli devices list + +# Approve it +docker compose run --rm clawdbot-cli devices approve +``` + +> **Note:** If you change `.env`, you must run `docker compose up -d` to apply it. `docker compose restart` is not enough. It writes config/workspace on the host: - `~/.clawdbot/` @@ -187,6 +198,19 @@ docker compose run --rm moltbot-cli channels add --channel discord --token "