> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bitfield.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Package to screen

> Build the first complete Runtime Kit feature: package data, a button action, a React screen, verification, and failure checks.

<div className="bf-article">
  <p className="bf-lead">
    Build one complete feature the Runtime Kit way: a package lists data and an action, Runtime Kit checks that package file, a React screen reads the named data, and a button asks the named action to do work.
  </p>

  ## What you will build

  You are building a small welcome panel for a product launch screen.

  The panel needs three public pieces:

  | Product moment                           | Runtime Kit shape                                                             |
  | ---------------------------------------- | ----------------------------------------------------------------------------- |
  | The screen shows welcome copy.           | A package `record` becomes named data for `useBitfieldData(...)`.             |
  | The user clicks for a launch suggestion. | A package `slot` named `welcome.suggest` becomes the action the button calls. |
  | The screen handles real UI states.       | The React screen renders loading, error, empty, and success.                  |

  The screen does not parse package files. The package does not import React. The button does not import the code behind `welcome.suggest`. Runtime Kit keeps those jobs separated.

  ```text theme={null}
  package folder
    -> things-to-store-and-run.json
    -> Runtime Kit admits the package
    -> screen reads "welcome-copy"
    -> button calls "welcome.suggest"
  ```

  <div className="bf-flow" aria-label="Package file admission flow">
    <div className="bf-flow-node">
      <span className="bf-flow-step">01</span>
      <strong>Package folder</strong>
      <p>Files start as source material owned by the package.</p>
    </div>

    <div className="bf-flow-arrow" aria-hidden="true">→</div>

    <div className="bf-flow-node">
      <span className="bf-flow-step">02</span>
      <strong>Package file</strong>
      <p>`things-to-store-and-run.json` declares records, bytes, and targets.</p>
    </div>

    <div className="bf-flow-arrow" aria-hidden="true">→</div>

    <div className="bf-flow-node">
      <span className="bf-flow-step">03</span>
      <strong>Admitted material</strong>
      <p>Runtime Kit checks the package before app code sees handles.</p>
    </div>

    <div className="bf-flow-arrow" aria-hidden="true">→</div>

    <div className="bf-flow-node">
      <span className="bf-flow-step">04</span>
      <strong>Public names</strong>
      <p>The app reads data names and calls action names.</p>
    </div>
  </div>

  That is the full public chain. The rest of this page fills in every step.

  ## Before you start

  You need these public facts before the feature can work:

  | Requirement         | What it means                                                                  |
  | ------------------- | ------------------------------------------------------------------------------ |
  | Account and key     | Your product has access to Bitfield through the account flow.                  |
  | Active device       | This machine or runtime identity triggered Bitfield in the billing window.     |
  | Package set name    | The product has a package set, such as `launch-demo`.                          |
  | Runtime Kit package | Your app can import `@bitfield/runtime-kit` and `@bitfield/runtime-kit/react`. |

  This page does not ask you to hand-edit `~/.bitfield`. Runtime Kit and account flows own local activation and package state. If one device behaves differently from another, use [Local state](/runtime-kit/local-state) and [Troubleshooting](/runtime-kit/troubleshooting) instead of copying folders by hand.

  ## Step 1: Create the package folder

  Create one package folder inside the package set you are working on:

  ```text theme={null}
  launch-demo/
    welcome-package/
      things-to-store-and-run.json
      slots/
        suggestion-slot.bin
  ```

  The package folder is source material. Runtime Kit is not asking your React app to read this folder. Runtime Kit checks package material first, then gives the app data names and action names.

  Success check:

  ```text theme={null}
  The package has exactly one package file:
  welcome-package/things-to-store-and-run.json
  ```

  If the file is missing, Runtime Kit has no package list to check.

  ## Step 2: List what the package brings

  `things-to-store-and-run.json` declares what this package brings.

  ```json theme={null}
  {
    "package": "welcome-package",
    "things": [
      {
        "type": "record",
        "address": "package::welcome-package::welcome-copy",
        "payload": {
          "headline": "Keep shipping.",
          "body": "Your app can add the next feature without making this screen import every package."
        }
      },
      {
        "type": "slot",
        "name": "welcome.suggest",
        "methods": [
          {
            "name": "query"
          }
        ],
        "boundary": {
          "call_shape": "envelope-bytes-in-envelope-bytes-out",
          "methods": [
            {
              "name": "query"
            }
          ]
        },
        "artifact": {
          "source_path": "slots/suggestion-slot.bin"
        }
      }
    ]
  }
  ```

  The `record` is the data the screen will read. The `slot` is the named target the button will call.

  The names that matter later are:

  | Name                                     | Used by       | Meaning                                                 |
  | ---------------------------------------- | ------------- | ------------------------------------------------------- |
  | `package::welcome-package::welcome-copy` | Package file  | Stable package-owned record address.                    |
  | `welcome-copy`                           | React screen  | Data name exposed to the screen.                        |
  | `welcome.suggest`                        | Button action | Action name used by `sendRequestToBitfieldTarget(...)`. |

  The address and the screen data name are related, but they are not the same thing. The app should read the data name, not build package addresses by hand.

  ## Step 3: Admit the package

  Before admission, this is only a folder with a package file.

  After admission, Runtime Kit has checked the package and can expose data names and action names.

  | Before admission                                       | After admission                                     |
  | ------------------------------------------------------ | --------------------------------------------------- |
  | `things-to-store-and-run.json` is source material.     | Runtime Kit has checked the package file.           |
  | `welcome-copy` exists only as package data.            | Runtime Kit can make it available to a screen.      |
  | `welcome.suggest` is only declared.                    | App code can ask that action for work.              |
  | `slots/suggestion-slot.bin` is package-owned material. | App code still calls the action name, not the file. |

  Success check:

  ```text theme={null}
  The package set contains package "welcome-package".
  The data name "welcome-copy" is available to the screen.
  The action name "welcome.suggest" is available for requests.
  ```

  If the package is not available, do not patch React. Check `things-to-store-and-run.json` first. See [Package file failures](/runtime-kit/troubleshooting#package-file-failures).

  ## Step 4: Read the named data

  Your React screen reads `welcome-copy`.

  ```tsx theme={null}
  import { useBitfieldData } from '@bitfield/runtime-kit/react';

  type WelcomeCopy = {
    headline: string;
    body: string;
  };

  export function WelcomePanel() {
    const welcome = useBitfieldData<WelcomeCopy>('welcome-copy');

    if (welcome.loading) return <section>Loading welcome copy.</section>;
    if (welcome.error) return <section>Could not load welcome copy.</section>;
    if (!welcome.data) return <section>No welcome copy yet.</section>;

    return (
      <section>
        <h2>{welcome.data.headline}</h2>
        <p>{welcome.data.body}</p>
      </section>
    );
  }
  ```

  ### What should happen

  ```text theme={null}
  The screen eventually renders:

  Keep shipping.
  Your app can add the next feature without making this screen import every package.
  ```

  If the screen stays empty, check the data name and render states. See [Named data read failures](/runtime-kit/troubleshooting#named-data-read-failures).

  ## Step 5: Send a request from the button

  The button calls the action by name.

  ```tsx theme={null}
  import { sendRequestToBitfieldTarget } from '@bitfield/runtime-kit';

  async function askForSuggestion(topic: string) {
    const reply = await sendRequestToBitfieldTarget({
      target: 'welcome.suggest',
      payload: { topic },
    });

    return JSON.parse(new TextDecoder().decode(reply.payload)) as {
      suggestion: string;
    };
  }
  ```

  The request shape is:

  | Request part | Shape                                                       |
  | ------------ | ----------------------------------------------------------- |
  | Action name  | `welcome.suggest`                                           |
  | Payload      | `{ topic: string }`                                         |
  | Reply        | `{ suggestion: string }` encoded as JSON bytes              |
  | Error owner  | The request caller handles failed request or failed decode. |

  ### What should happen

  ```text theme={null}
  Calling welcome.suggest with { topic: "launch" } returns reply bytes.
  The app decodes those bytes into { suggestion: string }.
  ```

  If the request throws before work starts, check the action name and package declaration. If JSON parsing fails, check the reply shape. See [Action request failures](/runtime-kit/troubleshooting#target-request-failures) and [Reply decoding failures](/runtime-kit/troubleshooting#reply-decoding-failures).

  ## Step 6: Put the read and request together

  This is the full screen. It reads named data and asks `welcome.suggest` for work without importing package setup.

  ```tsx theme={null}
  import { useState } from 'react';
  import { sendRequestToBitfieldTarget } from '@bitfield/runtime-kit';
  import { useBitfieldData } from '@bitfield/runtime-kit/react';

  type WelcomeCopy = {
    headline: string;
    body: string;
  };

  type SuggestionReply = {
    suggestion: string;
  };

  export function WelcomePanel() {
    const welcome = useBitfieldData<WelcomeCopy>('welcome-copy');
    const [suggestion, setSuggestion] = useState<string | null>(null);
    const [requestError, setRequestError] = useState<string | null>(null);

    async function refreshSuggestion() {
      setRequestError(null);

      try {
        const reply = await sendRequestToBitfieldTarget({
          target: 'welcome.suggest',
          payload: { topic: 'launch' },
        });

        const text = new TextDecoder().decode(reply.payload);
        const data = JSON.parse(text) as SuggestionReply;
        setSuggestion(data.suggestion);
      } catch (error) {
        setRequestError(error instanceof Error ? error.message : 'Request failed.');
      }
    }

    if (welcome.loading) return <section>Loading welcome copy.</section>;
    if (welcome.error) return <section>Could not load welcome copy.</section>;
    if (!welcome.data) return <section>No welcome copy yet.</section>;

    return (
      <section>
        <h2>{welcome.data.headline}</h2>
        <p>{welcome.data.body}</p>
        <button type="button" onClick={refreshSuggestion}>
          Refresh suggestion
        </button>
        {requestError ? <p>{requestError}</p> : null}
        {suggestion ? <p>{suggestion}</p> : null}
      </section>
    );
  }
  ```

  The component owns UI state. It does not own package admission, storage layout, or the implementation for `welcome.suggest`.

  ## Step 7: Verify the feature

  Use this checklist before treating the feature as done:

  | Check                | Pass condition                                                             |
  | -------------------- | -------------------------------------------------------------------------- |
  | Package file exists  | `welcome-package/things-to-store-and-run.json` exists.                     |
  | Record is declared   | The package file has a `record` for `welcome-copy`.                        |
  | Action is declared   | The package file has a `slot` named `welcome.suggest`.                     |
  | Read states render   | The component renders loading, error, empty, and success.                  |
  | Request has a shape  | The button sends `{ topic: string }` and decodes `{ suggestion: string }`. |
  | No private imports   | App code imports only public Runtime Kit functions.                        |
  | No local state edits | No one fixes the feature by editing `~/.bitfield` by hand.                 |

  If any row fails, fix that row before adding a second feature.

  ## What not to do

  Do not make the React component parse `things-to-store-and-run.json`. That moves package admission into the UI.

  Do not hardcode package folder paths into app code. The folder is package input, not the app API.

  Do not import the slot implementation into the button. Call `welcome.suggest`.

  Do not skip loading, error, or empty states. Runtime Kit features still have real user states.

  Do not publish package examples that contain private tokens, account secrets, or real customer data.

  ## What changes when the feature grows

  The public chain can grow without changing its shape.

  | Growth                                                  | What stays stable                                                         |
  | ------------------------------------------------------- | ------------------------------------------------------------------------- |
  | More copy records.                                      | Components still read data names.                                         |
  | A faster slot implementation.                           | The action name can stay `welcome.suggest`.                               |
  | A package-owned help file.                              | The package still lists owned material in `things-to-store-and-run.json`. |
  | A non-React screen later.                               | The read/request split still applies.                                     |
  | Another product with a package named `welcome-package`. | Package sets keep project material separated.                             |

  Runtime Kit is valuable because the feature can get bigger without forcing every screen to import or configure every lower layer.

  ## Debug the chain

  When something fails, locate which link failed:

  | Symptom                              | Check this link                                         | Fix path                                                                          |
  | ------------------------------------ | ------------------------------------------------------- | --------------------------------------------------------------------------------- |
  | Package cannot be admitted.          | `things-to-store-and-run.json` and package-owned paths. | [Package file failures](/runtime-kit/troubleshooting#package-file-failures)       |
  | Component never receives data.       | Data name and screen scope.                             | [Named data read failures](/runtime-kit/troubleshooting#named-data-read-failures) |
  | Button throws before work starts.    | Action name and payload shape.                          | [Action request failures](/runtime-kit/troubleshooting#target-request-failures)   |
  | Reply cannot be parsed as JSON.      | Reply shape and decoder.                                | [Reply decoding failures](/runtime-kit/troubleshooting#reply-decoding-failures)   |
  | Works on one device but not another. | Activation and package-set state.                       | [Local state confusion](/runtime-kit/troubleshooting#local-state-confusion)       |

  Start at `things-to-store-and-run.json`. Then check the data name or action name. Then check the component.

  ## Feature map

  Keep this map beside the feature while building it:

  ```md theme={null}
  ## Runtime Kit feature map

  - Package set: launch-demo
  - Package: welcome-package
  - Package file: welcome-package/things-to-store-and-run.json
  - Data name: welcome-copy
  - Action name: welcome.suggest
  - Request payload: { topic: string }
  - Reply payload: { suggestion: string }
  - React screen: WelcomePanel
  - Public imports only:
    - @bitfield/runtime-kit
    - @bitfield/runtime-kit/react
  ```

  That map keeps everyone working on the same public names.

  ## Quick reference

  ```text theme={null}
  Declare record       -> read with useBitfieldData(...)
  Declare slot         -> call with sendRequestToBitfieldTarget(...)
  Change implementation -> keep data or action names stable
  Change app UI        -> keep package admission out of React
  Debug failure        -> identify package file, read, request, decode, or activation link
  ```

  ## Where to go next

  Read [JavaScript Runtime Kit](/runtime-kit/javascript) when you want the full mental model.

  Read [Packages](/runtime-kit/packages) when you are shaping `things-to-store-and-run.json`.

  Read [`things-to-store-and-run.json`](/reference/package-boundary) when you need exact `record`, `stored_bytes`, or `slot` field rules.

  Read [Read data in React](/runtime-kit/use-bitfield-data) when a component needs named data.

  Read [Send a request](/runtime-kit/send-request) when a button needs an action.

  Read [Runtime Kit API](/reference/runtime-kit-api) when you need exact request, reply, selector, and render-state contracts.

  Read [Troubleshooting](/runtime-kit/troubleshooting) when the chain breaks.

  ## Now build the bigger version

  Take the same chain and build a screen that uses two packages.

  Package one owns the copy:

  ```json theme={null}
  {
    "type": "record",
    "address": "package::welcome-package::welcome-copy",
    "payload": {
      "headline": "Keep shipping.",
      "body": "Your app can add the next feature without making this screen import every package."
    }
  }
  ```

  Package two owns the checklist:

  ```json theme={null}
  {
    "type": "record",
    "address": "package::launch-checklist::items",
    "payload": {
      "items": [
        "Create your account",
        "Activate this device",
        "Run your first package",
        "Call your first target"
      ]
    }
  }
  ```

  The React screen reads both data names without importing either package:

  ```tsx theme={null}
  const welcome = useBitfieldData<WelcomeCopy>('welcome-copy');
  const checklist = useBitfieldData<{ items: string[] }>('launch-checklist');
  ```

  Then add one action name, such as `launch.next-step`, for the button that helps the user keep moving. The UI now has copy, checklist data, and a callable action while still using the same public read/request shape.

  When that shape feels clear, learn the larger composition in [Placeable surfaces](/runtime-kit/placeable-surfaces), then copy the full example in [Placeable surface product loop](/runtime-kit/cookbook/placeable-surface-product-loop).
</div>
