sudojidocs
Engineer+ Feature

Daemon & Portal Chat

Keep the agent always-on so your web portal can reach your servers in real time — no terminal open required.

What the daemon is

sudoji daemon opens a persistent WebSocket from your server to the Sudoji cloud hub (agent.sudoji.io). While it is running:

Your server appears as online in the portal Servers page.
Messages you send from the portal chat window are forwarded to the agent on the server and streamed back in real time.
📋Every message — from the terminal or the portal — is saved to a shared conversation thread with full history.
🔄If the connection drops, the daemon reconnects automatically with exponential back-off (max 30 s between retries).

  ┌──────────────────────┐         ┌───────────────────────────┐
  │   Your Browser       │         │   Your Linux Server       │
  │                      │         │                           │
  │  sudoji.io/sessions  │         │  $ sudoji daemon           │
  │  (portal chat UI)    │         │                           │
  └──────────┬───────────┘         └─────────────┬─────────────┘
             │  POST /portal/threads              │  WebSocket
             │  Bearer: Supabase JWT              │  /v1/daemon
             ▼                                   ▼
  ┌────────────────────────────────────────────────────────────┐
  │                 agent.sudoji.io                            │
  │                                                            │
  │  • Verifies JWT / API key                                  │
  │  • Checks plan + credits                                   │
  │  • Routes portal message → daemon WS                       │
  │  • Writes thread_messages to Supabase                      │
  │  • Supabase Realtime notifies portal UI                    │
  └────────────────────────────────────────────────────────────┘

Requirements

PlanEngineer or EnterpriseCreditsBalance > $0 (checked per agent turn, not on connect)API keyAny key on your account — same one used for sudoji askNetworkOutbound HTTPS/WSS to agent.sudoji.io:443
The daemon itself does not consume credits on connect. Credits are only deducted after an AI turn completes. If your balance reaches zero, the daemon stays connected but new messages from the portal will be blocked until you top up at sudoji.io/billing.

Starting the daemon

Foreground (testing)

Run directly to see the banner and connection logs. Press Ctrl-C to stop.

terminal
sudoji daemon

  ░░░░░ ░░░░░ ░░░░░░ ░░░░░ ░░░░░ ░░
  ░  ░░ ░ ░ ░ ░   ░ ░   ░   ░   ░░
  ░░░░░ ░░░░░ ░░░░░░ ░░░░░   ░   ░░
  ░     ░   ░ ░    ░ ░   ░   ░   ░░
  ░     ░   ░ ░░░░░░ ░   ░ ░░░░░ ░░░░░░

  connected  cstock-dev
  plan       engineer
  credits    $8.43
  hub        wss://agent.sudoji.io/v1/daemon

  ✓ daemon online

Running under PM2 (recommended — no second SSH session needed)

For production servers, run the daemon under PM2 so it survives reboots, auto-restarts on crash, and requires no open terminal session.

terminal
# Install pm2 if not already installed
sudo npm install -g pm2

# Start the daemon as a named process
pm2 start "sudoji daemon" --name sudoji-daemon

# Save the process list so pm2 restores it after reboot
pm2 save

# Register pm2 as a system service — run the command it prints
pm2 startup

# Monitor
pm2 status
pm2 logs sudoji-daemon --lines 30
After pm2 startup, copy and run the command it outputs (e.g. sudo env PATH=... pm2 startup systemd -u ubuntu --hp /home/ubuntu). That registers pm2 itself with systemd so it starts on boot and restores all saved processes — including the daemon.

Running under systemd

/etc/systemd/system/sudoji-daemon.service
[Unit]
Description=Sudoji Daemon
After=network.target

[Service]
ExecStart=/usr/bin/sudoji daemon
Restart=always
RestartSec=5
User=ubuntu
Environment=SUDOJI_NO_KEYCHAIN=1

[Install]
WantedBy=multi-user.target
terminal
sudo systemctl daemon-reload
sudo systemctl enable --now sudoji-daemon
sudo systemctl status sudoji-daemon
Set SUDOJI_NO_KEYCHAIN=1 in the service environment when there is no interactive user session — systemd and pm2 service contexts have no D-Bus or GNOME Keyring session to attach to.

Sending messages from the portal

Once the daemon is running, go to sudoji.io/dashboard/sessions and select a conversation thread. If the daemon is online for that server you will see ● daemon online in the thread header and the send bar becomes active.

Type a message and press Enter or click Send. The flow is:

