> ## 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.

# Share state between packages

> Use Bitfield state for shared product facts instead of sharing another package's private object.

<div className="bf-article">
  <p className="bf-lead">
    When two packages need the same state, do not make one package read another package's private object. Put the shared product fact in Bitfield and let each package read the view it needs.
  </p>

  A file tree chooses a file, then the editor, breadcrumbs, command palette, and AI context panel all need the active file. That state is no longer a private file-tree detail. It is product coordination state.

  Every package should see the same selected file without importing the file tree, sharing memory with it, or duplicating its private store.

  ## Traditional app shape

  ```ts theme={null}
  // file-tree/store.ts
  export const fileTreeStore = {
    selectedFile: '/app/components/Header.tsx',
  };

  // editor/open-file.ts
  import { fileTreeStore } from '../file-tree/store';

  export function openEditor() {
    return openFile(fileTreeStore.selectedFile);
  }
  ```

  This works until it does not. The editor now imports the file tree store. If the file tree changes its store shape, moves packages, or becomes a different UI, the editor breaks.

  ## Bitfield shape

  ```text theme={null}
  Bitfield state:
  selected-file = /app/components/Header.tsx

  file tree updates selected-file
  file editor reads selected-file
  breadcrumbs read selected-file
  AI context reads selected-file
  ```

  No package reads the file tree's private object. They all read the shared Bitfield fact.

  ## Code translation

  ### Traditional path

  ```ts theme={null}
  import { fileTreeStore } from '../file-tree/store';

  const selected = fileTreeStore.selectedFile;
  ```

  ### Bitfield path

  ```ts theme={null}
  const selectedFile = readInput('selected-file');
  ```

  ### React adapter example

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

  export function FileEditorShell() {
    const selectedFile = useBitfieldData<string>('selected-file');

    if (selectedFile.loading) return <p>Loading file</p>;
    if (selectedFile.error) return <p>Could not read the selected file.</p>;
    if (!selectedFile.data) return <p>No file selected.</p>;

    return <Editor filePath={selectedFile.data} />;
  }
  ```

  React is only the adapter shown here. The same rule applies to any shell: read the named Bitfield input instead of importing the file tree.

  ## Review checklist

  | Check                                       | Good answer                                                                 |
  | ------------------------------------------- | --------------------------------------------------------------------------- |
  | Does more than one package need the value?  | It is a shared product fact or data name, not one package's private object. |
  | Does the code import another package store? | Replace it with a named read.                                               |
  | Is the value only visual?                   | Keep it private instead of sharing it.                                      |
  | Can a non-React shell read the same value?  | Yes. The name is Runtime Kit-level, not React-only.                         |

  ## More examples

  | Shared product fact | Traditional mistake                                            | Bitfield shape                          |
  | ------------------- | -------------------------------------------------------------- | --------------------------------------- |
  | Current project     | Every panel imports `projectStore.current`.                    | Packages read `current-project`.        |
  | Selected agent      | Keyboard, chat, and timeline import one agent store.           | Packages read `selected-agent`.         |
  | Active conversation | Chat, sidebar, and notifications pass props through the shell. | Packages read `active-conversation`.    |
  | Preview status      | Dashboard imports preview service private code.                | Packages read `project-preview-status`. |

  ## One product fact, many readers

  The mental model is simple: a product fact is not owned by the first UI that touched it. The file tree might be the place where a user selected a file, but "the selected file" is not the file tree's private object once the editor, AI panel, breadcrumbs, and command palette all need it.

  Traditional code turns the first UI into the source every other package imports:

  ```ts theme={null}
  import { fileTreeStore } from '../file-tree/store';

  export function buildContext() {
    return { filePath: fileTreeStore.selectedFile };
  }
  ```

  Bitfield code turns the fact into a named product value:

  ```ts theme={null}
  const selectedFile = readInput('selected-file');
  ```

  ### React adapter example

  ```tsx theme={null}
  const selectedFile = useBitfieldData<string>('selected-file');
  ```

  The AI panel does not import the tree, command palette, recent-files list, command-line launch, or another device path. It reads the product fact it needs.

  ## Four shared-state situations

  ### Selected file

  ### Private file-tree read

  ```ts theme={null}
  import { selectedFile } from '../file-tree/state';
  ```

  ### Read the public selected file

  ```ts theme={null}
  const selectedFile = readInput('selected-file');
  ```

  Use this when multiple packages react to the same selected file.

  ### Current project

  ### Private workspace read

  ```ts theme={null}
  import { currentProject } from '../workspace/project-store';
  ```

  ### Read the public project

  ```ts theme={null}
  const project = readInput('current-project');
  ```

  Use this when panels, package filters, build actions, and account surfaces all need the same project context.

  ### Selected agent

  ### Private agent setter

  ```ts theme={null}
  selectedAgentStore.set(agentId);
  ```

  ### Request the selected-agent change

  ```ts theme={null}
  await sendRequestToBitfieldTarget({
    target: 'selected-agent.update',
    payload: { agentId },
  });
  ```

  Then readers use the selected-agent product fact instead of importing the setter package.

  ### Notification mode

  ### Private notification object

  ```ts theme={null}
  import { notificationSettings } from '../notifications/settings';

  notificationSettings.mode = 'quiet';
  ```

  ### Request the mode change

  ```ts theme={null}
  await sendRequestToBitfieldTarget({
    target: 'notification-mode.update',
    payload: { mode: 'quiet' },
  });
  ```

  Readers should observe the public mode value. Callers should not mutate notification package objects.

  ## What not to store as shared state

  | Value                  | Keep private or share?          | Reason                                                                     |
  | ---------------------- | ------------------------------- | -------------------------------------------------------------------------- |
  | Row hover              | Private                         | It is only visual.                                                         |
  | Editor scroll position | Usually private                 | It belongs to the current surface unless another package truly needs it.   |
  | Selected file          | Share                           | Editor, AI context, breadcrumbs, and commands may need it.                 |
  | Current project        | Share                           | It changes what many packages show.                                        |
  | Modal open state       | Usually private                 | The modal package can own it unless other packages coordinate around it.   |
  | Notification mode      | Share through a target and fact | Multiple callers can ask for the change, and multiple readers may show it. |

  ## What this prevents

  | Bad shape                                       | Why it breaks                                               | Better shape                                |
  | ----------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------- |
  | Package A imports Package B's store.            | Package A now depends on Package B's private code.          | Package A reads a named Bitfield input.     |
  | Each package keeps its own copy.                | Copies drift and disagree.                                  | Packages read the same Bitfield fact.       |
  | The shell passes the value through every layer. | The shell becomes the coordinator for shared product state. | Packages read the shared fact directly.     |
  | A package stores every click in Bitfield.       | Temporary UI noise becomes product state.                   | Only coordination state goes into Bitfield. |

  ## Common mistake

  Do not put every piece of state in Bitfield.

  ```text theme={null}
  private hover state -> keep private
  dropdown open state -> keep private
  draft field text before submit -> usually private
  selected file used by many packages -> Bitfield state
  current project used by many packages -> Bitfield state
  ```

  ## Review check

  When code imports another package's store, stop. Ask whether the value is a shared product fact. If yes, read a Bitfield input. If no, keep it private to the package that uses it.

  ## Next

  * Learn when state should stay private: [Keep private UI state private](/runtime-kit/build-without-tangled-code/keep-private-ui-state-private)
  * Read prepared values: [Read data another package prepared](/runtime-kit/build-without-tangled-code/read-data-another-package-prepared)
  * Look up the React read adapter: [Runtime Kit API](/reference/runtime-kit-api)
</div>
