docs: put daemon mode on the website and tighten the README
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.
This commit is contained in:
@@ -118,10 +118,8 @@ Everything else is a one-shot command that runs headless.
|
|||||||
|
|
||||||
### Daemon mode
|
### Daemon mode
|
||||||
|
|
||||||
A one-shot command logs in, does its job, and exits, which means nothing
|
A one-shot command logs in, does its job, and exits. Run a daemon instead and
|
||||||
outlives it and two commands at once fight over the server's one-session-per-
|
it holds the session while everything else borrows it:
|
||||||
account rule. Run a daemon instead and it holds the session while everything
|
|
||||||
else borrows it:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
soulseek-rs daemon # stays in the foreground; leave it running
|
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
|
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,
|
**Why you want this.** The server allows one session per account. Without a
|
||||||
and a command that arrives early opens a session of its own instead:
|
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
|
```bash
|
||||||
soulseek-rs daemon status --json >/dev/null 2>&1 || {
|
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
|
```bash
|
||||||
soulseek-rs daemon status # who it is, what it shares, who is attached
|
soulseek-rs daemon status # who it is, what it shares, who is attached
|
||||||
soulseek-rs daemon stop
|
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
|
For a client on another machine, bind a TCP port as well and give it the
|
||||||
token:
|
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
|
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
|
Third-party clients are first-class: the daemon speaks newline-delimited
|
||||||
JSON-RPC 2.0 described by an [OpenRPC](https://open-rpc.org) document
|
JSON-RPC 2.0 described by an [OpenRPC](https://open-rpc.org) document
|
||||||
|
|||||||
@@ -194,8 +194,7 @@ export const Community = () => {
|
|||||||
eyebrow="what this is not"
|
eyebrow="what this is not"
|
||||||
title="Three good clients to point you elsewhere."
|
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,
|
soulseek-rs has no graphical interface. If one of these fits you better, use it.
|
||||||
use it.
|
|
||||||
</SectionHead>
|
</SectionHead>
|
||||||
<div className="grid grid-cols-1 gap-3.5">
|
<div className="grid grid-cols-1 gap-3.5">
|
||||||
{ALTERNATIVES.map((alt) => (
|
{ALTERNATIVES.map((alt) => (
|
||||||
|
|||||||
@@ -171,12 +171,13 @@ const FromTheShell = () => (
|
|||||||
<p>
|
<p>
|
||||||
The command groups: <Code>search</Code>, <Code>get</Code>, <Code>download</Code>,{' '}
|
The command groups: <Code>search</Code>, <Code>get</Code>, <Code>download</Code>,{' '}
|
||||||
<Code>browse</Code>, <Code>room</Code>, <Code>message</Code>, <Code>serve</Code>,{' '}
|
<Code>browse</Code>, <Code>room</Code>, <Code>message</Code>, <Code>serve</Code>,{' '}
|
||||||
<Code>user</Code>, <Code>whoami</Code>, <Code>shares</Code>, <Code>config</Code>,{' '}
|
<Code>user</Code>, <Code>whoami</Code>, <Code>shares</Code>, <Code>daemon</Code>,{' '}
|
||||||
<Code>portmap</Code>, <Code>skills</Code>, <Code>completions</Code>. Records are
|
<Code>config</Code>, <Code>portmap</Code>, <Code>skills</Code>,{' '}
|
||||||
|
<Code>completions</Code>. Records are
|
||||||
tab-separated fields, one per line, or NDJSON with <Code>--json</Code>.
|
tab-separated fields, one per line, or NDJSON with <Code>--json</Code>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
No TTY, no daemon. <Code>search --json</Code> pipes through <Code>jq</Code> into{' '}
|
No TTY required. <Code>search --json</Code> pipes through <Code>jq</Code> into{' '}
|
||||||
<Code>download --stdin</Code>. Every ending has its own exit code: 4 found
|
<Code>download --stdin</Code>. Every ending has its own exit code: 4 found
|
||||||
nothing, 3 could not reach the server, 6 the transfer died.
|
nothing, 3 could not reach the server, 6 the transfer died.
|
||||||
</p>
|
</p>
|
||||||
@@ -222,6 +223,52 @@ const FromTheShell = () => (
|
|||||||
</Section>
|
</Section>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const Daemon = () => (
|
||||||
|
<Section>
|
||||||
|
<SectionHead eyebrow="5 · the daemon" title="One login, however many commands.">
|
||||||
|
Soulseek allows one session per account. Run a daemon and everything else borrows
|
||||||
|
it — no second login, nothing to configure.
|
||||||
|
</SectionHead>
|
||||||
|
<Cols start>
|
||||||
|
<Terminal
|
||||||
|
label="shell"
|
||||||
|
lines={[
|
||||||
|
{ t: 'cmd', text: 'soulseek-rs daemon &' },
|
||||||
|
{ t: 'cm', text: '# once; it holds the session' },
|
||||||
|
{ t: 'cmd', text: 'soulseek-rs search "netlabel 2004" --json' },
|
||||||
|
{ t: 'cm', text: '# no login, no flags — it finds the daemon' },
|
||||||
|
{ t: 'cmd', text: 'soulseek-rs' },
|
||||||
|
{ t: 'cm', text: '# the TUI attaches to the same session' },
|
||||||
|
{ t: 'cmd', text: 'soulseek-rs daemon status' },
|
||||||
|
{ t: 'cmd', text: 'soulseek-rs daemon stop' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Prose>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
It speaks newline-delimited JSON-RPC 2.0 described by an{' '}
|
||||||
|
<Code>openrpc.json</Code> the daemon serves itself, so a client generator gives
|
||||||
|
you one in any language. <Code>daemon --bind</Code> adds a TCP port for other
|
||||||
|
machines; those need the token from <Code>daemon token</Code>, while the local
|
||||||
|
socket never does.
|
||||||
|
</p>
|
||||||
|
</Prose>
|
||||||
|
</Cols>
|
||||||
|
</Section>
|
||||||
|
)
|
||||||
|
|
||||||
const TheRest = () => (
|
const TheRest = () => (
|
||||||
<Section band>
|
<Section band>
|
||||||
<Panel title="the rest" className="bg-raised [&>span]:bg-panel">
|
<Panel title="the rest" className="bg-raised [&>span]:bg-panel">
|
||||||
@@ -257,6 +304,7 @@ export const Docs = () => (
|
|||||||
<Layout />
|
<Layout />
|
||||||
<Keys />
|
<Keys />
|
||||||
<FromTheShell />
|
<FromTheShell />
|
||||||
|
<Daemon />
|
||||||
<TheRest />
|
<TheRest />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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: '›',
|
glyph: '›',
|
||||||
color: 'var(--status-info)',
|
color: 'var(--status-info)',
|
||||||
@@ -276,8 +289,10 @@ const Agents = () => (
|
|||||||
queueing behind before a 2 GB transfer.
|
queueing behind before a 2 GB transfer.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
It stays a CLI: no daemon, no MCP server, no API key. Upgrading the binary upgrades
|
It stays a CLI: no MCP server, no API key. The skill tells your agent to start a
|
||||||
the skill; rerun <Code>skills install</Code> to take it.{' '}
|
daemon first, so a batch of parallel requests is one login rather than one per
|
||||||
|
command. Upgrading the binary upgrades the skill; rerun <Code>skills install</Code>{' '}
|
||||||
|
to take it.{' '}
|
||||||
<Link to="/docs" className="text-link hover:text-link-hover">
|
<Link to="/docs" className="text-link hover:text-link-hover">
|
||||||
See the commands
|
See the commands
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
Reference in New Issue
Block a user