1Portal writes your message to the thread in Supabase (you see it immediately).
2The hub forwards the message to the daemon over the WebSocket.
3The daemon runs the agent pipeline on the server (reads files, executes tools if in fix mode).
4The assistant response is streamed back and saved to the thread. Supabase Realtime pushes it to your browser — no polling.
If the daemon goes offline while a conversation is open, the portal displays "Server agent is offline. Start the daemon with sudoji daemon on the server to process messages." You can keep sending — messages queue in the thread and the daemon will process them once it reconnects.

What the agent can do from the portal

The agent mode is set when a thread is created (from sudoji chat --mode <mode>) and controls what the agent is allowed to do when it handles your messages:

diagnoseDEFAULT · READ ONLY

The agent reads files and logs, identifies root causes, and explains what it finds. No commands are run. Use this to plan a change, discuss an approach, or ask questions before touching anything.

suggestREAD + PROPOSE

Diagnoses the problem and proposes the exact commands to fix it — but does not execute them. The list is shown in the response for you to copy and run manually.

fixCAN EXECUTE

Full agent loop. The daemon reads files and runs commands on the server. Each run_command call requires approval — from the terminal via [y/N] or pre-approved in your policy settings.

Use the portal as a planning interface: start a thread in diagnose mode, ask the agent to analyse your server or walk through a proposed change step by step. Once you are happy with the plan, switch to fix mode in a sudoji chat terminal session to execute it.

Terminal chat: sudoji chat

sudoji chat is the terminal-side companion to the portal. It opens an interactive REPL where you type messages and receive streamed responses — but unlike sudoji ask the conversation history is preserved across turns, so the agent can refer back to what it read and found earlier.

Every session is automatically assigned a generated name (like Brave Falcon) and saved as a thread. The thread is immediately visible in the portal Sessions → Chat tab, and you can rename it from the portal by clicking the title. If the daemon is running, the same thread is also reachable from the portal for sending follow-up messages from the web.

terminal — start a chat session
# Plan first in diagnose mode (read-only, safe)
sudoji chat

  sudoji › I want to add swap to this server — walk me through it
  › This server has 2 GB RAM and no swap. Recommended: 2 GB swap file.
    Steps: fallocate → chmod → mkswap → swapon → /etc/fstab entry.

  sudoji › exit

# Then execute in fix mode
sudoji chat --mode fix

  sudoji › why is the API returning 503?
  [agent reads nginx logs, pm2 status…]
  › The upstream Node process (pm2 id 0) has crashed 4 times in the last hour.
    Exit code 137 each time — it's being OOM-killed.

  sudoji › how much memory is it using vs the limit?
  [agent runs free -m, checks pm2 ecosystem…]
  › Node is hitting 1.8 GB. The server has 2 GB total and no swap.
    ecosystem.config.js sets max_memory_restart to 1500M.

  sudoji › add 1 GB of swap and restart the app
  allow? run  fallocate -l 1G /swapfile  [y/N]  y
  ✓
  allow? run  chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile  [y/N]  y
  ✓
  allow? run  pm2 restart api  [y/N]  y
  ✓ Done.

  sudoji › exit

Conversation threads

A thread is a stored multi-turn conversation. It records every message (user and assistant), tool calls made, and the cumulative token cost. Threads are associated with a specific server and visible in the portal.

FieldDescription
titleAuto-generated as an "Adjective Animal" name (e.g. "Brave Falcon"). Click the title in the portal to rename it.
statusactive (in use), idle (quiet > 30 min), closed (ended by user or expired).
modeThe agent mode active when the thread was created (diagnose / suggest / fix).
sourceWhere the thread originated: terminal, daemon, or portal.
total costCumulative spend in USD across all turns in this thread.
Thread history is unlimited for Engineer and Enterprise plans. Free plan threads are closed after 7 days of inactivity.

Troubleshooting

Daemon won't connect

Run sudoji doctor to confirm your API key and network are working. Check that port 443 outbound to agent.sudoji.io is open. If behind a proxy, the proxy must support WebSocket upgrades (HTTP CONNECT tunnelling).

daemon.rejected: PLAN_INSUFFICIENT

Your account is on the Free plan. Upgrade to Engineer at sudoji.io/pricing to use the daemon.

daemon.rejected: SERVER_LIMIT

Engineer plan allows one connected daemon at a time. If you have the daemon running on multiple servers simultaneously, only the first one within the limit will be accepted. Enterprise plan removes this restriction.

Portal shows daemon offline after reconnect

The daemon updates the server's daemon_status column on connect and on disconnect. If a crash left the record stale, it will be corrected as soon as the daemon reconnects. Refresh the portal after reconnect to see the updated status.

← CLI referenceUse cases & examples →
Daemon & Portal Chat — Sudoji — Sudoji Docs