From 3f914c44252c364023b419b860c366e13a39e58f Mon Sep 17 00:00:00 2001 From: Michel de Graaf Date: Mon, 27 Jul 2026 14:04:14 +0200 Subject: [PATCH] docs: put daemon mode on the website and tighten the README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The website made three claims daemon mode falsifies — "No TTY, no daemon", "no daemon, no MCP server, no API key", and "no GUI and no daemon mode yet" under what-this-is-not. All three corrected. Adds a docs section and a home feature card, both leading with the reason rather than the mechanics: the server allows one session per account, so parallel one-shot commands either displace each other or mean a throwaway username per run, which is account churn on infrastructure other people maintain. A daemon is one login for as long as you work. The README section said that three times over and buried the reasoning below the mechanics; rewritten to state it once, up front. It now also covers which commands stay local and that shares add reaches a running daemon, which was meant to land earlier and silently did not — the edit anchored on text that only existed in SKILL.md. --- README.md | 49 +++++++++++++++--------------- website/src/pages/community.tsx | 3 +- website/src/pages/docs.tsx | 54 +++++++++++++++++++++++++++++++-- website/src/pages/home.tsx | 19 ++++++++++-- 4 files changed, 94 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index bae13b9..7f98272 100644 --- a/README.md +++ b/README.md @@ -118,10 +118,8 @@ Everything else is a one-shot command that runs headless. ### Daemon mode -A one-shot command logs in, does its job, and exits, which means nothing -outlives it and two commands at once fight over the server's one-session-per- -account rule. Run a daemon instead and it holds the session while everything -else borrows it: +A one-shot command logs in, does its job, and exits. Run a daemon instead and +it holds the session while everything else borrows it: ```bash soulseek-rs daemon # stays in the foreground; leave it running @@ -129,8 +127,21 @@ soulseek-rs search 'aphex twin' # no login, no flags — uses the daemon soulseek-rs # the TUI attaches to the same session ``` -From a script, start it and wait for it — it takes a second or two to log in, -and a command that arrives early opens a session of its own instead: +**Why you want this.** The server allows one session per account. Without a +daemon, two commands at once either cut each other off or push you into a +throwaway username per run — account churn on infrastructure other people +maintain and share. A daemon is one login for as long as you work, and one +share index instead of a rescan every invocation. It also lets a download +outlive the command that queued it, and keeps collecting chat while nothing is +attached. If you drive this from a script or an agent, start one. + +Commands find it by themselves. It listens on a Unix socket only your user can +open, so there is nothing to configure and no secret to pass around — the same +arrangement Docker and ssh-agent use. With no daemon running, everything +behaves exactly as it did before; `--no-daemon` forces that for one run. + +From a script, start it and *wait* for it: it takes a second or two to log in, +and a command that arrives early opens a session of its own instead. ```bash soulseek-rs daemon status --json >/dev/null 2>&1 || { @@ -142,28 +153,18 @@ soulseek-rs daemon status --json >/dev/null 2>&1 || { } ``` -Commands find it by themselves. The daemon listens on a Unix socket only your -user can open, so there is nothing to configure and no secret to pass around — -the same arrangement Docker and ssh-agent use. With no daemon running, -everything behaves exactly as it did before; `--no-daemon` forces that for one -run. - -What this buys: downloads that outlive the command that queued them, several -clients (or agents) on one account at once, and a chat window that keeps -collecting while nothing is attached. - -It is also the neighbourly way to use the network. The server allows one -session per account, so parallel one-shot runs either displace each other or -push you into registering a throwaway name per run — account churn on -infrastructure other people maintain. A daemon is one login for as long as you -work, and one share index instead of a rescan per invocation. If you are -driving this from a script or an agent, start a daemon. - ```bash soulseek-rs daemon status # who it is, what it shares, who is attached soulseek-rs daemon stop ``` +Everything that touches the network goes through it. `config`, `skills`, +`completions` and `portmap` stay local, because they are about this machine +rather than a session. `shares add`/`remove` do both: they write the config +file *and* update a running daemon, so a folder is served straight away rather +than at its next start. Files land on the *daemon's* filesystem — `daemon +status` reports where. + For a client on another machine, bind a TCP port as well and give it the token: @@ -173,7 +174,7 @@ soulseek-rs daemon token # the secret that connection needs ``` There is no transport encryption, so put SSH or a TLS proxy in front of -anything non-loopback. Note that files land on the *daemon's* filesystem. +anything non-loopback. Third-party clients are first-class: the daemon speaks newline-delimited JSON-RPC 2.0 described by an [OpenRPC](https://open-rpc.org) document diff --git a/website/src/pages/community.tsx b/website/src/pages/community.tsx index 689b1a1..caa1f6f 100644 --- a/website/src/pages/community.tsx +++ b/website/src/pages/community.tsx @@ -194,8 +194,7 @@ export const Community = () => { eyebrow="what this is not" title="Three good clients to point you elsewhere." > - soulseek-rs has no GUI and no daemon mode yet. If one of these fits you better, - use it. + soulseek-rs has no graphical interface. If one of these fits you better, use it.
{ALTERNATIVES.map((alt) => ( diff --git a/website/src/pages/docs.tsx b/website/src/pages/docs.tsx index 3d31b91..3c6c1c1 100644 --- a/website/src/pages/docs.tsx +++ b/website/src/pages/docs.tsx @@ -171,12 +171,13 @@ const FromTheShell = () => (

The command groups: search, get, download,{' '} browse, room, message, serve,{' '} - user, whoami, shares, config,{' '} - portmap, skills, completions. Records are + user, whoami, shares, daemon,{' '} + config, portmap, skills,{' '} + completions. Records are tab-separated fields, one per line, or NDJSON with --json.

- No TTY, no daemon. search --json pipes through jq into{' '} + No TTY required. search --json pipes through jq into{' '} download --stdin. Every ending has its own exit code: 4 found nothing, 3 could not reach the server, 6 the transfer died.

@@ -222,6 +223,52 @@ const FromTheShell = () => ( ) +const Daemon = () => ( +
+ + Soulseek allows one session per account. Run a daemon and everything else borrows + it — no second login, nothing to configure. + + + + +

+ Commands find it themselves: it listens on a Unix socket only your user can + open, so there is no address to pass and no token to handle. Without one + running, everything behaves exactly as it did before. +

+

+ Why bother: the server permits a single session per account, so two one-off + commands at once either cut each other off or push you into a throwaway + username per run — account churn on a network other people maintain. A + daemon is one login for as long as you work, one share index instead of a + rescan every invocation, and downloads that outlive the command that queued + them. If you drive this from a script or an agent, start one. +

+

+ It speaks newline-delimited JSON-RPC 2.0 described by an{' '} + openrpc.json the daemon serves itself, so a client generator gives + you one in any language. daemon --bind adds a TCP port for other + machines; those need the token from daemon token, while the local + socket never does. +

+
+
+
+) + const TheRest = () => (
@@ -257,6 +304,7 @@ export const Docs = () => ( + ) diff --git a/website/src/pages/home.tsx b/website/src/pages/home.tsx index f1daf52..9d1a21d 100644 --- a/website/src/pages/home.tsx +++ b/website/src/pages/home.tsx @@ -59,6 +59,19 @@ const FEATURES = [ ), }, + { + glyph: '◈', + color: 'var(--accent-text)', + title: 'Daemon mode', + cmd: 'soulseek-rs daemon', + body: ( + <> + Hold one session and let every other command borrow it — the network allows + one login per account, so this is the neighbourly way to run several at once. It + speaks JSON-RPC, so other tools can drive it too. + + ), + }, { glyph: '›', color: 'var(--status-info)', @@ -276,8 +289,10 @@ const Agents = () => ( queueing behind before a 2 GB transfer.

- It stays a CLI: no daemon, no MCP server, no API key. Upgrading the binary upgrades - the skill; rerun skills install to take it.{' '} + It stays a CLI: no MCP server, no API key. The skill tells your agent to start a + daemon first, so a batch of parallel requests is one login rather than one per + command. Upgrading the binary upgrades the skill; rerun skills install{' '} + to take it.{' '} See the commands