diff --git a/README.md b/README.md index f031122..3349a1f 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ from the user's data at runtime, scoped by their existing grants. | an app that **discovers + routes** (menus, "open with", agents) | [`docs/consumers.md`](./docs/consumers.md) | | an **AI agent** asked to author records for a repo | [`docs/agent-guide.md`](./docs/agent-guide.md) | | writing a capability record | [`docs/capability-spec.md`](./docs/capability-spec.md) | +| watching the loop run **live in a browser** (OAuth + real PDS writes) | [`demo/`](./demo/) | ## Try it in 30 seconds @@ -52,12 +53,42 @@ cd tools node write-capability.mjs examples/subscribe.capability.json --dry-run --identifier myapp.com ``` +## See it run for real — the share-sheet demo + +The CLI above runs the loop offline against fixtures. The [`demo/`](./demo/) is the +same loop in a **browser, against a live network**: a "Share with…" share sheet that +discovers the handlers already in *your* repo footprint and runs an action for real. + +```bash +cd demo +npm install +npm run dev # builds the bundle, then serves → http://127.0.0.1:8787/demo/ +``` + +It walks the full pitch end to end: + +1. **Discover** (read-only, no login) — scan your repo for `dev.at-intent.usage`, + resolve each app's `dev.at-intent.capability` records into one action graph. +2. **Match** — keep the actions whose `subject` accepts the current page (a bare + `uri`); the rest are shown greyed, with the subject they'd need. +3. **Consent** — compute the *minimal* granular OAuth scopes those handlers declare + (`repo:…` / `rpc:…`, never blanket write) and request exactly that set. +4. **Act** — run an action live: `repo` writes a record into your PDS, `service` + proxies an XRPC call through it, `open` navigates. Discovery is the upstream + `resolveActionGraph` from [`resolver/`](./resolver/), unchanged. + +Because the scopes are granular, discovery *has* to run first to know what to ask +for — which is exactly why "ask for what the repo says is needed, and nothing more" +is the whole point. See [`demo/README.md`](./demo/README.md) for the auth model +(loopback vs hosted), the code map, and the `@atproto/api` service-call wrinkles. + ## What's in this repo ``` lexicons/ dev.at-intent.capability + dev.at-intent.usage (the two records) tools/ write capability/usage records — from a JSON file or interactively resolver/ the consumer-side discovery loop (lib + CLI + offline fixtures) +demo/ share-sheet browser consumer — discovery + OAuth + live PDS actions docs/ overview, producer/consumer guides, agent guide, spec reference ``` @@ -66,8 +97,10 @@ docs/ overview, producer/consumer guides, agent guide, spec reference Exploration / draft. The namespace `dev.at-intent.*` is a working placeholder (likely long-term home: `community.lexicon.*`); it's defined in one constant ([`tools/lib/nsid.mjs`](./tools/lib/nsid.mjs)) plus the lexicon `id` fields, so -re-homing is mechanical. No app publishes these records on the live network yet — -the resolver fixtures stand in for that so the full loop runs today. +re-homing is mechanical. No app publishes these records on the live network at scale +yet — the resolver fixtures stand in for that on the CLI — but the [`demo/`](./demo/) +already runs the whole loop against a real repo footprint over live OAuth, so the +end-to-end path (discover → consent → act) works today, not just in fixtures. ## Prior art & context