docs: invited-user quickstart + re-probe token mechanics on Gitea 1.27.2

The client is downloadable from central now, but no document took an invited
user from clone to working state. Quickstart covers link -> list -> get/add
-> watch, plus the two things people get wrong: an expired device code
creates nothing (just re-run link), and merging is deliberately a forge
action because watch refuses to merge or force.

Also re-probed the token-minting mechanics the README pinned to 1.27.1,
since both forges now run 1.27.2. All three results still hold:
  token-auth + Sudo header -> 401
  token-auth + ?sudo=      -> 401
  admin basic auth + Sudo  -> 201
Probe minted a token on the granthi-sync-e2e machine user and deleted it
(204 under basic auth). /v1/link's mint path is unaffected by the bump.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01LTARYHX7GPepi3CH3tp5pg
This commit is contained in:
Nirav Patel
2026-08-22 17:16:16 -04:00
co-authored by Claude Opus 5
parent 2cfef8fabb
commit 137d2cdd53
+45 -1
View File
@@ -26,6 +26,47 @@ git CLI only — same portability heritage as the estate's `gitea_sync.py` mesh.
└───────────────────────────────┘ └───────────────────────────────┘
``` ```
## Quickstart (invited user)
You need a shre-id account — an operator creates it; there is no open signup
(see "Invite-only story"). You also need to be on the tailnet: the
provisioning service is not publicly exposed yet.
```sh
git clone https://granthi.shre.ai/nirpa/granthi-sync.git
cd granthi-sync
# 1. Link this device. Prints a URL + code; approve it in a browser within
# 5 minutes. Creates your forge account and stores a scoped token in
# ~/.granthi-sync/config.json (0600). You never see a forge password.
./bin/granthi-sync link
# 2. See what is already yours on the forge.
./bin/granthi-sync list
# 3. Either pull an existing repo down...
./bin/granthi-sync get <repo> # or <owner>/<repo>, --into DIR
# 3b. ...or push a local folder up. It becomes a private repo.
./bin/granthi-sync add ~/work/notes
# 4. Keep everything synced. Autocommits, ff-pulls, pushes; skips anything
# that has diverged rather than merging or forcing.
./bin/granthi-sync watch # --once for a single pass
./bin/granthi-sync status # what is linked, last sync, divergence
```
Run `watch` as a background daemon on macOS with
`client/launchd/ai.granthi.sync.plist` (edit the script path, then
`launchctl bootstrap gui/$UID <plist>`).
**If the device code expires** (5 minutes, unapproved), nothing is created —
no account, no token, no partial state. Just run `link` again.
**Merging is a forge action, not a client one.** `watch` deliberately refuses
to merge; when a folder shows `DIVERGED` in `status`, resolve it in git or on
the forge web UI. The client will never force or auto-merge your work.
## Components ## Components
### `server/granthi_link.py` — provisioning service (granthi VPS) ### `server/granthi_link.py` — provisioning service (granthi VPS)
@@ -84,7 +125,10 @@ this change must be seeded into `state.json` once, as
machine user `granthi-sync-e2e` (seeded); the forge's human admin `nirpa` machine user `granthi-sync-e2e` (seeded); the forge's human admin `nirpa`
is never provisioned through `/v1/link`, so nothing else needed seeding. is never provisioned through `/v1/link`, so nothing else needed seeding.
Empirically verified mechanics on Gitea **1.27.1** (beta forge): Empirically verified mechanics on Gitea **1.27.1**, re-probed and still
holding on **1.27.2** (beta forge, 2026-08-22 — all three results below
matched; the probe minted a token on the `granthi-sync-e2e` machine user and
deleted it again, `DELETE …/tokens/{id}` returning 204 under basic auth):
* Token minting: `POST /api/v1/users/{login}/tokens` returns **401 for * Token minting: `POST /api/v1/users/{login}/tokens` returns **401 for
token-authenticated sudo** (both `Sudo:` header and `?sudo=`); it only works token-authenticated sudo** (both `Sudo:` header and `?sudo=`); it only works