# When everyone is librarian, library is everywhere

Throughout, `alice` is a librarian (an operator-hosted federation member) and
`bob` another (a peer member); `fed` is a federation, and `op` is the operator's
*host* (it appears in serve URLs like `http://op:8800`).

---

## Verbose setup, lean run

The CLI is **lean**: you declare a thing once, then refer to it by name.

Most commands read the same way: a **resource**, the **action** on it, then a
**name** for this run of that action:

- `accorder lib build alice`
- `accorder fedlib share live fed`

The resource (`lib` or `fedlib`) and verb (`build` or `share`) say *what to do*;
the trailing name is yours to choose, so you remember what this run was for.

That name is the **action alias** — a memorable context for the action. The
first time, you spell the action out in flags and `accorder` saves them under
the name. (A few per-run switches are better left one-off, so they are not
saved — see below.)

Once you have configured the action with flags, you run it bare — the saved
config is what executes.

For the `lib` resource — a Calibre library — the action alias names one of your
libraries. With only one, you need no name; it takes the implicit `default`.
With several, the name tells them apart: `research`, `comicbooks`, `fiction`…

If you run:

```
accorder lib build alice --librarian "Alice Wonderland" --calibrepath ~/Calibre/alice
```

both the librarian name and the path to Alice's Calibre library are saved.

Next time it is enough to run just:

```
accorder lib build alice
```

and both values are read from the configuration, as if the flags were provided.

Change your mind at any point by passing just the one flag you want different:
it overwrites that single value, the rest stays put, and you can forget again.

Add private mode on top of the already-saved librarian (`Alice Wonderland`) and
Calibre path (`~/Calibre/alice`):

```
accorder lib share live alice --mode private
```

It runs in private mode and saves the mode for future runs.

Next time all three flags are implicitly present:

```
accorder lib share live alice
```

Changing one flag runs with its new value plus the saved ones, and saves the
new value for future bare runs:

```
accorder lib share live alice --calibrepath ~/CalibreLibraries/alice
```

The invariant to hold in your head: **a bare run replays the latest values you
set** — omitting a flag means "what I last set," not a fresh default. This
covers the alias-persisted flags; deliberate per-run switches — `--offline`,
`--only-http`, `--only-tor`, `--insecure` — are never saved and must be given
each time.

