-
Notifications
You must be signed in to change notification settings - Fork 23
Description
Overview
Two related features that together enable Condor users to edit Hummingbot config files, create strategies, and manage running bots directly from Telegram via Claude Code — without leaving the chat.
- Feature A: Implement ACP filesystem + terminal capabilities so Claude Code can read/write files and run shell commands on behalf of the user
- Feature B: Add a
/acpinline menu giving users operational control over ACP sessions (steer, permissions, cwd, model, sessions list)
These are intentionally left unimplemented for now; this issue tracks the design and intent.
Background
Condor already acts as an ACP client, spawning Claude Code via claude-agent-acp and exchanging session/new + session/prompt messages over stdio. The core flow works. What's missing is:
- ACP optional capabilities — Condor doesn't advertise
fsorterminalcapabilities during theinitializehandshake, so Claude Code never attempts file or shell operations. - Session control UI — The current
/agentmenu has basic start/stop/status but no way to steer a running session, change the working directory, set permission levels, switch models, or see all active sessions.
Feature A: ACP Filesystem + Terminal Capabilities
What Needs to Be Implemented
Capability advertisement (in condor/acp/client.py, initialize response):
{
"capabilities": {
"fs": {
"readTextFile": True,
"writeTextFile": True
},
"terminal": True
}
}Filesystem handlers (agent → Condor callbacks):
| Method | Params | Returns |
|---|---|---|
fs/read_text_file |
{path: str} |
{content: str} |
fs/write_text_file |
{path: str, content: str} |
{} |
Terminal handlers:
| Method | Params | Returns |
|---|---|---|
terminal/create |
{command: [str], cwd?: str, env?: dict} |
{terminalId: str} |
terminal/output |
{terminalId: str} |
{output: str, exitCode?: int} |
terminal/release |
{terminalId: str} |
{} |
terminal/wait_for_exit |
{terminalId: str, timeout?: int} |
{exitCode: int} |
terminal/kill |
{terminalId: str} |
{} |
Security Model
This is the most critical part. Since Condor is a Telegram bot, arbitrary-path access must be prevented.
Read allowlist (paths Claude Code may read without approval):
~/hummingbot-api/bots/
~/hummingbot/conf/
~/hummingbot-skills/
~/.agents/
Write allowlist (writes only permitted inside):
~/hummingbot-api/bots/instances/*/conf/controllers/
~/hummingbot-api/bots/instances/*/conf/scripts/
~/hummingbot-api/bots/controllers/
~/hummingbot-api/bots/scripts/
Write approval gate: Every fs/write_text_file call must pause execution and send a Telegram message showing a unified diff with [✅ Approve] / [❌ Cancel] buttons before the write occurs. Same pattern as session/request_permission.
Terminal approval gate: Every terminal/create call shows the full command + working directory to the user before spawning. A hardcoded blocklist rejects obviously dangerous patterns (rm -rf /, curl | bash, writes outside allowed dirs, etc.).
Audit log: When operating in approve-all mode (see Feature B), auto-approved writes and terminal commands must still post a silent notification to Telegram so nothing is invisible.
Terminal Implementation Notes
- Use
asyncio.create_subprocess_exec(not shell=True) with stdout+stderr piped - In-memory terminal registry:
dict[terminalId, asyncio.subprocess.Process]+ output buffer per terminal - Background task per terminal reads stdout continuously and appends to buffer
terminal/outputdrains the buffer and returns current exit code (None if still running)terminal/wait_for_exitpolls untilreturncode is not Noneor timeout
Proposed File Structure
condor/acp/
├── client.py ← add _handle_fs_* and _handle_terminal_* dispatchers
├── fs.py ← NEW: path validation, read/write, diff generation, approval flow
└── terminal.py ← NEW: subprocess registry, output buffering, approval gate
End-to-End UX Example
User: "Update my perc_sell_rebalancer to use position_width_pct=30 and restart the bot"
(Claude Code calls
fs/read_text_fileon the controller YAML — auto-approved)Condor → Telegram:
📝 Claude wants to edit a file:
perc_sell_rebalancer.yml- position_width_pct: 40 + position_width_pct: 30[✅ Approve] [❌ Cancel]
(User approves → file written)
Condor → Telegram:
💻 Claude wants to run:
docker restart perc_sell_bot-20260227-...
[✅ Run] [❌ Cancel](User approves → output streamed back)
Condor: ✅ Bot restarted.
Feature B: /acp Inline Menu
Motivation
OpenClaw (reference implementation) exposes a full /acp command family: spawn, cancel, steer, close, status, cwd, permissions, model, sessions, doctor. Condor's current /agent menu covers spawn/cancel/close/status but is missing the operational controls that become essential once filesystem and terminal capabilities are live.
Commands to Implement (Priority Order)
1. Steer — highest leverage, no security implications
Inject a mid-session instruction without losing context. User taps [⚡ Steer], sends a message, it's delivered to the running Claude Code session as a steering nudge. Avoids needing to start a fresh session when you just want to redirect focus.
2. Permissions — required before fs/terminal goes live
Surface the permission mode as selectable buttons:
| Mode | Behavior |
|---|---|
approve-reads |
Reads auto-approved; writes + exec require per-operation approval (default) |
approve-all |
All operations auto-approved; audit log sent to Telegram |
deny-all |
All write/exec attempts denied gracefully |
Stored per-user in the existing pickle store.
3. CWD picker — required for Hummingbot config editing
Preset list (not free text) to avoid path injection:
~/hummingbot-api/bots/— bot instances and configs~/hummingbot/conf/— connectors and global settings~/hummingbot-skills/— skills repo~/condor/— Condor source- Custom path (requires explicit confirm step)
4. Sessions list — operational visibility
List active + recent sessions with key, label, model, start time, and context usage %. One tap to resume or close any session.
5. Model switcher — cost control
Switch mid-session between configured models (e.g. Claude Sonnet → Haiku → Gemini Flash).
Commands to Skip / Defer
- Thread binding — Telegram topics work but most Condor users are in DMs; low value for now
/acp set-mode— Depends onsession/set_modebeing exposed by the agent; not confirmed available/acp timeout— Fine to hardcode 120s for now/acp doctor— Nice to have eventually; low priority/acp install— Operator tooling, not user-facing
Proposed Menu Structure
/acp → inline menu
🤖 ACP Session
───────────────
[▶ Start] [⏹ Stop] [📊 Status]
── Controls ──
[⚡ Steer] [📁 CWD]
[🔐 Permissions] [🧠 Model]
── Sessions ──
[📋 List]
Proposed File Structure
handlers/agents/
├── __init__.py ← add /acp alias, extend dispatch
├── menu.py ← extend with new buttons
├── acp/ ← NEW subdirectory
│ ├── steer.py ← inject steer into active session
│ ├── permissions.py ← permissionMode state management per user
│ ├── cwd.py ← preset + custom cwd selector
│ ├── sessions.py ← list/resume/close sessions
│ └── model.py ← model switcher
Implementation Order
- Feature B: Steer (no security implications, immediately useful)
- Feature B: Permissions UI (required before fs/terminal)
- Feature A:
fs/read_text_file(low risk, no approval gate needed) - Feature A:
fs/write_text_file+ write approval gate - Feature B: CWD picker
- Feature A:
terminal/create+ terminal approval gate + remaining terminal methods - Feature B: Sessions list
- Feature B: Model switcher
Reference
- ACP protocol overview: https://agentclientprotocol.com/protocol/overview
- ACP filesystem spec: https://agentclientprotocol.com/protocol/file-system
- ACP terminal spec: https://agentclientprotocol.com/protocol/terminals
- OpenClaw
/acpreference: https://docs.openclaw.ai/tools/acp-agents