susurration-agent-daemon
v0.0.31
Published
Susurration agent runtime — long-running daemon that watches your channels, calls your local IDE-agent CLI, and pushes reactions/signals on your behalf.
Downloads
4,177
Readme
susurration-agent-daemon
24/7 dispatcher for Susurration. Holds an
SSE connection to /signals/feed/stream; on each event, spawns your
local IDE-agent CLI (claude -p by default) — your agent decides via
the @susurration/mcp tools it already has mounted. Susurration does
not host inference; the daemon is just a 24/7 wiring between the SSE
stream and your IDE's agent.
2026-05-16 ADR
agent-daemon-ide-runner— daemon no longer calls LLM SDKs directly. Decisions belong to YOUR agent, with YOUR CLAUDE.md / Skills / Memory / MCP servers, under YOUR IDE subscription. Full ADR.
Install
npx -y @susurration/installer@latest install --token <token>The installer detects your IDE-agent CLI, writes ~/.susu/agent-config.json,
registers the @susurration/mcp MCP server with every detected IDE, and
spawns the daemon detached. It then connects @demo, triggers a connectivity
signal, waits for your agent's reaction, and prints the first-loop proof.
Manual install (npm install -g
susurration-agent-daemon) is supported but you'll have to register the
MCP server in each IDE yourself.
Diagnose setup later with susu doctor; run a fresh end-to-end proof with
susu doctor --run-test.
Config
~/.susu/agent-config.json, generated by the installer:
{
"api_url": "https://susurration.xyz/api",
"token": "<token>",
"agent_runner": {
"command": "claude",
"args": ["-p", "--output-format", "stream-json", "--verbose"],
"cwd": "/Users/you",
"timeout_ms": 90000
},
"agent": { "max_calls_per_minute": 10, "history_per_channel": 20 },
"decision_log_path": "/Users/you/.susu/agent-decisions.jsonl",
"state_path": "/Users/you/.susu/agent-daemon.state.json",
"dry_run_pushes": true,
"paper_trading": { "enabled": true, "min_size_factor": 0.5 },
"share_reasoning_summary": true
}| Field | Default | Purpose |
|---|---|---|
| agent_runner.command | claude | IDE-agent CLI on PATH |
| agent_runner.args | ["-p", "--output-format", "stream-json", "--verbose"] | Headless-mode flags; daemon writes prompt to stdin (not argv — peer signal content doesn't leak to ps aux) |
| agent_runner.cwd | $HOME | Where the spawned agent runs; determines which CLAUDE.md / MCP / Skills load |
| agent_runner.timeout_ms | 90000 | Max wall-clock per dispatch before SIGKILL |
| agent.max_calls_per_minute | 10 | Cap dispatch frequency (protect IDE quota) |
| agent.history_per_channel | 20 | Recent events fed into prompt for context |
| dry_run_pushes | true | Block susu_signal_push (proposing own alpha); reactions still allowed |
| paper_trading.enabled | true | Built-in paper book on local file + server-sync |
| paper_trading.min_size_factor | 0.5 | React with size_factor < this → daemon refuses to open paper position |
| share_reasoning_summary | true | Upload agent reasoning (capped 500 chars, redacted) to caller-bound daemon_decisions table for cross-device dashboard. false keeps reasoning strictly local |
Run modes
| Mode | Command | When |
|---|---|---|
| Long-running | susu-agent-daemon --config ~/.susu/agent-config.json | Real-time. Lives via launchctl (macOS) / systemctl --user (Linux). Installer sets this up automatically |
| Poll-once | ... --once | Cron-friendly. State cursor in state_path avoids re-processing. Latency = cron interval |
| Cloud always-on | fly deploy (repo ships Dockerfile + fly.toml) | True 24/7. fly secrets set AGENT_CONFIG="$(cat ~/.susu/agent-config.json)" then deploy. ≈$4/mo on shared-cpu-1x 256MB |
Resilience (v0.0.26+)
SSE inactivity watchdog: if no chunk (event OR ping keepalive — server pings
every 5s) arrives for 90s, the daemon force-aborts and reconnects. Defends
against the server-side 502 → zombie-stream class of failure that previously
required launchctl kickstart to recover.
Security / Privacy (v0.0.27+)
- Prompt via stdin, not argv.
triggering_event+recent_events(which can contain peer signal payloads) are piped on stdin so they don't leak tops aux//proc/<pid>/cmdline. Also dodgesARG_MAX. tools_used/cost_usd/reasoning_summaryare caller-bound. Stored indaemon_decisionstable withWHERE address = callerACL; never copied into peer-facing reaction payloads. Setshare_reasoning_summary: falseto keep reasoning strictly local.- Secrets redacted before upload.
sk-*/Bearer …/AKIA…/AIza…/gh[pousr]_…/xox[baprs]-…shapes are masked in anyreasoning_summary/tools_usedpayload before leaving the daemon. - Agent capability gated by your IDE.
agent-config.jsondoes not containallowed_toolsor any LLM key (5/18 ADRremove-platform-paternalism). Whatever your~/.claude/settings.jsonpermits is what the agent can call.
Logs
Stdout (human-readable, mode=stream):
2026-05-18 09:15:00Z signal from @demo: {"direction":"long","token":"BTCUSDT",...}
⌥ runner: claude 44.0s exit=0
⌥ tools: ToolSearch, mcp__susurration__susu_signal_accept (2 calls)
⌥ permission_denials: 0JSONL (decision_log_path, append-only, one record per dispatch):
{"ts":"2026-05-18T09:15:44Z","triggering_event":{...},"invocation":{"runner":"claude","exit_code":0,"duration_ms":44030,"tools_used":[...],"cost_usd":0.31,"reasoning":"..."}}Local control HTTP (127.0.0.1:7777, optional)
Enables dashboard one-click upgrade and other in-place control. Bearer-auth
- Host-header check + CORS preflight only for
https://susurration.xyz. Disable with"local_server": falsein config.
Troubleshooting
- Agent dispatched but never accepts/rejects → check
~/.claude/settings.json:permissions.allowmust includemcp__susurration(or specific tools). Otherwise claude in headless mode denies the MCP call and the agent falls through to "do nothing". - Dashboard says daemon online but no new positions → SSE may have
zombied. 0.0.26+ watchdog should auto-recover within 90-105s; if not,
launchctl kickstart -k gui/$UID/com.susurration.agent-daemon. - Deprecation banner on startup → old
allowed_tools/max_budget_usdfields in config. Runnpx -y @susurration/installer@latest install --token <token>to regenerate cleanly.
Roadmap
- Per-channel agent runner override (different
cwdper channel for different personas) --baremode for low-trust environments (skip MCP / Skills auto-load)- Native Codex CLI support (separate ADR —
codex execis the entry, notcodex -p, and emits different stream-json schema)
