# AppAttest — Full text bundle Source: https://www.appattest.build Generated at build time. Every section below is also available individually as a `.md` URL. --- # Quickstart Source: https://www.appattest.build/docs/quickstart.md # Quickstart This page gets AppAttest running in an existing iOS app. End-to-end, it takes about five minutes on a real device. The rest of the docs go deeper on each step. ## Before you start - An iOS app you can run on a real device. App Attest does not run in the simulator. For SwiftUI previews, simulator runs, and tests, set `AppAttest.debugMode = .local(stubs: [...])` in a `#if DEBUG` block — release builds always run real attestation. - Apple Developer Program membership. App Attest is an Apple capability and requires signed builds. - An appAttest account. Sign up at . ## 1. Create the app in AppAttest In the dashboard at : 1. Click **New app**. 2. Enter your bundle identifier. Must match your Xcode project exactly. Example: `com.yourcompany.yourapp`. 3. Pick a team. The default team is fine for a solo setup. The dashboard now has one app with two environments: `development` and `production`. ## 2. Add secrets In your new app: 1. Select the `development` environment. 2. Click **Add secret**. 3. Give it a name, for example `openai`. 4. Paste the value. Secret values are write-only. Once saved, the dashboard never shows a value back to you — the platform can't decrypt stored values, so there is no reveal or copy-out path. If you lose a value, overwrite the secret with a new one. Editing a secret means entering a new value to replace the old. Repeat for `production` with the production-grade key when you're ready. ## 3. Turn on App Attest in Apple Developer Console Full walkthrough: see [Apple Developer Console setup](/docs/apple-developer-console). Short version: 1. → **Certificates, Identifiers & Profiles** → **Identifiers**. 2. Open your app identifier. 3. Scroll to **App Services**. Enable **App Attest**. 4. Save. You don't need to regenerate provisioning profiles for this change. ## 4. Xcode configuration Full walkthrough: see [Xcode setup](/docs/xcode-setup). Short version: 1. Open the project. 2. Select your app target. 3. **Signing & Capabilities** → **+ Capability** → **App Attest**. 4. Xcode adds `App Attest` to your entitlements file. That's it. Reference: [entitlements](/docs/entitlements). ## 5. Add the Swift SDK In Xcode: 1. **File** → **Add Package Dependencies**. 2. URL: `https://github.com/AppAttest/appAttest-sdk`. 3. Pick **Up to Next Major Version** from the latest tagged release. 4. Add the `AppAttest` product to your app target. Or in `Package.swift`: ```swift dependencies: [ .package(url: "https://github.com/AppAttest/appAttest-sdk", from: "0.1.0") ], targets: [ .target( name: "MyApp", dependencies: [ .product(name: "AppAttest", package: "appattest-sdk") ] ) ] ``` Platform floor: iOS 17 / macOS 14 / tvOS 17 / watchOS 10 (locked by the `@Observable` macro). Using React Native, Capacitor, or Flutter? See [Other platforms](/docs/other-platforms) for the equivalent install and read APIs — the rest of this guide (account, secrets, Apple Developer Console, entitlements) applies unchanged. ## 6. Initialize and use The SDK has no configuration. Bundle ID and Team ID come from the signed app at runtime — there's no key to paste in. One synchronous call in your App init does the whole bootstrap: ```swift import SwiftUI import AppAttest @main struct MyApp: App { init() { AppAttest.start() } var body: some Scene { WindowGroup { ContentView() } } } ``` `AppAttest.start()` is idempotent and returns in microseconds. Internally it hydrates any previously-synced secrets from Keychain (so cold-start reads feel synchronous), spawns the background attest + sync, and registers a foreground observer so the next foreground re-syncs. Read a secret anywhere in your app via the synchronous subscript: ```swift struct ContentView: View { var body: some View { if let key = AppAttest.secrets["OPENAI_API_KEY"] { Text("Ready") } else { ProgressView("Loading…") } } } ``` `AppAttest.secrets` is an in-memory dict observed by SwiftUI through `AppAttestClient.shared` (which is `@Observable @MainActor`). When a value lands, any view reading it re-renders. The subscript returns `String?` — nil while the first sync is still running, the value once it lands. For testability or explicit injection, prefer `@Environment(AppAttestClient.self)`: ```swift @main struct MyApp: App { init() { AppAttest.start() } var body: some Scene { WindowGroup { ContentView() .environment(AppAttestClient.shared) } } } struct ContentView: View { @Environment(AppAttestClient.self) private var attest var body: some View { Text(attest.secrets["OPENAI_API_KEY"] ?? "Loading…") } } ``` If you need a bootstrap step that absolutely cannot run before secrets are present, use the one-time async helper: ```swift .task { try? await AppAttest.waitForReady() APIClient.configure(token: AppAttest.secrets["BACKEND_KEY"]!) } ``` `waitForReady()` throws on `.subscriptionRequired`, `.creditsRequired`, or `.unavailable` — let your error UI react accordingly. ## 7. Observe state for unhappy paths Errors that aren't recoverable per-call live on `AppAttest.state` rather than thrown from the read path. Switch on it where you want to gate UI: ```swift struct RootView: View { @Environment(AppAttestClient.self) private var attest var body: some View { switch attest.state { case .initializing, .attesting, .syncing: SplashView() case .ready: MainView() case .subscriptionRequired(let err): UnavailableView(title: "Service paused", error: err) case .creditsRequired(let err): UnavailableView(title: "Service paused", error: err) case .unavailable(let err): switch err { case .attestationRejected: AttestationFailedView(error: err) default: RetryView(error: err) { attest.retry() } } } } } ``` `retry()` re-runs the sync without re-attesting — useful for a Retry button on the failure state. `.attestationRejected` is terminal for this install; the other `.unavailable` cases (`.serviceUnavailable`, `.network`) retry automatically on next foreground. **For end-user-facing apps:** show a generic "service temporarily unavailable" view when state isn't `.ready`. Don't surface our specific reasons or the embedded `subscribeUrl` / `topupUrl` to end users — they're for your developer-mode diagnostics or admin flows. ## 8. Verify Run on a real device. In the AppAttest dashboard, open **Recent activity**. After your device attests and syncs, you'll see a request row recorded for your app, marked as delivered, with its environment (sandbox or production). Rejections show up here too — not subscribed, no credits, rate limited, or attestation invalid — so a failed run is visible, not silent. If you don't see activity within 30 seconds, see [errors and debugging](/docs/entitlements#troubleshooting). ## What's next - [Apple Developer Console setup](/docs/apple-developer-console) — the Identifier and App Attest toggle in depth. - [Xcode setup](/docs/xcode-setup) — capability, entitlements, signing. - [Entitlements reference](/docs/entitlements) — what goes in the file and why. - [For AI agents](/docs/agents) — how an agent should read these docs on a developer's behalf. --- # Other platforms Source: https://www.appattest.build/docs/other-platforms.md # Other platforms AppAttest ships official bridges for **React Native**, **Capacitor**, and **Flutter**, plus a CocoaPods option for native Swift. They wrap the same SDK and expose the same shape — `start`, `waitForReady`, read a secret, observe state — idiomatic to each runtime. The account, secret, Apple Developer Console, and entitlements steps are identical across every platform. Do steps 1–4 of the [Quickstart](/docs/quickstart) first; this page only covers the per-platform **install** and **read** delta. App Attest is an Apple capability, so these bridges gate and deliver secrets on the **iOS** side of your cross-platform app. There is no Android or web attestation path — on those targets the SDK is unavailable and your code should fall back accordingly. Secrets are write-only on every platform: you set or overwrite a value in the dashboard, but the dashboard can never show a stored value back. ## React Native ```sh npm install @appattest/react-native cd ios && pod install ``` ```ts import { AppAttest, useSecret } from '@appattest/react-native'; // Once, at app launch: AppAttest.start(); // In a component — re-renders when secrets land: function ApiView() { const openaiKey = useSecret('OPENAI_API_KEY'); return openaiKey ? : ; } // Outside components: await AppAttest.waitForReady(); const key = await AppAttest.getSecret('OPENAI_API_KEY'); // string | null const all = await AppAttest.getAllSecrets(); // Record ``` Observe lifecycle state with the `useAppAttestState()` hook. ## Capacitor ```sh npm install @appattest/capacitor npx cap sync ``` ```ts import { AppAttest } from '@appattest/capacitor'; // Once, at app launch: AppAttest.start(); // Anywhere: await AppAttest.waitForReady(); const key = await AppAttest.getSecret('OPENAI_API_KEY'); // string | null const all = await AppAttest.getAllSecrets(); ``` Observe state with `await AppAttest.getState()` and `AppAttest.addStateListener(...)`. ## Flutter ```yaml # pubspec.yaml dependencies: appattest_flutter: ^0.1.0 ``` ```sh flutter pub get cd ios && pod install ``` ```dart import 'package:appattest_flutter/appattest_flutter.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); AppAttest.start(); runApp(const MyApp()); } // Anywhere: await AppAttest.waitForReady(); final key = await AppAttest.secret('OPENAI_API_KEY'); // String? final all = await AppAttest.allSecrets(); // Map ``` Observe state with `AppAttest.stateStream`. ## Swift via CocoaPods If you use CocoaPods instead of Swift Package Manager: ```ruby pod 'AppAttest' ``` Then use the SDK exactly as in the [Quickstart](/docs/quickstart#6-initialize-and-use). The Objective-C facade is available as `pod 'AppAttestObjC'` for bridge writers and Objective-C consumers; native Swift apps should depend on `AppAttest`. The bridges pull the iOS pods in automatically — you don't add them yourself. ## Testing without a device App Attest needs real hardware. For simulator builds, previews, and tests, enable local stubs (one debug mode, stripped from release builds): - **React Native / Capacitor:** `AppAttest.setDebugMode('local', { stubs: { OPENAI_API_KEY: 'sk-test-stub' } })` - **Flutter:** `AppAttest.setDebugMode(DebugMode.local, { 'OPENAI_API_KEY': 'sk-test-stub' })` ## Errors Every bridge surfaces the same stable error codes: `subscription_required`, `credits_required`, `attestation_rejected`, `service_unavailable`, `network`, `debug_mode_release_blocked`, `invalid_argument`. Gate your UI on the observed state rather than catching on the read path. ## What's next - [Quickstart](/docs/quickstart) — the shared end-to-end flow (account, secrets, Apple Developer Console, entitlements). - [Apple Developer Console setup](/docs/apple-developer-console) — enabling App Attest on your identifier. - [Entitlements reference](/docs/entitlements) — what goes in the file and why. --- # Apple Developer Console setup Source: https://www.appattest.build/docs/apple-developer-console.md # Apple Developer Console setup App Attest is an Apple capability. Before Xcode can sign a build that uses it, the capability has to be enabled on your app's identifier in the Apple Developer portal. You do this once per app identifier. It takes about a minute. ## Prerequisites - Apple Developer Program membership (paid). - Admin or App Manager role on the team that owns the app identifier. - Your app's bundle identifier, for example `com.yourcompany.yourapp`. ## Steps 1. Go to . 2. Sign in. Pick the correct team from the top-right team switcher if you belong to more than one. 3. Click **Certificates, Identifiers & Profiles**. 4. In the left sidebar, click **Identifiers**. 5. In the identifier list, find your app's bundle identifier. If it's not there yet, click the **+** button and register it now. Pick **App IDs** → **App**, then enter Description and Bundle ID. 6. Click the identifier to open it. 7. Scroll down to **Capabilities**. (Some Apple UIs call this section **App Services**.) The capabilities are a long checkbox list, alphabetical. 8. Find **App Attest** in the list. Check it. 9. Click **Save** at the top right. 10. Apple may show a confirmation dialog saying provisioning profiles using this identifier will need to be regenerated. For App Attest specifically, Xcode handles this on the next build. Click **Confirm**. You're done with the console. ## Verifying Back in the identifier detail page, **App Attest** should now show a green dot next to it. If it doesn't, hard-refresh the page. ## Common questions ### Do I need to regenerate provisioning profiles? In most cases, no. Xcode's automatic signing picks up the change the next time you build. If you use manual provisioning, download a fresh profile from the **Profiles** tab after saving the capability. ### Does enabling App Attest cost anything on Apple's side? No. App Attest is a no-cost Apple capability included with the Developer Program. The usage limits that matter are described in Apple's DeviceCheck documentation — they are high enough that a typical app will not hit them. ### Can I test App Attest on a simulator? No. App Attest requires Apple to sign an attestation using hardware-backed keys, which only real devices can produce. For simulator builds, SwiftUI previews, and tests, set `AppAttest.debugMode = .local(stubs: [...])` inside a `#if DEBUG` block — it bypasses network and attestation and returns the stubs you pass in. It's the only debug mode, and it's physically absent from Release builds (release always runs real attestation). See [Xcode setup](/docs/xcode-setup#troubleshooting). ### What if my team has multiple identifiers for the same app? Enable App Attest on every identifier that might run the app binary: the main app ID, any app-extension IDs that call AppAttest, and any wildcard IDs you sign with. Extensions do not typically need it unless they call AppAttest directly. ## What's next - [Xcode setup](/docs/xcode-setup) — add the capability to your project and entitlements. - [Entitlements reference](/docs/entitlements) — what the Xcode step writes to disk. --- # Xcode setup Source: https://www.appattest.build/docs/xcode-setup.md # Xcode setup This page covers the Xcode side of setup: adding the App Attest capability, adding the Swift package, and pointing the client at your project. The Apple Developer Console steps come first — see [Apple Developer Console setup](/docs/apple-developer-console). ## 1. Add the App Attest capability 1. Open your project in Xcode. 2. Select the project in the Navigator (top item, blue icon). 3. Select your app target from the **TARGETS** list. 4. Click the **Signing & Capabilities** tab. 5. Click **+ Capability** at the top of the capability list. 6. In the search field, type **App Attest**. 7. Double-click **App Attest** to add it. Xcode does two things: - Writes an entry to your app target's entitlements file. If you don't have one yet, Xcode creates `YourAppName.entitlements` next to your source. - Updates the target's build settings to point at that entitlements file. See [entitlements](/docs/entitlements) for the exact contents. ## 2. Check signing In the same **Signing & Capabilities** tab: - **Automatically manage signing** should be checked unless you have a reason to manage profiles manually. - The **Team** dropdown should show the team that owns the identifier you enabled App Attest on. - **Bundle Identifier** should match that identifier exactly. Build once. Xcode will regenerate the provisioning profile if needed. If you see a signing error, Xcode usually shows a **Try Again** button that fixes it. ## 3. Add the AppAttest Swift package 1. **File** → **Add Package Dependencies**. 2. In the search field at the top right, paste: `https://github.com/AppAttest/appAttest-sdk`. 3. Wait for Xcode to resolve it. 4. **Dependency Rule**: **Up to Next Major Version**, from the latest tagged release. 5. Click **Add Package**. 6. In the product selection dialog, add the **AppAttest** product to your **app target**. Do not add it to test targets. Xcode adds the package to your project's Package Dependencies list and links it into the app. ## 4. Wire the SDK into @main No configuration is required. The SDK detects your bundle identifier and Apple Team ID from the running process — there is no dashboard key or token to paste in. One call in your App init runs the whole bootstrap: ```swift import SwiftUI import AppAttest @main struct MyApp: App { init() { AppAttest.start() } var body: some Scene { WindowGroup { ContentView() } } } ``` Your app is identified by `(Team ID, bundle ID)` at the moment the SDK runs its first attestation. Production secrets only reach production-signed builds; sandbox secrets only reach development builds. The environment is inferred from the App Attest entitlement you added in step 1. `AppAttest.start()` is synchronous and idempotent; the actual attest + sync run on a background `Task`. Cold-start reads after the first launch hydrate from Keychain before the first frame. ## 5. Read a secret Access secrets anywhere via the synchronous subscript on the static `AppAttest` namespace: ```swift struct ContentView: View { var body: some View { if let key = AppAttest.secrets["OPENAI_API_KEY"] { Text("Ready") } else { ProgressView("Loading…") } } } ``` `AppAttest.secrets` is observed by SwiftUI through `AppAttestClient.shared` (which is `@Observable @MainActor`). When a value lands or rotates, any view reading it re-renders. The subscript returns `String?` — `nil` while the first sync is still running, the value once it lands. For unhappy paths, switch on `AppAttest.state`: ```swift struct RootView: View { @Environment(AppAttestClient.self) private var attest var body: some View { switch attest.state { case .initializing, .attesting, .syncing: SplashView() case .ready: MainView() case .subscriptionRequired(let err): UnavailableView(title: "Service paused", error: err) case .creditsRequired(let err): UnavailableView(title: "Service paused", error: err) case .unavailable(let err): RetryView(error: err) { attest.retry() } } } } ``` ## Troubleshooting ### "Missing com.apple.developer.devicecheck.appattest-environment" The entitlement was not added to the build. Re-check **Signing & Capabilities**. The App Attest capability should be present. If it is, delete `DerivedData` and build again: 1. **Xcode** → **Settings** → **Locations** → **Derived Data**. Click the arrow to open it in Finder. 2. Quit Xcode. 3. Delete the `DerivedData` folder. 4. Reopen and build. ### "App Attest not supported on this device" You are on a simulator, or the device is older than iPhone 6s / iOS 14. For simulator development, SwiftUI previews, and tests, use local stubs: ```swift #if DEBUG AppAttest.debugMode = .local(stubs: [ "OPENAI_API_KEY": "sk-test-stub", "BACKEND_KEY": "dev-token-abc" ]) #endif AppAttest.start() ``` Debug mode is `#if DEBUG`-gated and physically absent from Release builds — release builds always run real attestation. ### "Attestation failed" at runtime The bundle identifier, team, or App Attest capability on the Apple side is misaligned with what AppAttest expects. Check: 1. Dashboard bundle ID matches Xcode bundle ID exactly. 2. Apple Developer Console shows App Attest enabled on that identifier. 3. You are running a signed build, not an ad-hoc export. More on attestation failures: [entitlements troubleshooting](/docs/entitlements#troubleshooting). ## What's next - [Entitlements reference](/docs/entitlements) — the exact file contents Xcode writes. - [For AI agents](/docs/agents) — how to help a user complete this setup. --- # Entitlements reference Source: https://www.appattest.build/docs/entitlements.md # Entitlements reference When you add the App Attest capability in Xcode, the only file that changes is your target's entitlements file. This page documents the one key that matters. ## The key `com.apple.developer.devicecheck.appattest-environment` ## Values - `development` — for builds signed with a development provisioning profile (running from Xcode on your device). - `production` — for builds signed with a distribution profile (TestFlight, App Store, Enterprise distribution). The value Xcode writes depends on how the build is signed. You do not usually set this by hand. ## What the file looks like Minimal example — `YourApp.entitlements`: ```xml com.apple.developer.devicecheck.appattest-environment development ``` In a typical project the file will also contain other entitlements (App Groups, Keychain Sharing, Push Notifications, and so on). Those are unrelated to App Attest and can coexist safely. ## How the environment maps to AppAttest AppAttest uses the attestation environment reported by Apple to decide which environment's secrets to deliver. | Entitlement value | Apple attestation server | AppAttest environment | |---|---|---| | `development` | Apple sandbox | `development` secrets | | `production` | Apple production | `production` secrets | This means the same device, running the same app binary signed two different ways, will get two different sets of secrets. That is the intended behavior: your development key goes to development builds, your production key goes to App Store builds. ## Automatic signing vs. manual signing With automatic signing (the default), Xcode sets the value correctly based on the build configuration and the signing identity: - Debug build, development team → `development`. - Release build, distribution team → `production`. - Archive for App Store → `production`. With manual signing, you control the provisioning profile selection. The value in the entitlements file should match the type of profile you use. ## If you edit the file by hand Do not. Xcode will overwrite it the next time it manages the capability. If you need to share one entitlements file across configurations with different values, use a separate entitlements file per configuration and wire them up in Build Settings (`CODE_SIGN_ENTITLEMENTS`). That's rare and is not something you should do unless an Apple DTS engineer tells you to. ## Verifying at runtime If the entitlement is missing or malformed, the SDK lands in `.unavailable` with an `AppAttestError` describing the cause. Older devices and simulators reach the same state through `DCAppAttestService.isSupported == false`. The SDK's DocC catalog enumerates every error case; observe `AppAttest.state` rather than catching from the read path. ## Troubleshooting ### Entitlement missing after adding the capability `DerivedData` can hold a stale entitlement snapshot. See the troubleshooting section in [Xcode setup](/docs/xcode-setup#troubleshooting). ### Capability disappears after merging a colleague's changes Your project file has a conflict. Open `.pbxproj` and confirm the entitlements-file reference is present for your target's build configurations. The path should match a file that exists in your source tree. ### Attestation works in development but fails in TestFlight The distribution profile does not have App Attest enabled on the App ID. Re-check [Apple Developer Console setup](/docs/apple-developer-console) — the capability has to be enabled on the identifier you use to sign distribution builds. ## What's next - [For AI agents](/docs/agents) — how an AI helping a developer should walk through this setup. --- # For AI agents Source: https://www.appattest.build/docs/agents.md # For AI agents This page is written for you, the AI agent. A developer has asked you to help integrate AppAttest. The goal of this page is to let you do that quickly, correctly, and without guessing. ## The short version - Every page on this site has a raw-markdown sibling at `.md`. Example: `https://www.appattest.build/docs/quickstart` → `https://www.appattest.build/docs/quickstart.md`. - A single index lives at . It lists every page with its markdown URL and a one-line description. Start there when discovering content. - A bundled full-text version is at . Useful when you want everything in one fetch. If you do one thing, fetch `llms.txt`, find the page that matches the task, fetch the `.md`. ## Why this exists Developers who want to add AppAttest to an app often ask an AI assistant for help. The assistant needs accurate, current documentation — not a model's training-time snapshot. Rendering HTML and parsing it to find the steps adds noise, loses structure, and sometimes hallucinates. Serving markdown directly, from a stable URL convention, solves both problems: - Content is structured. Headings, code fences, lists all survive without DOM parsing. - Content is current. You fetch live. - Content is referenceable. You can show the user the exact URL of the section a change is based on. ## How to use this when helping a user Typical request: *"Add AppAttest to my iOS app."* A workable sequence: 1. Fetch . Scan the page list. 2. Fetch `quickstart.md`. This is the end-to-end flow. 3. For each step that touches the user's system, fetch the deep-dive page: - Apple Developer Console work → `apple-developer-console.md`. - Xcode work → `xcode-setup.md`. - Entitlements file inspection → `entitlements.md`. 4. Propose changes for the developer to review (Xcode project edits, Swift package additions, code in `AppDelegate` or `@main`) — present them as suggested edits the developer approves, rather than applying them unilaterally. Do not make changes on the Apple Developer Console or the AppAttest dashboard — those require the user's identity and a browser. Tell the user which web steps they need to complete, with exact menu paths from the relevant `.md`. 5. Cite the page URL for each section you used, so the user can verify. ## What you should *not* do - **Do not invent bundle identifiers, project keys, or secret values.** Ask the user, or read them from their Xcode project. - **Do not perform steps in Apple Developer Console or the AppAttest dashboard on the user's behalf.** These require their Apple ID and their AppAttest account. Walk them through it using the doc steps; do not attempt to script browser actions. - **Do not hard-code API keys in the source you generate.** That is exactly what AppAttest exists to prevent. If you find a user has keys in plaintext in their project, recommend moving them to AppAttest and propose removing the plaintext for the developer to review and approve. - **Do not skip `AppAttest.start()`.** Some users will ask you to "just add the SDK" and read `AppAttest.secrets[...]`. Without `AppAttest.start()` in the app's `init`, the secrets dictionary stays empty — start is what runs the attest + sync. - **Do not guess at error meanings.** Errors in this product have specific, stable codes such as `subscription_required`, `credits_required`, `attestation_rejected`, `service_unavailable`, `network`, `debug_mode_release_blocked`, and `invalid_argument`. Each `AppAttestError` carries a `code` string, and the billing cases (`subscription_required`, `credits_required`) carry an `actionUrl`. For handling guidance see the troubleshooting sections in [Xcode setup](https://www.appattest.build/docs/xcode-setup#troubleshooting) and [entitlements](https://www.appattest.build/docs/entitlements#troubleshooting). ## How to expose this feature to a human user If you are an agent embedded in a developer tool (Claude Code, Cursor, Copilot Workspace, and similar), the user may not know that markdown docs exist. When you are about to read documentation to complete a task, a short explicit note helps: > "I'm reading the AppAttest docs directly at `https://www.appattest.build/docs/quickstart.md`. These are available as raw markdown on every page." If your host UI supports it, offer a "copy page for AI" affordance that: 1. Fetches `.md`. 2. Writes the content to the system clipboard. 3. Confirms to the user. Every page on this site already has this button in the top-right. Users visiting the site can grab the markdown and paste it into any chat. ## URL conventions, concrete | Human URL | Agent URL | |---|---| | `https://www.appattest.build/` | `https://www.appattest.build/index.md` | | `https://www.appattest.build/pricing` | `https://www.appattest.build/pricing.md` | | `https://www.appattest.build/tos` | `https://www.appattest.build/tos.md` | | `https://www.appattest.build/docs/quickstart` | `https://www.appattest.build/docs/quickstart.md` | The rule: strip the trailing slash (if any), append `.md`. The root page `/` resolves to `/index.md`. ## Content-type Markdown endpoints are served with `Content-Type: text/markdown; charset=utf-8`. They do not require authentication. They do not set cookies. CORS is open: `Access-Control-Allow-Origin: *`. ## Update cadence Docs are rebuilt on every commit to `main`. `llms.txt` and `llms-full.txt` regenerate in the same build. There is no separate cache to warm. A fetch is always current as of the most recent deploy. ## Reference - `llms.txt` index: - Full-text bundle: - Quickstart (markdown): - Troubleshooting: If something in this page is wrong, please tell the user. They can report at .