# Build a Textxt Mini App with an AI coding assistant

This document is the canonical compact context for AI-assisted Mini App development. It is intentionally stricter than a general tutorial. Follow the linked machine-readable artifacts whenever prose and generated code disagree.

## 1. Platform model

A Textxt Mini App is an HTTPS web application loaded inside a sandboxed chat panel. It communicates with the Textxt host through Bridge 1.0. A Mini App does not receive Firebase credentials, does not access Textxt Firestore directly, and does not treat runtime session metadata as authentication.

Canonical artifacts:

- Bridge contract: https://textxt.com/mini-apps/developers/bridge-v1.json
- Manifest schema: https://textxt.com/mini-apps/schema/manifest-v1.json
- SDK 1.0.3: https://textxt.com/mini-apps/sdk/1.0.3/textxt-mini-app.js
- TypeScript declarations: https://textxt.com/mini-apps/sdk/textxt-mini-app.d.ts
- Starter: https://textxt.com/mini-apps/starter/
- Security checklist: https://textxt.com/mini-apps/developers/security/
- Platform policy: https://textxt.com/mini-apps/developers/policies/
- Changelog: https://textxt.com/mini-apps/developers/changelog/

## 2. Download and run the starter

```bash
mkdir my-textxt-mini-app
cd my-textxt-mini-app

BASE=https://textxt.com/mini-apps/starter
curl -fsSLO "$BASE/index.html"
curl -fsSLO "$BASE/manifest.json"
curl -fsSLO "$BASE/host.html"
curl -fsSLO "$BASE/textxt-mini-app.js"
curl -fsSLO "$BASE/validate-manifest.mjs"

npx serve .
```

Open the printed local URL with `/host.html`. The simulator supplies context and exercises Bridge behavior without requiring a production Textxt release.

## 3. Use the SDK, not the transport

```html
<script src="https://textxt.com/mini-apps/sdk/1.0.3/textxt-mini-app.js"></script>
<script>
  const bridge = window.TextxtMiniApp.createBridge();

  async function start() {
    const context = await bridge.getContext();
    const commands = new Set(context.bridge.availableCommands);

    if (commands.has("sendMessage")) {
      await bridge.sendMessage({ text: "Result from my Mini App" });
    }
  }

  start().catch((error) => {
    document.querySelector("[role=status]").textContent =
      error.message || "Unable to connect to Textxt.";
  });
</script>
```

Do not construct Bridge envelopes or call `window.parent.postMessage` yourself. The SDK pins the parent origin, creates request IDs, handles timeouts, maps host errors, and dispatches events.

## 4. Feature detection and permissions

The manifest declares the maximum permissions requested by the release. The user grants permissions per app and chat. The available command list is the runtime authority.

Always:

1. Call `getContext()` after the app opens.
2. Read `context.bridge.availableCommands`.
3. Disable or hide an action when its command is unavailable.
4. Handle permission changes and `sessionExpired` without losing local user input.
5. Request only permissions required by visible functionality.

Never assume that every Textxt version, platform, chat, or user grants the same commands.

When the host exposes `pickChatContent`, the app may ask the user to select specific text messages or images from the active Textxt conversation. This is an explicit picker action; do not scrape chat content or assume access to the entire conversation.

## 5. Manifest 1

Use the JSON Schema as the source of truth. Do not add owner IDs, review status, timestamps, secrets, or undeclared fields.

```json
{
  "manifestVersion": 1,
  "appId": "conversation-notes",
  "name": "Conversation Notes",
  "description": "Capture a note and send it back to the conversation.",
  "iconUrl": "https://example.com/apps/conversation-notes/1.0.0/icon.png",
  "startUrl": "https://example.com/apps/conversation-notes/1.0.0/index.html",
  "allowedOrigins": ["https://example.com"],
  "permissions": ["readContext", "sendMessage", "setDraft"],
  "capabilities": ["message.text"],
  "bridgeVersion": "1.0",
  "minimumHostVersion": "1.1.0",
  "requiredHostCapabilities": ["bridge.command-discovery"],
  "visibility": "private",
  "tags": ["notes", "productivity"],
  "version": "1.0.0",
  "privacyPolicyUrl": "https://example.com/privacy",
  "supportUrl": "https://example.com/support",
  "releaseNotes": "Initial release."
}
```

Validate during development and again against the deployed release:

```bash
node validate-manifest.mjs --local manifest.json
node validate-manifest.mjs --remote manifest.json
```

## 6. Production hosting

Use one HTTPS origin for the entry HTML and every executable JavaScript, CSS, module, and worker dependency. Put the exact semantic version in the release URL and do not overwrite an approved version.

The server must send Content-Security-Policy as an HTTP response header. A minimal static-app baseline is:

```text
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors https://textxt.com https://textxt-14209.web.app
```

Adjust only the directives required by the app and declare every external origin during review. A `<meta http-equiv>` tag does not replace the required CSP response header.

## 7. UI and reliability requirements

- Support widths from 320px through desktop without horizontal overflow.
- Respect host theme, locale, safe-area, keyboard, layout, visibility, and fullscreen events when relevant.
- Keep user-visible writes behind explicit user actions.
- Prevent duplicate writes while an action is pending and make retries idempotent where possible.
- Preserve unsent local input when permission, network, or session state changes.
- Show actionable errors without exposing tokens, internal identifiers, or stack traces.
- Report operational errors through `bridge.reportError` only after removing sensitive data.

## 8. Authentication and backend services

`session.id` and the legacy `sessionToken` are correlation values, not credentials. If the Mini App owns a backend, use its own authentication flow. If Textxt has registered a server-side service for the app, call it through `invokeTextxtService` after feature detection and permission grant.

Never:

- ask the user to paste a Textxt password, Firebase token, API key, or session value;
- read or write Textxt Firestore directly;
- infer identity from a correlation session;
- load executable code from an origin absent from the release;
- auto-send messages, spend TXT, or upload files on launch.

## 9. Release workflow

1. Host the immutable HTTPS release.
2. Run local and remote manifest validation.
3. Verify mobile layout and permission-denied states.
4. Sign in to Textxt and open Settings -> Mini app developer.
5. Submit the manifest URL through the Developer Console.
6. Address automated verification or review notes.
7. Publish updates at a new semantic-version URL and monitor staged rollout health.

## 10. Instructions for an AI coding assistant

- Read the Bridge JSON contract, Manifest JSON Schema, and TypeScript declarations before generating code.
- Do not invent Bridge commands, payloads, manifest fields, authentication behavior, or backend access.
- Prefer the starter structure unless the user explicitly requests a framework.
- Return complete source files, not isolated snippets.
- Include permissions used, local test steps, remote validation, CSP configuration, and known limitations.
- If a requested capability is absent from `availableCommands`, explain the limitation and implement a safe fallback instead of bypassing the host.
