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

# Ask another package to do work

> Send a request to a named target instead of importing and calling another package's implementation.

<div className="bf-article">
  <p className="bf-lead">
    When a package needs another package to run work, call a named Bitfield target. Do not import the implementation function directly.
  </p>

  A keyboard package changes the selected agent. A notifications package changes the notification mode. A search box asks a search target for results. In traditional code, these become direct service calls. In Bitfield, they are action requests.

  A correct caller uses the action name and payload shape. It does not import the implementation file for the work.

  ## Traditional app shape

  ```ts theme={null}
  import { updateSelectedAgent } from '../selected-agent/service';

  export async function onShortcut(agentId: string) {
    await updateSelectedAgent(agentId);
  }
  ```

  That direct call now depends on the selected-agent package implementation. If the implementation moves, changes runtime, or becomes a slot, the caller changes too.

  ## Bitfield shape

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

  export async function onShortcut(agentId: string) {
    await sendRequestToBitfieldTarget({
      target: 'selected-agent.update',
      payload: { value: agentId },
    });
  }
  ```

  The action name is the public target. The implementation can change without making the caller import new code.

  ## Code translation

  | Traditional code                      | Bitfield code                                           |
  | ------------------------------------- | ------------------------------------------------------- |
  | Import a service function.            | Call `sendRequestToBitfieldTarget(...)`.                |
  | Pass private objects.                 | Send a small public payload.                            |
  | Return whatever the function returns. | Decode reply bytes according to the action reply shape. |
  | Catch implementation errors.          | Handle request failure and bad replies.                 |

  ## Good action requests

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

  ```ts theme={null}
  const reply = await sendRequestToBitfieldTarget({
    target: 'project-preview.refresh-status',
    payload: { projectId: 'app' },
  });
  ```

  ```ts theme={null}
  const reply = await sendRequestToBitfieldTarget({
    target: 'help.search',
    payload: { query: 'activation key' },
  });
  ```

  Each request names the job and sends the smallest public payload needed for that job.

  ## Four request situations

  ### Refresh a preview

  ### Direct service call

  ```ts theme={null}
  import { refreshPreview } from '../project-preview/refresh';

  await refreshPreview(projectId);
  ```

  ### Use the action name

  ```ts theme={null}
  await sendRequestToBitfieldTarget({
    target: 'project-preview.refresh-status',
    payload: { projectId },
  });
  ```

  The caller uses the job name and payload. It does not import the implementation file.

  ### Change selected agent

  ### Direct store mutation

  ```ts theme={null}
  import { selectedAgentStore } from '../agents/store';

  selectedAgentStore.set(agentId);
  ```

  ### Ask for the change

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

  The same request can come from a keyboard shortcut, command palette, sidebar, or future shell.

  ### Update notification mode

  ### Direct package function

  ```ts theme={null}
  import { setNotificationMode } from '../notifications/mode';

  await setNotificationMode('quiet');
  ```

  ### Send the public request

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

  Settings and command surfaces can call the same public action without sharing notification package code.

  ### Search help content

  ### Private search import

  ```ts theme={null}
  import { searchHelpIndex } from '../help/search-index';

  const results = searchHelpIndex(query);
  ```

  ### Search through the target

  ```ts theme={null}
  const results = await sendRequestToBitfieldTarget({
    target: 'help.search',
    payload: { query },
  });
  ```

  The caller sends the question. The package that owns the searchable material decides how to answer.

  ## Request versus state

  | You need to...                    | Use                                                         | Reason                                                  |
  | --------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------- |
  | Show the currently selected file. | Data name or Bitfield state read.                           | Nothing has to run just to observe it.                  |
  | Change which file is selected.    | Action request or state write through the package contract. | A change may need validation, side effects, or fan-out. |
  | Render preview URL.               | Data name.                                                  | The preview package already prepared the view.          |
  | Refresh preview URL.              | Action request.                                             | Work has to run.                                        |
  | Toggle a dropdown.                | Private UI state.                                           | It is visual-only.                                      |
  | Change notification mode.         | Action request.                                             | Multiple callers can request the same product action.   |

  ## Reply and error boundary

  The caller may use the reply shape. It must not import the implementation path.

  ```ts theme={null}
  const reply = await sendRequestToBitfieldTarget({
    target: 'project-preview.refresh-status',
    payload: { projectId },
  });

  if (!reply.ok) {
    showError(reply.error.message);
  }
  ```

  If the target returns bytes, text, JSON, or a structured result, the page that defines the target should say that. The caller should decode only the documented reply shape.

  ## Review checklist

  | Check                                         | Good answer                                                    |
  | --------------------------------------------- | -------------------------------------------------------------- |
  | Does the caller import implementation code?   | No. It sends an action request.                                |
  | Is the payload small and public?              | Yes. It contains only the fields the action reply shape needs. |
  | Is the caller guessing the reply shape?       | No. It decodes the documented reply shape.                     |
  | Can the same request come from another shell? | Yes. React is one adapter, not the action owner.               |

  ## What this prevents

  | Bad shape                                                   | Why it breaks                                      | Better shape                                   |
  | ----------------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------- |
  | Button imports target implementation.                       | UI and work runtime become coupled.                | Button sends an action request.                |
  | Caller passes a huge private object.                        | Action reply shape depends on caller private code. | Caller sends a small public payload.           |
  | Caller assumes every reply is JSON.                         | Non-JSON targets break the caller.                 | Decode according to the action reply shape.    |
  | Caller updates Bitfield state and runs side effects itself. | Work logic spreads across packages.                | Request the package target that owns that job. |

  React is one adapter that can send an action request. The same target should make sense from a keyboard shortcut, a terminal command, a Swift screen, a background job, or a future shell.

  ## Common failures

  | Symptom                                                | Likely mistake                                 | Fix                                                   |
  | ------------------------------------------------------ | ---------------------------------------------- | ----------------------------------------------------- |
  | Button works only in one package.                      | It imported a local implementation.            | Move the call to an action request.                   |
  | Reply parsing breaks.                                  | The caller guessed the reply shape.            | Document the action reply shape and decode only that. |
  | Work runs twice.                                       | UI code both updates state and calls a worker. | Pick the action request as the work boundary.         |
  | A new service file appears just to cross the boundary. | It copied the traditional app shape.           | Call a named target.                                  |

  ## Review check

  If caller code imports a function from another package to "do work," stop. The public API is an action request. The caller may use the action name, payload, reply shape, and error states. It must not import the implementation file.

  ## Next

  * Look up request details: [Runtime Kit API](/reference/runtime-kit-api)
  * Build a callable package target: [Callable package slot](/runtime-kit/cookbook/callable-package-slot)
  * Learn when to read instead of request: [Read data another package prepared](/runtime-kit/build-without-tangled-code/read-data-another-package-prepared)
</div>
