# linji The CLI for 林集 (linji.at) — an atproto study-community client. One binary: multi-account login, spaces, threads, posting, watching, Markdown export. It is also the supported surface for **building bots** that read and post on app0.linji.at. ## Build & install Requires Zig 0.16 (`zvm`/`zigup` recommended) and a C toolchain. ```sh zig build # -> zig-out/bin/linji zig build test # unit tests zig build install --prefix ~/.local # -> ~/.local/bin/linji ``` Dev scenarios (need `../zds` built — `cd ../zds && zig build -Dtarget=x86_64-linux-gnu.2.36`; the explicit target uses zig's bundled CRT because today's system glibc `crt1.o` carries `.sframe` relocations zig's linker rejects): `zig build scenario-space`, `zig build scenario-serve`. ## Accounts Any atproto handle works. To **post in spaces hosted on app0.linji.at**, the bot's records are hosted on our zds (phase 001: member records live on the host's zds — see docs/architecture.dj "External members"), and an admin must add the account to the space's member list: ```sh linji space add-member --space at:///space/at.linji.space/ --did linji space rename --space at:///space/at.linji.space/ --name "" ``` Login is OAuth. Tokens refresh themselves afterwards; the session lives in `$LINJI_HOME/accounts.json` (default `~/.local/share/linji`). ```sh linji login --pds # prints an authorize URL, opens consent ``` **Headless servers:** log in once on a machine with a browser, then copy `accounts.json` to the server (`chmod 600` — it carries the DPoP key and refresh token). Refresh is automatic from then on. ## Commands (bot-relevant) ```sh linji thread list --space # thread AT-URIs + titles linji thread create --space --title # -> thread AT-URI linji post --space --thread # -> post AT-URI linji read --space [--tag ] # merged thread view linji watch --space [--interval ms] # follow new posts linji edit|delete --space --post … linji export --space --thread # thread as Markdown ``` `--as ` picks a non-default account. `--tag` filters to threads containing an inline hashtag. ## A minimal bot The loop: `watch` for new posts, reply with `post`. Here reacting to a `#question` tag: ```sh #!/bin/sh SPACE="at://did:plc:community/space/at.linji.space/general" THREAD="at://did:plc:bot/at.linji.thread/…" # reply thread linji watch --space "$SPACE" --interval 3000 | while IFS= read -r line; do case "$line" in *"#question"*) linji post --space "$SPACE" --thread "$THREAD" \ "收到 — 让我想想。" ;; esac done ``` For machine-readable reads, the BFF serves `GET /api/space?uri=` (JSON: threads + posts) once you hold a session cookie; the CLI's rendered output is the stable interface for shell bots. Run it under your service manager. app0/dinit/ has examples for the dev stack. ## Dev rig ```sh dinit -d app0/dinit dev # zds + seed + BFF + vite (see app0/dinit/dev) # seeded accounts: community/alice/bob (.test, password -password) ``` Layout, architecture, roadmap: see `../docs/`.