`accorder config show alice` prints the saved flag tree for one alias — the
stored values a bare run replays (run-time defaults, environment values, and
descriptor/credential resolution aren't part of that picture). `accorder config
list` names the aliases you've built up so far (`alice`, `bob`, `fed`) and the
action families saved under each.

Some flags span a resource's actions: give `--calibrepath` once (at your first
`lib` command, step 1) and the alias's other shared-group `lib` actions —
`browse`, `build`, `import`, `join`, `publish`, `status`, `sync`, `upload`,
`share live` — inherit it (`lib download` is the exception: its `--calibrepath`
is a plain destination directory, set on that action).

`--librarian` and `--libraryID` are adopted before they are generated: if any
action under the alias already carries one, that value is taken and spread to
the rest; only when none does is a new one minted. An empty field on the action
you happen to run is not the same as the library having no identity.

Federations do the same through the **descriptor** (`fedlib config set`) — but
note the positional there is a **federation id**, not an action alias: `fedlib
config set`, `fedlib members invite`, and `fedlib members offer` key the
descriptor by that id (a separate store from the aliases above). `fedlib build`
and `fedlib share live` take a normal action alias; when it names a descriptor
(as `fed` does here), they recall its bucket, S3, paths, and keys-file.

---

## 0 — Reader (a web browser, no accorder)

Browse, search, and download from the web — no catalog to maintain or
re-share. The reader surfs the web:

```
https://library.memoryoftheworld.org
```

That page is the public face of a federation aggregate. Once the operator has
set it up (step 2), serving it is a single line — the descriptor and alias
remember the bucket, S3, paths, and listen address:

```
accorder fedlib share live motw
```

And it is more than a web page: in this most-public mode a browser gets plain
browsing, but pointing `accorder` at the same endpoint turns the reader into a
librarian — caching the index, selecting offline, rendering into your own
Calibre, re-sharing. That is the rest of this guide.

---

## 1 — Reader → Librarian (`accorder lib browse`)

A friend is a librarian, keen to share their library with you. Or, as with
`Memory of the World`, a group of friends — amateur librarians — run an
aggregate of many libraries and share it with the world.

You browse a shared library and render your selection into your own Calibre
library. The catalog-to-be needs two things: a Calibre path and a librarian
name. A library name is optional — it labels your rendered catalog and travels
to anyone who later browses yours. After running:

```
accorder lib browse alice --endpoint https://library.memoryoftheworld.org
```

the shared library's index is downloaded, cached, and bookmarked as alice's
last source. A bare `lib browse alice` reopens it.

Each browsed source is also registered by name (`lib index list` shows them),
and any of them can be browsed with `--from <name>` without disturbing the
bookmark.

The `lib browse` command opens a web browser on the shared library.

Until the Calibre path and librarian name are set, the header's **SETTINGS**
step collects them first, and the other steps stay locked.

From there the header walks you through three steps:
- in **SELECT** you browse, search, and pick books;
- in **QUEUE** you review the picks and download them;
- the third step carries the name of your own library (or `MY LIBRARY` until you name it) — click it and the downloaded books are **rendered** into your Calibre-ready catalog.

Both the Calibre path and the librarian name can be handed over on the command
line (`-c` and `-l`), so a fully-flagged browse skips **SETTINGS** entirely —
only an optional library name is left to set there. Both are saved and shared
with every later `lib` action:

```
accorder lib browse alice --endpoint https://library.memoryoftheworld.org --calibrepath ~/Calibre/alice --librarian alice
```

If the aggregate is shared in private mode, alice needs an invite from the
operator and passes an `--invite` blob in place of the URL:

```
accorder lib browse alice --invite 'accorder-invite:…'
```

---

### Browse offline

Reopen alice's last-browsed source with no network: the cached index gives you
full browsing and search offline. A selection lives only in the running
session — to fetch files, come back online and download from **QUEUE**; then,
as always, the header's last step — the one named after your catalog — renders
the downloaded books into it.

```
accorder lib browse alice --offline
```

---

### Build your catalog (`accorder lib build`)

Building a catalog needs only two flags: `--librarian` and `--calibrepath`.
Coming from `lib browse` above, both are already on the alias — each from its
flag (`-c`, `-l`) or **SETTINGS**, the librarian auto-generated (as is the UUID)
when left unset — so alice builds with:

```
accorder lib build alice
```

The browse route is not required: starting from an already existing Calibre
library, the same build just needs those two flags spelled out:

```
accorder lib build alice --librarian alice --calibrepath ~/Calibre/alice
```

Or the books are in Zotero. `lib import` syncs a BetterBibTeX export into the
Calibre library — adding what is new, updating what changed, leaving the rest
alone — and `--calibrepath` is already shared, so only the export directory is
new:

```
accorder lib import alice --zotero-path /tmp/betterbibtex-from-zotero/
```

Re-run it whenever the export changes. A book Zotero no longer carries is
reported, not removed, until you ask:

```
accorder lib import alice --prune
```

`--prune` and `--yes` are per-run like the switches above — never saved — so a
bare `lib import alice` cannot delete anything you did not ask for.

After the library changes, alice rebuilds with just:

```
accorder lib build alice
```

---

### Share it (`accorder lib share live`)

Serve the library so others can `lib browse` it. In a `-tags tor` build it
comes up on both a Tor onion and HTTP (`--only-http` narrows to clearnet); the
default build serves HTTP only. `--mode` gates access.

```
accorder lib share live alice --only-http --listen 0.0.0.0:8900 --mode private
```

A bare restart replays the saved listen and mode:

```
accorder lib share live alice
```

`--only-http` is per-run and never saved, so on a Tor-enabled build repeat it
(the default build is HTTP-only anyway).

While it serves, alice's terminal prints a ready-made command for her friend.
She does not run it — she copies it and sends it to `bob`:

```
accorder lib browse local-librarian --from remote-alice --endpoint http://192.168.1.24:8900/
```

The two names say which side each belongs to: **local-** is the friend's own
context, **remote-** is alice's library. Alice cannot know who will receive the
line, so the local half stays the generic `local-librarian` — a word inviting
replacement.

`bob` puts his own alias in place of the suggested one and runs it:

```
accorder lib browse local-bob --from remote-alice --endpoint http://192.168.1.24:8900/
```

Read it as three answers:

- `local-bob` is his *local* setup — his librarian name, Calibre path, and the
  action alias (`local-bob`), saved in the configuration for next time;
- `remote-alice` is his name for the *remote* library, whose index he searches,
  selects from, queues, and downloads to render into his `local-bob` catalog;
- `--endpoint` is *where* that library lives.

Next time bob needs only his alias:

```
accorder lib browse local-bob
```

Or he can reach alice's library while working under a different alias — a
separate local Calibre library, but the same source library and index:

```
accorder lib browse local-bob-2 --from remote-alice
```

Both names were only suggestions. Bob can use any alias — omitting it means
`default` — rename the source with `lib index rename`, or drop `--from` once it
is saved. On a loopback bind, no such line is printed — nothing off-machine
could reach it.

Granting a friend access prints an invite blob; they browse your share into
their own library — step 1, from the other side.

Alice prepares the invitation for her friend `bob`:

```
accorder lib share grant alice --friend bob --endpoint http://alice-host:8900
```

`bob` gets his invitation from `alice` and can then build his own library:

```
accorder lib browse bob --invite 'accorder-invite:…' --calibrepath ~/Calibre/bob
```

---

## 2 — Operate a federation (`accorder fedlib`)

Stand up an aggregate and serve it; this comes before joining because the
invite/offer minted here is what a librarian joins with. The descriptor
(`fedlib config set`) is remembered, so the rest stays short.

```
accorder fedlib config set fed --bucket motw/fed --s3-provider Wasabi --s3-endpoint s3.wasabisys.com --keys-file keys/op.s3.keys --mode public --fedlib-path ~/agg --upload-prefix aggregate
```

`fedlib members invite` mints an operator-hosted member's blob. Auto-minting
the member's scoped S3 creds needs the operator's IAM **root** keys — not the
descriptor's `keys/op.s3.keys`, which is the aggregate's own S3 creds. Drop
them in `operator_root.keys` (or `wasabi_root.keys`) in the config dir, or pass
`--operator-root-keys-file`; with root keys in place you pass neither creds nor
bucket.

```
accorder fedlib members invite fed alice --prefix alice
```

`fedlib members offer` mints a peer's claim URL:

```
accorder fedlib members offer fed --prefix bob --librarian bob --endpoint http://op:8800
```

`fedlib build` bootstraps the aggregate once; the positional pulls bucket, S3,
output path, and keys-file from the descriptor, so it's credless too.

```
accorder fedlib build fed
```

Then `fedlib share live` serves it and rebuilds automatically as members
change:

```
accorder fedlib share live fed --only-http --poll-interval 5 --listen 0.0.0.0:8800
```

A restart replays the saved configuration; as with `lib share live`,
`--only-http` is per-run, so repeat it on a Tor-enabled build:

```
accorder fedlib share live fed --only-http
```

---

### Join a federation (`accorder lib join`)

Each librarian joins with what the operator minted above — `alice` with the
operator-hosted membership blob (`accorder-fedlib-invite:…`), `bob` with his
peer-offer claim URL. The alias is the first word; the blob or URL goes to
`--invite`.

Alice joins under the alias she has been building with all along. That alias
carries a library UUID she minted locally in step 1, and the invite carries the
federation's — so the join adopts the federation's identity in its place. It
can, because nothing was ever published under the local one: the alias holds a
catalog, not a membership. Her calibrepath and librarian name are already on
the alias, so the join needs neither, and it builds and publishes into the
bucket in one go (it confirms first when run from a terminal). Later,
`lib publish alice` republishes after changes.

```
accorder lib join alice --invite 'accorder-fedlib-invite:…'
```

An alias that *is* already a membership — one carrying a federation prefix, a
dict ID, a publish bucket or stored write credentials — refuses a conflicting
invite instead, and says which of those it found. Re-inviting an existing
member, where the invite carries the UUID the alias already holds, is not a
conflict and simply refreshes the credentials. Refusals that can be decided
from the alias and the offer's prefix happen *before* the claim, so a refused
join leaves a single-use offer unspent.

`bob` — browsing into his own Calibre since step 1 — hosts his library himself.
First he builds it:

```
accorder lib build bob
```

Then he shares it, and the share keeps serving in its terminal:

```
accorder lib share live bob --only-http --listen 0.0.0.0:8900 --mode private
```

From a second terminal he claims the peer offer. The operator pulls from his
live share; his `--libraryID` comes from his alias:

```
accorder lib join bob --invite 'http://op:8800/invite/…' --endpoint http://bob-host:8900 --insecure
```

Re-run `lib build bob` after changes — the operator's poll picks it up.

---

## Federation of federations

A fedlib aggregate is itself a library — today you can `lib browse` it from the
top, render any member's books into your Calibre, and re-share (step 1, one
level up); what you rendered can join a federation via `lib join` (step 2).
Aggregates joining other aggregates is the direction, not yet a command —
`lib join` operates on a librarian's Calibre library, not on a fedlib. Books
already move catalog → catalog the whole way:

```
accorder lib browse alice --endpoint https://<a-fedlib>
```

---
