cade-cli 0.13.4__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cade_cli-0.13.4 → cade_cli-0.14.0}/PKG-INFO +52 -36
- {cade_cli-0.13.4 → cade_cli-0.14.0}/README.md +51 -35
- {cade_cli-0.13.4 → cade_cli-0.14.0}/pyproject.toml +1 -1
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/server.py +13 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/__init__.py +5 -0
- cade_cli-0.14.0/src/cade_mcp_local/tools/agents.py +151 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/notifications.py +2 -2
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/ai/prompts.py +33 -19
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/app.py +156 -115
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/account.py +3 -1
- cade_cli-0.14.0/src/cadecoder/cli/commands/agents.py +440 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/auth.py +0 -19
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/chat.py +4 -23
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/hooks.py +60 -59
- cade_cli-0.14.0/src/cadecoder/cli/commands/mem.py +221 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/serve.py +64 -3
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/tasks.py +19 -7
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/thread.py +1 -1
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/tools.py +48 -31
- cade_cli-0.14.0/src/cadecoder/core/agent.py +501 -0
- cade_cli-0.14.0/src/cadecoder/core/comms.py +177 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/config.py +25 -203
- cade_cli-0.14.0/src/cadecoder/core/inbox.py +138 -0
- cade_cli-0.14.0/src/cadecoder/core/memory.py +76 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/paths.py +57 -19
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/runtime.py +27 -10
- {cade_cli-0.13.4/src/cadecoder/serve → cade_cli-0.14.0/src/cadecoder/core}/secrets.py +15 -5
- cade_cli-0.14.0/src/cadecoder/core/spawn.py +215 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/execution/orchestrator.py +2 -2
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/__init__.py +9 -3
- cade_cli-0.14.0/src/cadecoder/hooks/config.py +193 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/providers/__init__.py +8 -3
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/__init__.py +1 -1
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/allowlist.py +2 -2
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/config.py +52 -53
- cade_cli-0.14.0/src/cadecoder/serve/cron.py +37 -0
- cade_cli-0.14.0/src/cadecoder/serve/daemon.py +661 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/install.py +50 -27
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/observability.py +3 -1
- cade_cli-0.14.0/src/cadecoder/serve/owner.py +44 -0
- cade_cli-0.14.0/src/cadecoder/serve/secrets.py +24 -0
- cade_cli-0.14.0/src/cadecoder/serve/services.py +309 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/worker.py +65 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tasks/__init__.py +1 -8
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tasks/store.py +4 -4
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tasks/types.py +0 -9
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/templates/serve/launchd.plist.tmpl +1 -1
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/templates/serve/systemd.service.tmpl +2 -2
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/manager/composite.py +279 -132
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/manager/config.py +25 -20
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/manager/mcp.py +230 -94
- cade_cli-0.14.0/src/cadecoder/ui/completion.py +74 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/ui/display.py +13 -7
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/ui/input.py +49 -13
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/ui/session.py +219 -116
- cade_cli-0.14.0/src/cadecoder/ui/slash.py +84 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/voice/session.py +22 -2
- cade_cli-0.13.4/src/cadecoder/cli/commands/channels.py +0 -79
- cade_cli-0.13.4/src/cadecoder/cli/commands/context.py +0 -205
- cade_cli-0.13.4/src/cadecoder/cli/commands/mem.py +0 -176
- cade_cli-0.13.4/src/cadecoder/cli/commands/model.py +0 -255
- cade_cli-0.13.4/src/cadecoder/cli/commands/persona.py +0 -572
- cade_cli-0.13.4/src/cadecoder/hooks/config.py +0 -151
- cade_cli-0.13.4/src/cadecoder/serve/daemon.py +0 -383
- cade_cli-0.13.4/src/cadecoder/storage/personas.py +0 -243
- cade_cli-0.13.4/src/cadecoder/tasks/channels.py +0 -89
- cade_cli-0.13.4/src/cadecoder/tasks/notifications.py +0 -100
- cade_cli-0.13.4/src/cadecoder/ui/slash.py +0 -47
- {cade_cli-0.13.4 → cade_cli-0.14.0}/.gitignore +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/LICENSE +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/__main__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/_metadata.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/config.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/errors.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/resources.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/_read_cache.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/context.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/filesystem.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/git.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/questions.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/results.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/schemas.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/search.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/shell.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/snippets.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/tasks.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/web_fetch.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/tools/web_search.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/utils.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/arcade_client.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/cache.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/extract.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/markdown.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/preapproved.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/prompts.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/scrape.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/search/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/search/arcade.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/search/base.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cade_mcp_local/web/search/http.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/ai/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/auth.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/cron.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/cli/commands/mcp.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/constants.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/errors.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/frozen.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/git.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/logging.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/model_specs.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/names.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/core/types.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/execution/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/execution/context_window.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/execution/mcp_schema_index.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/execution/parallel.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/execution/tool_result_store.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/execution/tool_schema_cache.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/engine.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/executors/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/executors/callback.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/executors/command.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/executors/http.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/executors/prompt.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/executors/ssrf_guard.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/matchers.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/registry.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/hooks/types.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/providers/anthropic.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/providers/base.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/providers/ollama.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/providers/openai.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/adapters/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/adapters/base.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/adapters/desktop.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/adapters/registry.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/adapters/stub.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/adapters/telegram.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/chunker.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/commands.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/elicitation.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/format.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/lock.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/progress_sink.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/router.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/serve/sinks.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/storage/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/storage/threads.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tasks/lock.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tasks/scheduler.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/templates/login_failed.html +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/templates/login_success.html +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/templates/serve/serve.toml.example +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/templates/styles.css +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/manager/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/manager/_request_ctx.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/manager/base.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/search/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/search/discovered.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/search/scoring.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/tools/search/service.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/ui/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/ui/elicitation.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/voice/__init__.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/voice/audio.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/voice/cleanup.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/voice/stt.py +0 -0
- {cade_cli-0.13.4 → cade_cli-0.14.0}/src/cadecoder/voice/tts.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cade-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: Cade - The CLI Agent from Arcade.dev
|
|
5
5
|
Project-URL: Homepage, https://arcade.dev
|
|
6
6
|
Project-URL: Documentation, https://docs.arcade.dev
|
|
@@ -91,7 +91,7 @@ Description-Content-Type: text/markdown
|
|
|
91
91
|
The CLI agent from [Arcade.dev](https://arcade.dev). Coding, research, and everyday automation — driven from a terminal, a single shell pipe, or a long-lived daemon that replies over Telegram.
|
|
92
92
|
|
|
93
93
|
```bash
|
|
94
|
-
|
|
94
|
+
curl -fsSL https://arcadeagent.dev/install | sh # or: uv tool install cade-cli | pip install cade-cli
|
|
95
95
|
cade login
|
|
96
96
|
cade
|
|
97
97
|
```
|
|
@@ -101,10 +101,10 @@ cade
|
|
|
101
101
|
## Highlights
|
|
102
102
|
|
|
103
103
|
- **Three deployment modes from the same binary.** Interactive chat (`cade`), one-shot or pipe (`cade -m "…"`), or a headless daemon that replies over messaging (`cade serve`).
|
|
104
|
-
- **Tools from anywhere.** Built-in local tools (filesystem / shell / git / search / tasks /
|
|
104
|
+
- **Tools from anywhere.** Built-in local tools (filesystem / shell / git / search / tasks / memory), [Arcade Cloud](https://arcade.dev) tools (Slack, GitHub, Gmail, calendars, …), and any [MCP](https://modelcontextprotocol.io/) server you register — all unified under one tool surface.
|
|
105
105
|
- **Bidirectional MCP.** Tools can call `context.ui.elicit(…)` for structured input, `context.log.*` for live operator logs, and `context.progress.report(…)` for editable progress UI — routed end-to-end through whichever adapter is active (Telegram inline keyboard, terminal prompt).
|
|
106
|
-
- **
|
|
107
|
-
- **Extensibility surface.** Hooks (lifecycle events), tasks (
|
|
106
|
+
- **Agents + per-agent memory.** Multiple agents, each with their own model, system prompt, tools, and an indexed memory store backed by [agent-library](https://pypi.org/project/agent-library/).
|
|
107
|
+
- **Extensibility surface.** Hooks (lifecycle events), tasks (durable work), cron (scheduled prompts) — all available to the agent as `Local_*` tools and to you as `cade <subcommand>`.
|
|
108
108
|
- **Bring your own LLM.** OpenAI, Anthropic, or any OpenAI-compatible endpoint (Ollama, vLLM, Together, Groq, Fireworks, …). `--local-only` skips Arcade Cloud entirely.
|
|
109
109
|
|
|
110
110
|
---
|
|
@@ -113,12 +113,21 @@ cade
|
|
|
113
113
|
|
|
114
114
|
| Source | Command |
|
|
115
115
|
|---|---|
|
|
116
|
-
|
|
|
116
|
+
| **Install script** (recommended) | `curl -fsSL https://arcadeagent.dev/install \| sh` |
|
|
117
117
|
| uv | `uv tool install cade-cli` |
|
|
118
118
|
| pip | `pip install cade-cli` |
|
|
119
119
|
| From source | `git clone https://github.com/arcadeai-labs/cade.git && cd cade && uv sync` |
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
The install script detects your OS/arch, downloads the matching prebuilt binary
|
|
122
|
+
(macOS arm64, Linux x64), verifies its checksum, and drops `cade` in
|
|
123
|
+
`~/.local/bin` — no GitHub token required. Pin a version or install location:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
CADE_VERSION=0.14.0 CADE_INSTALL_DIR=/usr/local/bin \
|
|
127
|
+
sh -c "$(curl -fsSL https://arcadeagent.dev/install)"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
(Windows: grab the `.zip` from the releases page, or `pip install cade-cli`.)
|
|
122
131
|
|
|
123
132
|
**Prerequisites:** Python 3.11+, an Arcade account ([arcade.dev](https://arcade.dev)) for cloud tools, and an LLM provider key (`OPENAI_API_KEY` or `ANTHROPIC_API_KEY`). Skip the Arcade account with `--local-only` or `CADE_LOCAL_ONLY=1`.
|
|
124
133
|
|
|
@@ -138,9 +147,9 @@ Full install and first-run docs: [`docs/install.md`](./docs/install.md) and
|
|
|
138
147
|
cade # interactive chat
|
|
139
148
|
cade -m "What changed in HEAD?" # single message, then exit
|
|
140
149
|
cade -m "What went wrong?" < error.log # prompt + file/stdin
|
|
141
|
-
cade
|
|
150
|
+
cade resume # resume the most recent thread
|
|
142
151
|
cade resume "auth-rewrite" # resume a thread by name
|
|
143
|
-
cade
|
|
152
|
+
cade use reviewer # switch the current agent
|
|
144
153
|
cade --voice # speak / hear (requires cade-cli[voice])
|
|
145
154
|
```
|
|
146
155
|
|
|
@@ -148,10 +157,8 @@ cade --voice # speak / hear (requires cade-cli[voi
|
|
|
148
157
|
|
|
149
158
|
| Flag | Description |
|
|
150
159
|
|---|---|
|
|
151
|
-
| `-r`, `--resume` | Resume most recent thread |
|
|
152
160
|
| `-m`, `--message` | Single-message mode; piped stdin is appended to the prompt |
|
|
153
|
-
|
|
|
154
|
-
| `-V`, `--voice` | Voice mode; install `cade-cli[voice]` first |
|
|
161
|
+
| `--voice` | Voice mode; install `cade-cli[voice]` first |
|
|
155
162
|
| `-v`, `--verbose` | Debug logging |
|
|
156
163
|
| `--version` | Print version |
|
|
157
164
|
|
|
@@ -165,7 +172,7 @@ cade --voice # speak / hear (requires cade-cli[voi
|
|
|
165
172
|
| `/logs` | Recent log entries |
|
|
166
173
|
| `/thread`, `/history` | Current thread info |
|
|
167
174
|
| `/pin`, `/unpin` | Pin reference material into the session |
|
|
168
|
-
| `/tasks`, `/cron`, `/hooks`, `/
|
|
175
|
+
| `/tasks`, `/cron`, `/hooks`, `/notify` | Coordination surfaces (mirrored as `cade tasks` / `cade cron` / `cade hooks`) |
|
|
169
176
|
| `/usage` | Context-window status and token usage |
|
|
170
177
|
| `/cd`, `/pwd`, `/!` | Shell shortcuts |
|
|
171
178
|
| `Ctrl+C` | Exit |
|
|
@@ -177,7 +184,7 @@ cade --voice # speak / hear (requires cade-cli[voi
|
|
|
177
184
|
Tools come from three sources and are addressed uniformly by their registered name:
|
|
178
185
|
|
|
179
186
|
- **`Local_*`** — built-in: filesystem (`ReadFile`, `WriteFile`, `Edit`, `ListFiles`), shell (`Bash`), `Search`, `Git`, `Task*`, `AskUserQuestion`, `RetrieveToolResult`, `ToolSchema`, `PinContext`, `PushNotification`, `WebFetch`, and `WebSearch`.
|
|
180
|
-
- **`Memory_*`** — agent-library backed, per-
|
|
187
|
+
- **`Memory_*`** — agent-library backed, per-agent indexed knowledge store.
|
|
181
188
|
- **Arcade Cloud + user MCP servers** — anything you register.
|
|
182
189
|
|
|
183
190
|
```bash
|
|
@@ -198,37 +205,46 @@ cade mcp authorize my-server # OAuth flow (browser)
|
|
|
198
205
|
cade mcp list / status / test / enable / disable / rm
|
|
199
206
|
```
|
|
200
207
|
|
|
201
|
-
User MCP servers register
|
|
208
|
+
User MCP servers register on the agent's `~/.cade/config/agents/<name>.toml [[mcp]]` list (with `cade.toml [agent_defaults].mcp` as the shared default). Servers with large catalogs are auto-deferred (parameter schemas stripped to keep tool-list bytes down) and fetched on demand via `Local_ToolSchema`.
|
|
202
209
|
|
|
203
210
|
---
|
|
204
211
|
|
|
205
|
-
##
|
|
212
|
+
## Agents + memory
|
|
213
|
+
|
|
214
|
+
Each **agent** bundles a model, system prompt, tools, and memory. The current
|
|
215
|
+
agent is ambient — most commands act on it.
|
|
206
216
|
|
|
207
217
|
```bash
|
|
208
|
-
cade
|
|
209
|
-
cade
|
|
218
|
+
cade new reviewer --prompt "You are a meticulous code reviewer." # create + switch
|
|
219
|
+
cade list # all agents
|
|
220
|
+
cade use reviewer # switch the current agent
|
|
221
|
+
cade info / cade edit reviewer # inspect / change config
|
|
210
222
|
|
|
211
|
-
cade mem
|
|
223
|
+
cade mem # the current agent's memory (status)
|
|
212
224
|
cade mem add ~/notes # index a directory
|
|
213
225
|
cade mem search "auth design" # semantic search
|
|
214
226
|
```
|
|
215
227
|
|
|
216
|
-
Memory is
|
|
228
|
+
Memory is per-agent — each agent has its own
|
|
229
|
+
`~/.cade/data/agents/<id>/memory/.librarian/` index, so a `reviewer` agent's
|
|
230
|
+
notes never leak into another.
|
|
217
231
|
|
|
218
232
|
---
|
|
219
233
|
|
|
220
234
|
## Headless daemon: `cade serve`
|
|
221
235
|
|
|
222
|
-
Run Cade as a long-lived daemon that replies through adapters. Telegram is supported for personal bot workflows, and Desktop exposes a local WebSocket for native clients. Each conversation gets its own persistent thread —
|
|
236
|
+
Run Cade as a long-lived daemon that replies through adapters. Telegram is supported for personal bot workflows, and Desktop exposes a local WebSocket for native clients. Each conversation gets its own persistent thread — model, memory, and tools carry across messages.
|
|
223
237
|
|
|
224
238
|
```bash
|
|
225
239
|
cade serve init # wizard: bot token, allowed senders
|
|
226
|
-
cade serve # foreground
|
|
240
|
+
cade serve # foreground (current agent)
|
|
241
|
+
cade serve --agent ops # serve a specific agent (one daemon per agent)
|
|
242
|
+
cade serve list # agents with a running daemon
|
|
227
243
|
cade serve --install launchd # macOS LaunchAgent (or --install systemd)
|
|
228
244
|
cade serve status / stop # health, uptime; SIGTERM running daemon
|
|
229
245
|
```
|
|
230
246
|
|
|
231
|
-
|
|
247
|
+
Each agent's serve config lives in `~/.cade/config/agents/<name>.toml [serve]`. Edit and `kill -HUP $(cat ~/.cade/run/agents/<name>/serve.pid)` to reload without restart.
|
|
232
248
|
|
|
233
249
|
**Security defaults are fail-closed:** `allowed_senders = []` blocks everyone; tools are default-deny against `[serve.tools].allow` (globs / regex / pipe lists supported); `deny` always wins.
|
|
234
250
|
|
|
@@ -236,18 +252,19 @@ The MCP transport is fully bidirectional, so tools running inside the daemon can
|
|
|
236
252
|
|
|
237
253
|
---
|
|
238
254
|
|
|
239
|
-
## Extensibility: hooks, tasks, cron
|
|
255
|
+
## Extensibility: hooks, tasks, cron
|
|
240
256
|
|
|
241
|
-
|
|
257
|
+
Three primitives the agent uses directly (as `Local_*` tools) and you can drive from the CLI:
|
|
242
258
|
|
|
243
259
|
| Surface | What it is | CLI |
|
|
244
260
|
|---|---|---|
|
|
245
261
|
| **Hooks** | Lifecycle event handlers (pre/post tool, user prompt submit) | `cade hooks list / add / remove / test` |
|
|
246
|
-
| **Tasks** |
|
|
262
|
+
| **Tasks** | Durable work units that survive turn boundaries | `cade tasks list / get / create / update / delete` |
|
|
247
263
|
| **Cron** | Scheduled prompts the agent runs on a timer | `cade cron list / add / remove / enable / disable / run-now` |
|
|
248
|
-
| **Channels** | JSONL-backed inter-session pub/sub | `cade channels list / send / recv / clear` |
|
|
249
264
|
|
|
250
|
-
|
|
265
|
+
Cross-agent messaging is set up with `cade link` / `cade channel` (an agent can only
|
|
266
|
+
reach another it's been linked to). Hooks and tasks/cron details live in their
|
|
267
|
+
respective `cade <subcommand> --help` outputs.
|
|
251
268
|
|
|
252
269
|
---
|
|
253
270
|
|
|
@@ -259,9 +276,9 @@ Cade works with any OpenAI-compatible endpoint. Three ways to wire one in (CLI f
|
|
|
259
276
|
# CLI flag for Ollama. Use a model from `ollama list`.
|
|
260
277
|
cade chat -L --endpoint http://localhost:11434 --model qwen3:4b
|
|
261
278
|
|
|
262
|
-
#
|
|
263
|
-
cade
|
|
264
|
-
cade
|
|
279
|
+
# Or create a dedicated agent for the local model
|
|
280
|
+
cade new local-qwen --model qwen3:4b
|
|
281
|
+
cade use local-qwen
|
|
265
282
|
export OLLAMA_BASE_URL="http://localhost:11434"
|
|
266
283
|
CADE_LOCAL_ONLY=1 cade -m "hello from a local model"
|
|
267
284
|
|
|
@@ -281,12 +298,11 @@ All state lives under `~/.cade/`. Override the location with `CADE_HOME=/path/to
|
|
|
281
298
|
|
|
282
299
|
| File | Purpose |
|
|
283
300
|
|---|---|
|
|
284
|
-
| `config/cade.toml` |
|
|
285
|
-
| `
|
|
301
|
+
| `config/cade.toml` | Global settings + `[agent_defaults]` (model, provider, UI, …) |
|
|
302
|
+
| `config/agents/<name>.toml` | Per-agent config (model, prompt, `[[mcp]]`, `[serve]`, hooks) |
|
|
303
|
+
| `data/agents/<id>/` | Per-agent state: `threads/ memory/ tasks/ inbox/` |
|
|
304
|
+
| `run/agents/<name>/` | Per-agent daemon runtime: `serve.pid`, mcp-services, cron lease |
|
|
286
305
|
| `logs/cade.log` | Rotating log file |
|
|
287
|
-
| `config/contexts/<context>.toml [[mcp]]` | User MCP server registry |
|
|
288
|
-
| `config/contexts/<context>.toml [serve]` | `cade serve` daemon config |
|
|
289
|
-
| `personas/`, `memory/`, `tasks/`, `channels/` | Persona-scoped state |
|
|
290
306
|
|
|
291
307
|
Full layout, env vars, and TOML schema in [`docs/configuration.md`](./docs/configuration.md).
|
|
292
308
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The CLI agent from [Arcade.dev](https://arcade.dev). Coding, research, and everyday automation — driven from a terminal, a single shell pipe, or a long-lived daemon that replies over Telegram.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
|
|
6
|
+
curl -fsSL https://arcadeagent.dev/install | sh # or: uv tool install cade-cli | pip install cade-cli
|
|
7
7
|
cade login
|
|
8
8
|
cade
|
|
9
9
|
```
|
|
@@ -13,10 +13,10 @@ cade
|
|
|
13
13
|
## Highlights
|
|
14
14
|
|
|
15
15
|
- **Three deployment modes from the same binary.** Interactive chat (`cade`), one-shot or pipe (`cade -m "…"`), or a headless daemon that replies over messaging (`cade serve`).
|
|
16
|
-
- **Tools from anywhere.** Built-in local tools (filesystem / shell / git / search / tasks /
|
|
16
|
+
- **Tools from anywhere.** Built-in local tools (filesystem / shell / git / search / tasks / memory), [Arcade Cloud](https://arcade.dev) tools (Slack, GitHub, Gmail, calendars, …), and any [MCP](https://modelcontextprotocol.io/) server you register — all unified under one tool surface.
|
|
17
17
|
- **Bidirectional MCP.** Tools can call `context.ui.elicit(…)` for structured input, `context.log.*` for live operator logs, and `context.progress.report(…)` for editable progress UI — routed end-to-end through whichever adapter is active (Telegram inline keyboard, terminal prompt).
|
|
18
|
-
- **
|
|
19
|
-
- **Extensibility surface.** Hooks (lifecycle events), tasks (
|
|
18
|
+
- **Agents + per-agent memory.** Multiple agents, each with their own model, system prompt, tools, and an indexed memory store backed by [agent-library](https://pypi.org/project/agent-library/).
|
|
19
|
+
- **Extensibility surface.** Hooks (lifecycle events), tasks (durable work), cron (scheduled prompts) — all available to the agent as `Local_*` tools and to you as `cade <subcommand>`.
|
|
20
20
|
- **Bring your own LLM.** OpenAI, Anthropic, or any OpenAI-compatible endpoint (Ollama, vLLM, Together, Groq, Fireworks, …). `--local-only` skips Arcade Cloud entirely.
|
|
21
21
|
|
|
22
22
|
---
|
|
@@ -25,12 +25,21 @@ cade
|
|
|
25
25
|
|
|
26
26
|
| Source | Command |
|
|
27
27
|
|---|---|
|
|
28
|
-
|
|
|
28
|
+
| **Install script** (recommended) | `curl -fsSL https://arcadeagent.dev/install \| sh` |
|
|
29
29
|
| uv | `uv tool install cade-cli` |
|
|
30
30
|
| pip | `pip install cade-cli` |
|
|
31
31
|
| From source | `git clone https://github.com/arcadeai-labs/cade.git && cd cade && uv sync` |
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
The install script detects your OS/arch, downloads the matching prebuilt binary
|
|
34
|
+
(macOS arm64, Linux x64), verifies its checksum, and drops `cade` in
|
|
35
|
+
`~/.local/bin` — no GitHub token required. Pin a version or install location:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
CADE_VERSION=0.14.0 CADE_INSTALL_DIR=/usr/local/bin \
|
|
39
|
+
sh -c "$(curl -fsSL https://arcadeagent.dev/install)"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
(Windows: grab the `.zip` from the releases page, or `pip install cade-cli`.)
|
|
34
43
|
|
|
35
44
|
**Prerequisites:** Python 3.11+, an Arcade account ([arcade.dev](https://arcade.dev)) for cloud tools, and an LLM provider key (`OPENAI_API_KEY` or `ANTHROPIC_API_KEY`). Skip the Arcade account with `--local-only` or `CADE_LOCAL_ONLY=1`.
|
|
36
45
|
|
|
@@ -50,9 +59,9 @@ Full install and first-run docs: [`docs/install.md`](./docs/install.md) and
|
|
|
50
59
|
cade # interactive chat
|
|
51
60
|
cade -m "What changed in HEAD?" # single message, then exit
|
|
52
61
|
cade -m "What went wrong?" < error.log # prompt + file/stdin
|
|
53
|
-
cade
|
|
62
|
+
cade resume # resume the most recent thread
|
|
54
63
|
cade resume "auth-rewrite" # resume a thread by name
|
|
55
|
-
cade
|
|
64
|
+
cade use reviewer # switch the current agent
|
|
56
65
|
cade --voice # speak / hear (requires cade-cli[voice])
|
|
57
66
|
```
|
|
58
67
|
|
|
@@ -60,10 +69,8 @@ cade --voice # speak / hear (requires cade-cli[voi
|
|
|
60
69
|
|
|
61
70
|
| Flag | Description |
|
|
62
71
|
|---|---|
|
|
63
|
-
| `-r`, `--resume` | Resume most recent thread |
|
|
64
72
|
| `-m`, `--message` | Single-message mode; piped stdin is appended to the prompt |
|
|
65
|
-
|
|
|
66
|
-
| `-V`, `--voice` | Voice mode; install `cade-cli[voice]` first |
|
|
73
|
+
| `--voice` | Voice mode; install `cade-cli[voice]` first |
|
|
67
74
|
| `-v`, `--verbose` | Debug logging |
|
|
68
75
|
| `--version` | Print version |
|
|
69
76
|
|
|
@@ -77,7 +84,7 @@ cade --voice # speak / hear (requires cade-cli[voi
|
|
|
77
84
|
| `/logs` | Recent log entries |
|
|
78
85
|
| `/thread`, `/history` | Current thread info |
|
|
79
86
|
| `/pin`, `/unpin` | Pin reference material into the session |
|
|
80
|
-
| `/tasks`, `/cron`, `/hooks`, `/
|
|
87
|
+
| `/tasks`, `/cron`, `/hooks`, `/notify` | Coordination surfaces (mirrored as `cade tasks` / `cade cron` / `cade hooks`) |
|
|
81
88
|
| `/usage` | Context-window status and token usage |
|
|
82
89
|
| `/cd`, `/pwd`, `/!` | Shell shortcuts |
|
|
83
90
|
| `Ctrl+C` | Exit |
|
|
@@ -89,7 +96,7 @@ cade --voice # speak / hear (requires cade-cli[voi
|
|
|
89
96
|
Tools come from three sources and are addressed uniformly by their registered name:
|
|
90
97
|
|
|
91
98
|
- **`Local_*`** — built-in: filesystem (`ReadFile`, `WriteFile`, `Edit`, `ListFiles`), shell (`Bash`), `Search`, `Git`, `Task*`, `AskUserQuestion`, `RetrieveToolResult`, `ToolSchema`, `PinContext`, `PushNotification`, `WebFetch`, and `WebSearch`.
|
|
92
|
-
- **`Memory_*`** — agent-library backed, per-
|
|
99
|
+
- **`Memory_*`** — agent-library backed, per-agent indexed knowledge store.
|
|
93
100
|
- **Arcade Cloud + user MCP servers** — anything you register.
|
|
94
101
|
|
|
95
102
|
```bash
|
|
@@ -110,37 +117,46 @@ cade mcp authorize my-server # OAuth flow (browser)
|
|
|
110
117
|
cade mcp list / status / test / enable / disable / rm
|
|
111
118
|
```
|
|
112
119
|
|
|
113
|
-
User MCP servers register
|
|
120
|
+
User MCP servers register on the agent's `~/.cade/config/agents/<name>.toml [[mcp]]` list (with `cade.toml [agent_defaults].mcp` as the shared default). Servers with large catalogs are auto-deferred (parameter schemas stripped to keep tool-list bytes down) and fetched on demand via `Local_ToolSchema`.
|
|
114
121
|
|
|
115
122
|
---
|
|
116
123
|
|
|
117
|
-
##
|
|
124
|
+
## Agents + memory
|
|
125
|
+
|
|
126
|
+
Each **agent** bundles a model, system prompt, tools, and memory. The current
|
|
127
|
+
agent is ambient — most commands act on it.
|
|
118
128
|
|
|
119
129
|
```bash
|
|
120
|
-
cade
|
|
121
|
-
cade
|
|
130
|
+
cade new reviewer --prompt "You are a meticulous code reviewer." # create + switch
|
|
131
|
+
cade list # all agents
|
|
132
|
+
cade use reviewer # switch the current agent
|
|
133
|
+
cade info / cade edit reviewer # inspect / change config
|
|
122
134
|
|
|
123
|
-
cade mem
|
|
135
|
+
cade mem # the current agent's memory (status)
|
|
124
136
|
cade mem add ~/notes # index a directory
|
|
125
137
|
cade mem search "auth design" # semantic search
|
|
126
138
|
```
|
|
127
139
|
|
|
128
|
-
Memory is
|
|
140
|
+
Memory is per-agent — each agent has its own
|
|
141
|
+
`~/.cade/data/agents/<id>/memory/.librarian/` index, so a `reviewer` agent's
|
|
142
|
+
notes never leak into another.
|
|
129
143
|
|
|
130
144
|
---
|
|
131
145
|
|
|
132
146
|
## Headless daemon: `cade serve`
|
|
133
147
|
|
|
134
|
-
Run Cade as a long-lived daemon that replies through adapters. Telegram is supported for personal bot workflows, and Desktop exposes a local WebSocket for native clients. Each conversation gets its own persistent thread —
|
|
148
|
+
Run Cade as a long-lived daemon that replies through adapters. Telegram is supported for personal bot workflows, and Desktop exposes a local WebSocket for native clients. Each conversation gets its own persistent thread — model, memory, and tools carry across messages.
|
|
135
149
|
|
|
136
150
|
```bash
|
|
137
151
|
cade serve init # wizard: bot token, allowed senders
|
|
138
|
-
cade serve # foreground
|
|
152
|
+
cade serve # foreground (current agent)
|
|
153
|
+
cade serve --agent ops # serve a specific agent (one daemon per agent)
|
|
154
|
+
cade serve list # agents with a running daemon
|
|
139
155
|
cade serve --install launchd # macOS LaunchAgent (or --install systemd)
|
|
140
156
|
cade serve status / stop # health, uptime; SIGTERM running daemon
|
|
141
157
|
```
|
|
142
158
|
|
|
143
|
-
|
|
159
|
+
Each agent's serve config lives in `~/.cade/config/agents/<name>.toml [serve]`. Edit and `kill -HUP $(cat ~/.cade/run/agents/<name>/serve.pid)` to reload without restart.
|
|
144
160
|
|
|
145
161
|
**Security defaults are fail-closed:** `allowed_senders = []` blocks everyone; tools are default-deny against `[serve.tools].allow` (globs / regex / pipe lists supported); `deny` always wins.
|
|
146
162
|
|
|
@@ -148,18 +164,19 @@ The MCP transport is fully bidirectional, so tools running inside the daemon can
|
|
|
148
164
|
|
|
149
165
|
---
|
|
150
166
|
|
|
151
|
-
## Extensibility: hooks, tasks, cron
|
|
167
|
+
## Extensibility: hooks, tasks, cron
|
|
152
168
|
|
|
153
|
-
|
|
169
|
+
Three primitives the agent uses directly (as `Local_*` tools) and you can drive from the CLI:
|
|
154
170
|
|
|
155
171
|
| Surface | What it is | CLI |
|
|
156
172
|
|---|---|---|
|
|
157
173
|
| **Hooks** | Lifecycle event handlers (pre/post tool, user prompt submit) | `cade hooks list / add / remove / test` |
|
|
158
|
-
| **Tasks** |
|
|
174
|
+
| **Tasks** | Durable work units that survive turn boundaries | `cade tasks list / get / create / update / delete` |
|
|
159
175
|
| **Cron** | Scheduled prompts the agent runs on a timer | `cade cron list / add / remove / enable / disable / run-now` |
|
|
160
|
-
| **Channels** | JSONL-backed inter-session pub/sub | `cade channels list / send / recv / clear` |
|
|
161
176
|
|
|
162
|
-
|
|
177
|
+
Cross-agent messaging is set up with `cade link` / `cade channel` (an agent can only
|
|
178
|
+
reach another it's been linked to). Hooks and tasks/cron details live in their
|
|
179
|
+
respective `cade <subcommand> --help` outputs.
|
|
163
180
|
|
|
164
181
|
---
|
|
165
182
|
|
|
@@ -171,9 +188,9 @@ Cade works with any OpenAI-compatible endpoint. Three ways to wire one in (CLI f
|
|
|
171
188
|
# CLI flag for Ollama. Use a model from `ollama list`.
|
|
172
189
|
cade chat -L --endpoint http://localhost:11434 --model qwen3:4b
|
|
173
190
|
|
|
174
|
-
#
|
|
175
|
-
cade
|
|
176
|
-
cade
|
|
191
|
+
# Or create a dedicated agent for the local model
|
|
192
|
+
cade new local-qwen --model qwen3:4b
|
|
193
|
+
cade use local-qwen
|
|
177
194
|
export OLLAMA_BASE_URL="http://localhost:11434"
|
|
178
195
|
CADE_LOCAL_ONLY=1 cade -m "hello from a local model"
|
|
179
196
|
|
|
@@ -193,12 +210,11 @@ All state lives under `~/.cade/`. Override the location with `CADE_HOME=/path/to
|
|
|
193
210
|
|
|
194
211
|
| File | Purpose |
|
|
195
212
|
|---|---|
|
|
196
|
-
| `config/cade.toml` |
|
|
197
|
-
| `
|
|
213
|
+
| `config/cade.toml` | Global settings + `[agent_defaults]` (model, provider, UI, …) |
|
|
214
|
+
| `config/agents/<name>.toml` | Per-agent config (model, prompt, `[[mcp]]`, `[serve]`, hooks) |
|
|
215
|
+
| `data/agents/<id>/` | Per-agent state: `threads/ memory/ tasks/ inbox/` |
|
|
216
|
+
| `run/agents/<name>/` | Per-agent daemon runtime: `serve.pid`, mcp-services, cron lease |
|
|
198
217
|
| `logs/cade.log` | Rotating log file |
|
|
199
|
-
| `config/contexts/<context>.toml [[mcp]]` | User MCP server registry |
|
|
200
|
-
| `config/contexts/<context>.toml [serve]` | `cade serve` daemon config |
|
|
201
|
-
| `personas/`, `memory/`, `tasks/`, `channels/` | Persona-scoped state |
|
|
202
218
|
|
|
203
219
|
Full layout, env vars, and TOML schema in [`docs/configuration.md`](./docs/configuration.md).
|
|
204
220
|
|
|
@@ -19,6 +19,9 @@ patch_frozen_return_detection()
|
|
|
19
19
|
|
|
20
20
|
from cade_mcp_local.resources import register_resources # noqa: E402
|
|
21
21
|
from cade_mcp_local.tools import ( # noqa: E402
|
|
22
|
+
agent_list_tool,
|
|
23
|
+
agent_send_tool,
|
|
24
|
+
agent_spawn_tool,
|
|
22
25
|
ask_user_question_tool,
|
|
23
26
|
bash_tool,
|
|
24
27
|
edit_tool,
|
|
@@ -54,6 +57,10 @@ is running. Use these tools when you need to:
|
|
|
54
57
|
TaskUpdate, TaskDelete) — the host registers them as Local_* names
|
|
55
58
|
- PushNotification to inject a structured notice into the agent context at the next
|
|
56
59
|
tool boundary
|
|
60
|
+
- AgentSend / AgentList to coordinate with other agents the user has linked to this
|
|
61
|
+
one (ACL-gated; delivered to the target agent's inbox)
|
|
62
|
+
- AgentSpawn to delegate a self-contained sub-task to a fresh child agent and get
|
|
63
|
+
back just its result (requires this agent to allow spawning)
|
|
57
64
|
- AskUserQuestion when you need structured clarification from the user (host:
|
|
58
65
|
Local_AskUserQuestion)
|
|
59
66
|
- WebFetch to read an external URL (Firecrawl via Arcade by default, httpx
|
|
@@ -112,6 +119,12 @@ def create_app() -> MCPApp:
|
|
|
112
119
|
# Notifications (inject XML into context at next tool boundary)
|
|
113
120
|
app.add_tool(push_notification_tool)
|
|
114
121
|
|
|
122
|
+
# Cross-agent coordination (ACL-gated; delivers to another agent's inbox)
|
|
123
|
+
app.add_tool(agent_send_tool)
|
|
124
|
+
app.add_tool(agent_list_tool)
|
|
125
|
+
# Spawn an ephemeral child task-agent (opt-in via the agent's allow_spawn)
|
|
126
|
+
app.add_tool(agent_spawn_tool)
|
|
127
|
+
|
|
115
128
|
# Structured clarification question for the user
|
|
116
129
|
app.add_tool(ask_user_question_tool)
|
|
117
130
|
|
|
@@ -5,6 +5,7 @@ is running. Use these tools when you need to read, write, search, or execute
|
|
|
5
5
|
commands on the same machine as the running cade process.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
from cade_mcp_local.tools.agents import agent_list_tool, agent_send_tool, agent_spawn_tool
|
|
8
9
|
from cade_mcp_local.tools.context import search_recent_context_tool
|
|
9
10
|
from cade_mcp_local.tools.filesystem import (
|
|
10
11
|
edit_tool,
|
|
@@ -62,6 +63,10 @@ __all__ = [
|
|
|
62
63
|
"task_delete_tool",
|
|
63
64
|
# Notifications
|
|
64
65
|
"push_notification_tool",
|
|
66
|
+
# Cross-agent coordination
|
|
67
|
+
"agent_send_tool",
|
|
68
|
+
"agent_list_tool",
|
|
69
|
+
"agent_spawn_tool",
|
|
65
70
|
# Interactive
|
|
66
71
|
"ask_user_question_tool",
|
|
67
72
|
# Web
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""MCP tools for cross-agent coordination.
|
|
2
|
+
|
|
3
|
+
Lets the model address other agents the user has explicitly linked. Delivery
|
|
4
|
+
rides the durable per-agent inbox (so the message survives until the target
|
|
5
|
+
agent's next turn), and the user-provisioned channel ACL gates every send:
|
|
6
|
+
two top-level agents can talk only if a user ran ``cade link`` / added them to
|
|
7
|
+
a shared channel. The default is isolation.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Annotated, Any
|
|
12
|
+
|
|
13
|
+
from arcade_mcp_server import Context, tool
|
|
14
|
+
from typing_extensions import TypedDict
|
|
15
|
+
|
|
16
|
+
from cade_mcp_local._metadata import CREATE_META, READ_META
|
|
17
|
+
from cade_mcp_local.errors import InvalidInputError
|
|
18
|
+
from cadecoder.core import agent as agent_mod
|
|
19
|
+
from cadecoder.core import comms as comms_mod
|
|
20
|
+
from cadecoder.core.inbox import inbox_for_path
|
|
21
|
+
from cadecoder.core.paths import get_paths
|
|
22
|
+
|
|
23
|
+
log = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AgentSendOutput(TypedDict):
|
|
27
|
+
delivered: bool
|
|
28
|
+
target: str
|
|
29
|
+
target_id: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AgentSpawnOutput(TypedDict):
|
|
33
|
+
agent: str
|
|
34
|
+
id: str
|
|
35
|
+
result: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class AgentListOutput(TypedDict):
|
|
39
|
+
agents: list[dict[str, Any]]
|
|
40
|
+
count: int
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _agent_from_request_meta() -> str | None:
|
|
44
|
+
"""Per-request acting agent from MCP ``_meta['cade/agent']``, if the host set it.
|
|
45
|
+
|
|
46
|
+
The cade host stamps this on every built-in ``tools/call`` so the agent
|
|
47
|
+
resolves per-request rather than from this subprocess's env/state. Returns
|
|
48
|
+
``None`` when running outside a request context (tests, one-shot CLI).
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
from arcade_mcp_server.request_context import get_request_meta
|
|
52
|
+
except Exception:
|
|
53
|
+
return None
|
|
54
|
+
meta = get_request_meta()
|
|
55
|
+
if meta is None:
|
|
56
|
+
return None
|
|
57
|
+
return meta.__dict__.get("cade/agent")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _current_agent_name() -> str:
|
|
61
|
+
name = _agent_from_request_meta() or agent_mod.get_active_agent_name()
|
|
62
|
+
if not name:
|
|
63
|
+
raise InvalidInputError("agent", "no current agent is set")
|
|
64
|
+
return name
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@tool(
|
|
68
|
+
name="AgentSend",
|
|
69
|
+
desc=(
|
|
70
|
+
"Send a message to another agent's inbox. Only works for agents a user "
|
|
71
|
+
"has linked to this one (via `cade link` or a shared channel); otherwise "
|
|
72
|
+
"the send is refused. The message is delivered at the target agent's next "
|
|
73
|
+
"turn. Use AgentList first to see who you can reach."
|
|
74
|
+
),
|
|
75
|
+
metadata=CREATE_META,
|
|
76
|
+
)
|
|
77
|
+
def agent_send_tool(
|
|
78
|
+
context: Context,
|
|
79
|
+
target: Annotated[str, "Target agent name, id, or unique id prefix."],
|
|
80
|
+
message: Annotated[str, "Message to deliver to the target agent."],
|
|
81
|
+
) -> Annotated[AgentSendOutput, "Delivery result."]:
|
|
82
|
+
if not message.strip():
|
|
83
|
+
raise InvalidInputError("message", "cannot be empty")
|
|
84
|
+
sender = _current_agent_name()
|
|
85
|
+
target_agent = agent_mod.resolve(target)
|
|
86
|
+
if target_agent is None:
|
|
87
|
+
raise InvalidInputError("target", f"agent '{target}' not found")
|
|
88
|
+
if not comms_mod.can_communicate(sender, target_agent.name):
|
|
89
|
+
raise InvalidInputError(
|
|
90
|
+
"target",
|
|
91
|
+
f"not linked with '{target_agent.name}'. A user must run: "
|
|
92
|
+
f"cade link {sender} {target_agent.name}",
|
|
93
|
+
)
|
|
94
|
+
inbox = inbox_for_path(get_paths().agent_data(target_agent.id))
|
|
95
|
+
inbox.enqueue_notification(message, source=f"agent:{sender}")
|
|
96
|
+
return {"delivered": True, "target": target_agent.name, "target_id": target_agent.id}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@tool(
|
|
100
|
+
name="AgentSpawn",
|
|
101
|
+
desc=(
|
|
102
|
+
"Delegate a focused sub-task to a fresh child agent that runs in its own "
|
|
103
|
+
"process and context, returning just the result (keeps your context "
|
|
104
|
+
"clean). Only works if this agent was created with --allow-spawn. Blocks "
|
|
105
|
+
"until the child finishes."
|
|
106
|
+
),
|
|
107
|
+
metadata=CREATE_META,
|
|
108
|
+
)
|
|
109
|
+
async def agent_spawn_tool(
|
|
110
|
+
context: Context,
|
|
111
|
+
task: Annotated[str, "The self-contained sub-task for the child agent."],
|
|
112
|
+
) -> Annotated[AgentSpawnOutput, "The child agent and its result."]:
|
|
113
|
+
from cadecoder.core.spawn import SpawnError, spawn_task_agent
|
|
114
|
+
|
|
115
|
+
if not task.strip():
|
|
116
|
+
raise InvalidInputError("task", "cannot be empty")
|
|
117
|
+
# Resolve the parent from the per-request agent identity so the child is
|
|
118
|
+
# attributed to the calling agent, not this subprocess's env/state.
|
|
119
|
+
parent_name = _agent_from_request_meta()
|
|
120
|
+
parent = agent_mod.resolve(parent_name) if parent_name else None
|
|
121
|
+
try:
|
|
122
|
+
return await spawn_task_agent(task, parent=parent) # type: ignore[return-value]
|
|
123
|
+
except SpawnError as e:
|
|
124
|
+
raise InvalidInputError("task", str(e)) from e
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@tool(
|
|
128
|
+
name="AgentList",
|
|
129
|
+
desc=(
|
|
130
|
+
"List the agents you can message — i.e. agents a user has linked to this "
|
|
131
|
+
"one through a shared channel. Returns an empty list when you are isolated."
|
|
132
|
+
),
|
|
133
|
+
metadata=READ_META,
|
|
134
|
+
)
|
|
135
|
+
def agent_list_tool(
|
|
136
|
+
context: Context,
|
|
137
|
+
) -> Annotated[AgentListOutput, "Reachable agents."]:
|
|
138
|
+
sender = _current_agent_name()
|
|
139
|
+
reachable: list[dict[str, Any]] = []
|
|
140
|
+
for candidate in agent_mod.list_agents():
|
|
141
|
+
if candidate.name == sender:
|
|
142
|
+
continue
|
|
143
|
+
if comms_mod.can_communicate(sender, candidate.name):
|
|
144
|
+
reachable.append(
|
|
145
|
+
{
|
|
146
|
+
"name": candidate.name,
|
|
147
|
+
"id": candidate.id,
|
|
148
|
+
"description": candidate.description,
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
return {"agents": reachable, "count": len(reachable)}
|
|
@@ -9,7 +9,7 @@ from typing_extensions import TypedDict
|
|
|
9
9
|
|
|
10
10
|
from cade_mcp_local._metadata import CREATE_META
|
|
11
11
|
from cade_mcp_local.errors import InvalidInputError
|
|
12
|
-
from cadecoder.
|
|
12
|
+
from cadecoder.core.inbox import current_inbox
|
|
13
13
|
|
|
14
14
|
log = logging.getLogger(__name__)
|
|
15
15
|
|
|
@@ -45,5 +45,5 @@ def push_notification_tool(
|
|
|
45
45
|
raise InvalidInputError("message", "cannot be empty")
|
|
46
46
|
level_value = level.value if isinstance(level, NotificationLevel) else str(level)
|
|
47
47
|
xml = f"<notification>\n <level>{level_value}</level>\n <message>{message}</message>\n</notification>"
|
|
48
|
-
|
|
48
|
+
current_inbox().enqueue(xml)
|
|
49
49
|
return {"queued": True, "level": level_value}
|