Major changes: - Config-driven adapters: all channels (Slack, Discord, Telegram, WebChat, Webhooks) controlled via config.json with enabled flags and token auto-detection, no CLI flags required - Runtime engine field: runtime.engine selects opencode/claude from config - Interactive install script: 8-phase setup wizard with AI runtime detection/installation, token setup, identity file personalization (personality presets), aetheel CLI command, background service (launchd/systemd) - Live runtime switching: /engine, /model, /provider commands hot-swap the AI runtime from chat without restart, changes persisted to config.json - Usage tracking: per-request cost extraction from Claude Code JSON output, cumulative stats via /usage command - Auto-failover: rate limit detection on both runtimes, automatic switch to other engine on quota errors with user notification - Chat commands work without / prefix (Slack intercepts / in channels), commands: engine, model, provider, config, usage, reload, cron, subagents, status, help - /config set for editing config.json from chat with dotted key notation - Security audit saved to docs/security-audit.md - Full command reference in docs/commands.md - Future changes doc with NanoClaw agent teams analysis - Logo added to README and WebChat UI - README fully rewritten with all features documented
7.8 KiB
Aetheel vs Nanoclaw: Feature Comparison & OpenCode Assessment
Aetheel is a solid reimplementation of the core nanoclaw concept in Python, but there are meaningful gaps. Here's what maps, what's missing, and where the opencode integration could be improved.
What Aetheel Has (Maps Well to Nanoclaw)
| Feature | Nanoclaw | Aetheel | Status |
|---|---|---|---|
| Multi-channel adapters | WhatsApp (baileys) | Slack + Telegram | ✅ Good — cleaner abstraction via BaseAdapter |
| Session isolation | Per-group sessions | Per-thread sessions via SessionStore |
✅ Good |
| Dual runtime support | Claude Code SDK only | OpenCode (CLI+SDK) + Claude Code CLI | ✅ Good — more flexible |
| Scheduled tasks | Cron + interval + once via MCP tool | Cron + one-shot via APScheduler | ✅ Good |
| Subagent spawning | SDK Task/TeamCreate tools |
Background threads via SubagentManager |
✅ Basic |
| Memory system | CLAUDE.md files per group | SOUL.md + USER.md + MEMORY.md + hybrid search | ✅ Better — vector + BM25 search |
| Skills system | .claude/skills/ with SKILL.md |
skills/<name>/SKILL.md with trigger matching |
✅ Good |
| Action tags | MCP tools (send_message, schedule_task) | Regex-parsed [ACTION:remind|...] tags |
✅ Different approach, works |
What's Missing from Aetheel
1. Container Isolation
Nanoclaw's biggest architectural feature. Every agent runs in an isolated Apple Container (or Docker) with controlled volume mounts, secret injection via stdin, and per-group IPC namespaces. Aetheel runs everything in the same process. This means:
- No sandboxing of agent tool use (bash, file writes)
- No mount-based security boundaries between groups
- Secrets are in the process environment, not isolated
2. MCP Server Integration
Nanoclaw runs a custom MCP server (ipc-mcp-stdio.ts) inside the container that gives the agent tools like send_message, schedule_task, register_group. Aetheel uses regex-parsed action tags instead, which is fragile — the AI has to format tags perfectly, and there's no validation or structured tool calling.
3. Multi-Group Support
Nanoclaw has per-group folders, per-group memory (CLAUDE.md), per-group IPC, and a global memory layer. Aetheel has a single workspace with shared memory files. No group isolation.
4. Persistent Conversation Sessions on Disk
Nanoclaw stores sessions as JSONL files in data/sessions/{group}/.claude/ and can resume at a specific assistant message UUID. Aetheel's SessionStore is in-memory only — sessions are lost on restart.
5. IPC Message Streaming
Nanoclaw's agent runner uses a MessageStream (AsyncIterable) to pipe follow-up messages into an active agent query. The host can send new messages to a running agent via IPC files. Aetheel's runtime is request-response only — one message in, one response out.
6. Transcript Archiving
Nanoclaw archives full conversation transcripts to markdown before context compaction via a PreCompact hook. Aetheel logs sessions to daily files but doesn't handle compaction.
7. Group Registration
Nanoclaw lets the main agent register new groups dynamically via an MCP tool. Aetheel has no equivalent.
8. Idle Timeout / Session Lifecycle
Nanoclaw has a 30-minute idle timeout that closes the container stdin, ending the session gracefully. Aetheel has session TTL cleanup but no active lifecycle management.
OpenCode Integration Assessment
The opencode runtime implementation in agent/opencode_runtime.py is well-structured. Here's what's correct and what needs attention.
What's Done Well
- Dual mode (CLI + SDK) with graceful fallback from SDK to CLI
- Binary auto-discovery across common install paths
- JSONL event parsing for
opencode run --format jsonoutput - Session ID extraction from event stream
- System prompt injection via XML tags (correct workaround since
opencode rundoesn't have--system-prompt) - Config from environment variables
Issues / Improvements Needed
1. SDK Client API Mismatch
The code calls self._sdk_client.session.chat(session_id, **chat_kwargs) but the opencode Python SDK uses client.session.prompt() not .chat(). The correct call is:
response = self._sdk_client.session.prompt(
path={"id": session_id},
body={"parts": parts, "model": model_config}
)
2. SDK Client Initialization
The code uses from opencode_ai import Opencode but the actual SDK package is @opencode-ai/sdk (JS/TS) or opencode-sdk-python (Python). The Python SDK uses createOpencodeClient pattern. Verify the actual Python SDK import path — it may be from opencode import Client or similar depending on the package version.
3. No --continue Flag Validation
The CLI mode passes --continue and --session for session continuity, but opencode run may not support --continue the same way as the TUI. The opencode run command is designed for single-shot execution. For session continuity in CLI mode, you'd need to use the SDK mode with opencode serve.
4. Missing --system Flag
The code injects system prompts as XML in the message body. This works but is a workaround. The SDK mode's client.session.prompt() supports a system parameter in the body, which would be cleaner.
5. No Structured Output Support
Opencode's SDK supports format: { type: "json_schema", schema: {...} } for structured responses. This could replace the fragile [ACTION:...] regex parsing with proper tool calls.
6. No Plugin/Hook Integration
Opencode has a plugin system (tool.execute.before, tool.execute.after, experimental.session.compacting) that could replace the action tag parsing. You could create an opencode plugin that exposes send_message and schedule_task as custom tools, similar to nanoclaw's MCP approach.
7. Session Persistence
SessionStore is in-memory. Opencode's server persists sessions natively, so in SDK mode you could rely on the server's session storage and just map conversation_id → opencode_session_id in a SQLite table.
Architectural Gap Summary
The biggest architectural gap isn't about opencode specifically — it's that Aetheel runs the agent in-process without isolation, while nanoclaw's container model is what makes it safe to give the agent bash access and file write tools.
To close that gap, options include:
- Containerize the opencode runtime — run
opencode serveinside a Docker container with controlled mounts - Use opencode's permission system — configure all dangerous tools to
"ask"or"deny"per agent - Add an MCP server — replace action tag regex parsing with proper MCP tools for
send_message,schedule_task, etc. - Persist sessions to SQLite — survive restarts and enable resume-at-message functionality
Nanoclaw Features → Opencode Equivalents
| Nanoclaw (Claude Code SDK) | Opencode Equivalent | Gap Level |
|---|---|---|
query() async iterable |
HTTP server + SDK client.session.prompt() |
🔴 Architecture change needed |
resume + resumeSessionAt |
POST /session/:id/message |
🟡 No resume-at-UUID equivalent |
| Streaming message types (system/init, assistant, result) | SSE events via GET /event |
🟡 Different event schema |
PreCompact hook |
experimental.session.compacting plugin |
🟢 Similar concept, different API |
PreToolUse hook (bash sanitization) |
tool.execute.before plugin |
🟢 Similar concept, different API |
bypassPermissions |
Per-tool permission config set to "allow" |
🟢 Direct mapping |
isSingleUserTurn: false via AsyncIterable |
prompt_async endpoint |
🟡 Needs verification |
CLAUDE.md auto-loading via settingSources |
AGENTS.md convention | 🟢 Rename files |
Secrets via env param on query() |
shell.env plugin hook |
🟡 Different isolation model |
MCP servers in query() config |
opencode.json mcp config or POST /mcp |
🟢 Direct mapping |