From e52e8d4b3852270286bba8b8d2d2dd9ed26a541b Mon Sep 17 00:00:00 2001
From: tsukino <87639218+0xtsukino@users.noreply.github.com>
Date: Fri, 12 Jun 2026 14:41:26 +0200
Subject: [PATCH 1/4] blog: mobile-launch post + two new interactive components
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Announces the TLSNotary mobile app for iOS / Android and walks
developers through the four-layer host-adapter stack the app sits
on (plugin-sdk → host-contracts → host-react-native → consumer app).
Two new MDX components:
- renders the four user-facing app screens
(browse plugins / approve plugin / approve reveal / verified
result) as styled HTML phone-frame mockups — no screenshot assets,
no light-vs-dark variants to chase, colors mirror the real app.
- is an interactive layered architecture
explorer in the same style as . Tap a
layer to see what lives in it. Takes a `platform` prop so the
same component can drive future posts about the extension or
CLI variants.
The post itself is ~1300 words: walkthrough, architecture, three
build-your-own paths (plugin / extension / mobile) routing through
the new tlsnotary Claude Code skill.
---
blog/2026-06-12-mobile-launch/index.md | 72 +++
src/components/MobileAppShowcase/index.tsx | 267 +++++++++
.../MobileAppShowcase/styles.module.css | 563 ++++++++++++++++++
src/components/MobileFlowDiagram/index.tsx | 242 ++++++++
.../MobileFlowDiagram/styles.module.css | 210 +++++++
5 files changed, 1354 insertions(+)
create mode 100644 blog/2026-06-12-mobile-launch/index.md
create mode 100644 src/components/MobileAppShowcase/index.tsx
create mode 100644 src/components/MobileAppShowcase/styles.module.css
create mode 100644 src/components/MobileFlowDiagram/index.tsx
create mode 100644 src/components/MobileFlowDiagram/styles.module.css
diff --git a/blog/2026-06-12-mobile-launch/index.md b/blog/2026-06-12-mobile-launch/index.md
new file mode 100644
index 0000000..8981666
--- /dev/null
+++ b/blog/2026-06-12-mobile-launch/index.md
@@ -0,0 +1,72 @@
+---
+title: "TLSNotary on Mobile: A New App and a Path for Building Your Own"
+authors: [tsukino]
+description: "We just shipped TLSNotary for iOS and Android — both as a demo of selective-disclosure proofs on a phone, and as a reference implementation for developers who want to build their own TLSN-powered mobile app on top of the new @tlsn/host-react-native adapter."
+---
+
+import MobileAppShowcase from '@site/src/components/MobileAppShowcase';
+import MobileFlowDiagram from '@site/src/components/MobileFlowDiagram';
+
+A few months ago, TLSNotary was a browser extension and a protocol. Today it's also a mobile app — iOS and Android, with the same plugin gallery you know from the extension, the same selective-disclosure guarantees, and a brand-new development story for anyone who wants to ship their own TLSN-powered app.
+
+The app itself is a **demo**: install it, browse the gallery, and produce a real proof against the public verifier. But it's also a **reference implementation**. Everything the app does on top of the TLSNotary protocol — the WebView that intercepts headers, the bottom sheet that asks for your approval, the native module that runs the Rust prover — is packaged so you can build the same stack into your own app without reading 2,000 lines of source.
+
+
+
+---
+
+## A walk through the app
+
+The mobile app's flow mirrors the extension's, but reorganized for a phone-sized screen. Four states matter:
+
+
+
+**Browse plugins.** Each plugin is a small piece of TypeScript that knows how to prove something specific — your Spotify top artist, your bank balance above a threshold, your Twitter handle. The gallery is curated, but a developer can swap in their own registry.
+
+**Approve the plugin.** Before any code runs, the app shows you exactly which hosts the plugin will hit, what data it will request, and asks you to choose how strictly you want to gate it: approve every reveal one-by-one, or approve everything for the session. Rejecting at this point means the plugin never executes.
+
+**Approve the reveal.** After the prover has built the protocol up to the moment of disclosure, the app stops and shows you the actual bytes that will leave your device — every range, with REVEAL or HASH badges so you can tell what's plaintext and what's a commitment. This is the same gate the extension's strict-mode flow uses, ported to a mobile-native bottom sheet.
+
+**See the verified result.** The proof completes against the verifier, and the app shows you the value you proved (your top artist, your follower count) along with which host signed it. The full proof transcript is collapsible — most users don't need it, but it's there if you want to inspect or share it.
+
+The whole flow runs locally except for the TLS prover's outbound connection (to the target server) and its multi-party computation handshake (with the verifier). Your session cookie never leaves the device.
+
+---
+
+## How the app is built
+
+The mobile app is one consumer of a four-layer stack we shipped alongside it. Tap a layer to see what lives in it:
+
+
+
+The protocol core (`@tlsn/plugin-sdk`) is the same code the browser extension runs. It owns the `HostCore` engine that evaluates a plugin's JavaScript inside a sandbox, drives the reactive `main()` loop, manages plugin state, and exposes the capabilities a plugin uses (`prove()`, `openWindow()`, `useHeaders()`, …). Nothing in there knows whether it's running in a service worker, a phone, or a Node CLI.
+
+Below it sits `@tlsn/host-contracts` — five interfaces every platform adapter implements. There's a `ProverClient` (how do I run a TLS prover on this platform?), a `WindowManager` (how do I open a tab/window/WebView and track it?), a `RequestInterceptor` (how do I capture the headers that fire inside it?), a `PluginRenderer` (how do I turn `DomJson` into UI?), and an `ApprovalUi` (how do I ask the user before doing something?). The contract is the bridge — it's why the same plugin runs on three radically different platforms unchanged.
+
+`@tlsn/host-react-native` is the mobile-specific glue that implements those five contracts. The window manager wraps `react-native-webview`. The request interceptor uses injected JavaScript inside the WebView to wrap `fetch` and `XMLHttpRequest`. The prover client is a thin shim over `tlsn-native`, an Expo native module that hosts a Rust port of the TLSNotary prover (Hermes can't run the WASM build, so we built the prover natively for iOS and Android). The renderer maps the plugin's `DomJson` tree onto React Native primitives — ``, ``, `` — with style adapters that translate browser CSS to React Native's `StyleSheet`. The approval UI is your app's responsibility: the adapter exposes hooks; you bring the bottom sheet.
+
+The top layer is **your app**. The mobile app at `app/mobile/` in the monorepo is one example — Expo Router screens, a plugin registry, the approval sheets you saw above, a theme. You can fork it or you can start from scratch, depending on how much UX you want to own.
+
+---
+
+## Build your own
+
+There are three paths a developer can take into TLSNotary, and we ship a Claude Code skill for each of them.
+
+**Build a plugin.** If you want to prove data from a specific API — your bank, a SaaS dashboard, anything you can hit with `fetch` — write a plugin. Plugins are platform-agnostic: the same `swissbank.plugin.ts` runs on the mobile app, the browser extension, and the CLI. The `create-plugin` skill walks you through it.
+
+**Build your own extension.** If you want a Chrome / Firefox / Safari extension with your own branding and plugin curation, scaffold a new project on top of `@tlsn/host-extension`. You own the manifest, the popup, the gallery — the adapter brings the WindowManager, the offscreen WASM prover, the request interception, and the content-script renderer. The upstream TLSNotary extension is the canonical reference.
+
+**Build your own mobile app.** If you want TLSN on iOS or Android, scaffold on top of `@tlsn/host-react-native`. You own the screens, the gallery, and the theming; the adapter brings the WebView, the native prover, and the renderer. The TLSN mobile app at `app/mobile/` is the canonical reference.
+
+For all three paths, the canonical entry point is the **`tlsnotary` Claude Code skill** that lives in the monorepo at `.claude/skills/tlsnotary/SKILL.md`. Clone it into your own project under `.claude/skills/` and ask Claude something like *"add TLSNotary to my Expo app"* — Claude reads the skill, picks the right path, and walks you through scaffolding the consumer files. The skill is the canonical, auto-discoverable entry point so you don't have to remember any slash commands.
+
+The packages and the skill are all in the monorepo at [tlsnotary/tlsn-extension](https://github.com/tlsnotary/tlsn-extension). The mobile app lives under `app/mobile/`, the adapters under `packages/host-*`, and the skills under `.claude/skills/`.
+
+---
+
+## What's next
+
+The mobile app is the first ship of the new host-adapter platform — there will be a CLI cut, an Electron adapter, and more reference plugins to follow. If you're building something with TLSNotary and the tooling has a sharp edge, please file an issue on GitHub or join us on Discord. We want to hear it.
+
+Install the app, run a proof, and let us know what you build.
diff --git a/src/components/MobileAppShowcase/index.tsx b/src/components/MobileAppShowcase/index.tsx
new file mode 100644
index 0000000..39cbd1e
--- /dev/null
+++ b/src/components/MobileAppShowcase/index.tsx
@@ -0,0 +1,267 @@
+import React from 'react';
+import styles from './styles.module.css';
+
+/**
+ * Four mockup screens of the TLSN mobile app, rendered as styled HTML —
+ * no screenshot assets, no light/dark variants to maintain, no app/store
+ * frames to chase. Colors and copy mirror the real React Native screens at:
+ *
+ * app/mobile/app/(tabs)/index.tsx →
+ * app/mobile/components/tlsn/PluginApprovalSheet.tsx →
+ * app/mobile/components/tlsn/RevealApprovalSheet.tsx →
+ * app/mobile/app/plugin/[id].tsx (success branch) →
+ */
+
+export default function MobileAppShowcase() {
+ return (
+
+ );
+}
+
+function platformLabel(platform: 'mobile' | 'extension' | 'cli'): string {
+ if (platform === 'extension') return 'extension';
+ if (platform === 'cli') return 'CLI';
+ return 'mobile';
+}
+
+function connectorLabel(idx: number): string {
+ // Between consumer (0) and adapter (1) → imports.
+ // Between adapter (1) and contracts (2) → implements.
+ // Between contracts (2) and sdk (3) → built on.
+ if (idx === 0) return 'imports';
+ if (idx === 1) return 'implements';
+ return 'built on';
+}
diff --git a/src/components/MobileFlowDiagram/styles.module.css b/src/components/MobileFlowDiagram/styles.module.css
new file mode 100644
index 0000000..62d33a9
--- /dev/null
+++ b/src/components/MobileFlowDiagram/styles.module.css
@@ -0,0 +1,210 @@
+.widget {
+ --mfd-card: var(--ifm-background-color);
+ --mfd-panel: var(--ifm-color-emphasis-100);
+ --mfd-text: var(--ifm-font-color-base);
+ --mfd-muted: var(--ifm-color-emphasis-700);
+ --mfd-line: var(--ifm-color-emphasis-200);
+ --mfd-line-strong: var(--ifm-color-emphasis-300);
+ --mfd-accent: #0969da;
+ --mfd-accent-soft: #ddf4ff;
+ --mfd-accent-border: #b6e3ff;
+ --mfd-tlsn: #243f5f;
+ --mfd-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
+
+ margin: 2rem auto;
+ padding: 24px 26px 20px;
+ max-width: 720px;
+ border-radius: 14px;
+ background: var(--mfd-panel);
+ border: 1px solid var(--mfd-line);
+ box-sizing: border-box;
+ color: var(--mfd-text);
+ font-size: 14px;
+ line-height: 1.5;
+}
+
+:global([data-theme='dark']) .widget {
+ --mfd-accent: #58a6ff;
+ --mfd-accent-soft: #0a2540;
+ --mfd-accent-border: #1f6feb;
+ --mfd-tlsn: #6088b8;
+}
+
+.header {
+ text-align: center;
+ margin-bottom: 18px;
+}
+
+.title {
+ font-size: 18px;
+ font-weight: 600;
+ margin: 0 0 4px;
+ letter-spacing: -0.01em;
+ color: var(--mfd-text);
+}
+
+.subtitle {
+ font-size: 13px;
+ margin: 0;
+ color: var(--mfd-muted);
+}
+
+/* ------------------------------------------------------------ */
+/* Layer stack */
+/* ------------------------------------------------------------ */
+.stack {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+}
+
+.layer {
+ position: relative;
+ display: block;
+ width: 100%;
+ text-align: left;
+ background: var(--mfd-card);
+ border: 1px solid var(--mfd-line-strong);
+ border-radius: 10px;
+ padding: 12px 16px;
+ font: inherit;
+ color: inherit;
+ cursor: pointer;
+ transition:
+ border-color 120ms ease,
+ box-shadow 120ms ease,
+ transform 120ms ease;
+}
+
+.layer:hover {
+ border-color: var(--mfd-accent-border);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
+}
+
+.layer:focus-visible {
+ outline: 2px solid var(--mfd-accent);
+ outline-offset: 2px;
+}
+
+.layer.active {
+ border-color: var(--mfd-accent);
+ box-shadow: 0 0 0 3px var(--mfd-accent-soft);
+}
+
+.layer.consumer {
+ border-style: dashed;
+ border-color: var(--mfd-tlsn);
+}
+
+.layer.consumer.active {
+ border-style: solid;
+ border-color: var(--mfd-tlsn);
+ box-shadow: 0 0 0 3px var(--mfd-accent-soft);
+}
+
+.layerHeader {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ gap: 12px;
+ margin-bottom: 4px;
+ flex-wrap: wrap;
+}
+
+.layerTitle {
+ font-family: var(--mfd-mono);
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--mfd-text);
+}
+
+.layerSubtitle {
+ font-size: 12px;
+ color: var(--mfd-muted);
+ font-style: italic;
+}
+
+.layerRows {
+ list-style: none;
+ padding: 0;
+ margin: 6px 0 0;
+}
+
+.layerRows li {
+ font-family: var(--mfd-mono);
+ font-size: 12px;
+ color: var(--mfd-muted);
+ line-height: 1.65;
+}
+
+/* ------------------------------------------------------------ */
+/* Connectors between layers */
+/* ------------------------------------------------------------ */
+.connector {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ padding: 6px 0;
+}
+
+.connectorLine {
+ width: 1px;
+ height: 14px;
+ background: var(--mfd-line-strong);
+}
+
+.connectorLabel {
+ font-size: 11px;
+ color: var(--mfd-muted);
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+
+/* ------------------------------------------------------------ */
+/* Detail panel */
+/* ------------------------------------------------------------ */
+.detailPanel {
+ margin-top: 16px;
+ padding: 14px 16px;
+ background: var(--mfd-card);
+ border: 1px solid var(--mfd-line);
+ border-radius: 10px;
+}
+
+.detailHeader {
+ font-family: var(--mfd-mono);
+ font-size: 13px;
+ font-weight: 600;
+ color: var(--mfd-accent);
+ margin-bottom: 6px;
+}
+
+.detailBody {
+ font-size: 13.5px;
+ line-height: 1.6;
+ color: var(--mfd-text);
+}
+
+.detailBody code {
+ font-family: var(--mfd-mono);
+ font-size: 12.5px;
+ background: var(--mfd-panel);
+ padding: 1px 5px;
+ border-radius: 4px;
+ border: 1px solid var(--mfd-line);
+}
+
+/* ------------------------------------------------------------ */
+/* Narrow viewport */
+/* ------------------------------------------------------------ */
+@media (max-width: 540px) {
+ .widget {
+ padding: 18px 14px 14px;
+ }
+
+ .layerHeader {
+ flex-direction: column;
+ gap: 2px;
+ }
+}
From 30a7f19268473e81b6e49f857a7cb201e03f4a88 Mon Sep 17 00:00:00 2001
From: tsukino <87639218+0xtsukino@users.noreply.github.com>
Date: Fri, 12 Jun 2026 14:41:26 +0200
Subject: [PATCH 2/4] blog: more accurate mobile mockups + real code samples
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Mobile app rendering:
- Bigger phone frames (280px vs 240px) so the content is readable
- Real iOS-style status bar (time + signal bars + battery — no fake
emoji icons)
- Real navbar on each screen with the app's #243f5f background and
white bold title (matches Expo Stack header)
- Plugin gallery cards now match the real app's spacing, font sizes,
and #243f5f plugin-name color
- Success screen now uses the real horizontal banner layout (logo
left, name + verified badge stacked right) with the key-result
card overlapping the banner by 14px the way the real app does
- All padding / typography / button styles aligned to the React Native
source (PluginApprovalSheet.tsx, RevealApprovalSheet.tsx, plugin/[id].tsx)
How-the-app-is-built section:
- Replaced 4 paragraphs of architecture prose with 5 real code
snippets pulled straight from app/mobile/components/tlsn/PluginScreen.tsx:
MobilePluginHost setup, , ,
, and the executePlugin() call that ties it together.
- Kept the for the structural overview, but the
meat of the section is now "here's what the integration looks like
in code", not a wall of text.
Also: skills moved from .claude/skills/ to ./skills/ in the
tlsn-extension repo; updated the link in this post accordingly.
---
blog/2026-06-12-mobile-launch/index.md | 81 ++-
src/components/MobileAppShowcase/index.tsx | 183 ++++---
.../MobileAppShowcase/styles.module.css | 517 ++++++++++--------
3 files changed, 461 insertions(+), 320 deletions(-)
diff --git a/blog/2026-06-12-mobile-launch/index.md b/blog/2026-06-12-mobile-launch/index.md
index 8981666..5afaa93 100644
--- a/blog/2026-06-12-mobile-launch/index.md
+++ b/blog/2026-06-12-mobile-launch/index.md
@@ -33,19 +33,78 @@ The whole flow runs locally except for the TLS prover's outbound connection (to
---
-## How the app is built
+## How the app uses the libraries
-The mobile app is one consumer of a four-layer stack we shipped alongside it. Tap a layer to see what lives in it:
+The mobile app is one consumer of a four-layer stack: your app on top, `@tlsn/host-react-native` underneath it, `@tlsn/host-contracts` describing what every adapter implements, and `@tlsn/plugin-sdk` at the bottom — the same protocol core the browser extension runs.
-The protocol core (`@tlsn/plugin-sdk`) is the same code the browser extension runs. It owns the `HostCore` engine that evaluates a plugin's JavaScript inside a sandbox, drives the reactive `main()` loop, manages plugin state, and exposes the capabilities a plugin uses (`prove()`, `openWindow()`, `useHeaders()`, …). Nothing in there knows whether it's running in a service worker, a phone, or a Node CLI.
-
-Below it sits `@tlsn/host-contracts` — five interfaces every platform adapter implements. There's a `ProverClient` (how do I run a TLS prover on this platform?), a `WindowManager` (how do I open a tab/window/WebView and track it?), a `RequestInterceptor` (how do I capture the headers that fire inside it?), a `PluginRenderer` (how do I turn `DomJson` into UI?), and an `ApprovalUi` (how do I ask the user before doing something?). The contract is the bridge — it's why the same plugin runs on three radically different platforms unchanged.
-
-`@tlsn/host-react-native` is the mobile-specific glue that implements those five contracts. The window manager wraps `react-native-webview`. The request interceptor uses injected JavaScript inside the WebView to wrap `fetch` and `XMLHttpRequest`. The prover client is a thin shim over `tlsn-native`, an Expo native module that hosts a Rust port of the TLSNotary prover (Hermes can't run the WASM build, so we built the prover natively for iOS and Android). The renderer maps the plugin's `DomJson` tree onto React Native primitives — ``, ``, `` — with style adapters that translate browser CSS to React Native's `StyleSheet`. The approval UI is your app's responsibility: the adapter exposes hooks; you bring the bottom sheet.
-
-The top layer is **your app**. The mobile app at `app/mobile/` in the monorepo is one example — Expo Router screens, a plugin registry, the approval sheets you saw above, a theme. You can fork it or you can start from scratch, depending on how much UX you want to own.
+What that looks like in code is short. Every screen the user sees is a thin wrapper over four primitives the adapter ships. Here's how `PluginScreen.tsx` — the file that orchestrates a whole prove session — wires them together.
+
+**1. Set up the host.** `MobilePluginHost` wraps the SDK's `HostCore` and asks you for a handful of callbacks: how to run the native prover, how to render UI, how to open a WebView. The user-approval bottom sheets are *your* component; the host calls into them when it needs a decision.
+
+```tsx
+const host = new MobilePluginHost({
+ onProveUntilReveal: async (request, options) => {
+ // Run the protocol up to compute_reveal, before the user has approved
+ // anything — the result includes the byte ranges that *would* be revealed.
+ return await proverRef.current.prepareReveal({ ...request, proverOptions: options });
+ },
+ onProveFinalize: async (sessionId, approved) => {
+ // After the user approves the reveal bottom sheet, finalize the proof.
+ return await proverRef.current.finalizeReveal(sessionId, approved);
+ },
+ onRevealApproval: ({ descriptors, approve, reject }) => {
+ setRevealApproval({ descriptors, approve, reject }); // shows
+ },
+ onRenderPluginUi: (windowId, domJson) => setDomJson(domJson),
+ onOpenWindow: async (url) => {
+ setWebViewUrl(url); // mounts
+ return { windowId, uuid: `mobile-${windowId}`, tabId: 0 };
+ },
+ onCloseWindow: () => { setWebViewUrl(null); setDomJson(null); },
+});
+```
+
+**2. Mount the native prover.** `` is a headless component that wraps the `tlsn-native` Expo module — a Rust port of the TLSNotary prover packaged as an iOS / Android native library (Hermes can't run the WASM build the extension uses, so we shipped one natively). The `ref` is what `MobilePluginHost` calls `prepareReveal()` and `finalizeReveal()` against.
+
+```tsx
+ setProverReady(true)}
+ onError={(err) => setError(err.message)}
+ onProgress={handleProveProgress}
+/>
+```
+
+**3. Intercept headers in a WebView.** When the plugin calls `openWindow()`, your app mounts ``, which loads the URL and runs injected JavaScript to wrap `fetch` and `XMLHttpRequest`. Every request fires `onHeaderIntercepted`, and your app routes that into the running plugin via `host.emitHeaderIntercepted()`.
+
+```tsx
+ {
+ host.emitHeaderIntercepted(eventEmitter, windowId, header);
+ }}
+/>
+```
+
+**4. Render the plugin's UI.** Plugins describe their UI as `DomJson` — a JSON tree of `div` / `button` / `text` nodes. `` walks that tree and renders it as React Native primitives (``, ``, ``), translating any CSS the plugin emits to RN's `StyleSheet`. Click handlers route back to the host so the plugin can react.
+
+```tsx
+ host.emitPluginAction(eventEmitter, windowId, handlerName)}
+/>
+```
+
+**5. Run the plugin.** Everything above is plumbing. The actual entry point is one line:
+
+```tsx
+await host.executePlugin(pluginCode, { eventEmitter });
+```
+
+That's the whole integration. The approval sheets, the plugin gallery, the theming, the settings — those are yours to design. The TLSN-specific machinery is the snippets above plus the components that render them. The reference implementation at [`app/mobile/`](https://github.com/tlsnotary/tlsn-extension/tree/main/app/mobile) is around 600 lines on top of the adapter; you can fork it or start from scratch depending on how much UX you want to own.
---
@@ -59,9 +118,9 @@ There are three paths a developer can take into TLSNotary, and we ship a Claude
**Build your own mobile app.** If you want TLSN on iOS or Android, scaffold on top of `@tlsn/host-react-native`. You own the screens, the gallery, and the theming; the adapter brings the WebView, the native prover, and the renderer. The TLSN mobile app at `app/mobile/` is the canonical reference.
-For all three paths, the canonical entry point is the **`tlsnotary` Claude Code skill** that lives in the monorepo at `.claude/skills/tlsnotary/SKILL.md`. Clone it into your own project under `.claude/skills/` and ask Claude something like *"add TLSNotary to my Expo app"* — Claude reads the skill, picks the right path, and walks you through scaffolding the consumer files. The skill is the canonical, auto-discoverable entry point so you don't have to remember any slash commands.
+For all three paths, the canonical entry point is the **`tlsnotary` Claude Code skill** that lives in the monorepo at [`skills/tlsnotary/SKILL.md`](https://github.com/tlsnotary/tlsn-extension/blob/main/skills/tlsnotary/SKILL.md). Copy the `skills/` directory into your own project, point Claude Code at it, and ask something like *"add TLSNotary to my Expo app"* — Claude reads the skill, picks the right path, and walks you through scaffolding the consumer files. The skill is the canonical, auto-discoverable entry point so you don't have to remember any slash commands.
-The packages and the skill are all in the monorepo at [tlsnotary/tlsn-extension](https://github.com/tlsnotary/tlsn-extension). The mobile app lives under `app/mobile/`, the adapters under `packages/host-*`, and the skills under `.claude/skills/`.
+The packages and the skill are all in the monorepo at [tlsnotary/tlsn-extension](https://github.com/tlsnotary/tlsn-extension). The mobile app lives under `app/mobile/`, the adapters under `packages/host-*`, and the skills under `skills/`.
---
diff --git a/src/components/MobileAppShowcase/index.tsx b/src/components/MobileAppShowcase/index.tsx
index 39cbd1e..879a689 100644
--- a/src/components/MobileAppShowcase/index.tsx
+++ b/src/components/MobileAppShowcase/index.tsx
@@ -3,13 +3,13 @@ import styles from './styles.module.css';
/**
* Four mockup screens of the TLSN mobile app, rendered as styled HTML —
- * no screenshot assets, no light/dark variants to maintain, no app/store
- * frames to chase. Colors and copy mirror the real React Native screens at:
+ * no screenshot assets, no light/dark variants to maintain. Colors and copy
+ * mirror the real React Native screens at:
*
- * app/mobile/app/(tabs)/index.tsx →
+ * app/mobile/app/(tabs)/index.tsx →
* app/mobile/components/tlsn/PluginApprovalSheet.tsx →
* app/mobile/components/tlsn/RevealApprovalSheet.tsx →
- * app/mobile/app/plugin/[id].tsx (success branch) →
+ * app/mobile/app/plugin/[id].tsx (success branch) →
*/
export default function MobileAppShowcase() {
@@ -42,11 +42,12 @@ function Phone({ caption, children }: PhoneProps) {