Skip to main content

A Runtime Kit package is a folder with one public files-and-names file. That file tells Bitfield what to store, which bytes the package owns, and which callable slots the package exposes.

What this is

Packages are how features enter Bitfield without turning into direct imports everywhere.A package can bring three public kinds of things:
ThingPlain meaning
recordStore or remove one named piece of package data.
stored_bytesAttach package-owned bytes, such as text, JSON, images, or other files.
slotDeclare a named package target app code can ask for work.
The package file says what exists. Runtime Kit decides how those declarations become public names.

The mental model

Put a boundary file in the package. The boundary file says, “Here is what this package wants Bitfield to know about.” Runtime Kit checks that file before package material becomes active.That check is important. The package should not quietly read files outside itself. It should not invent unsupported thing types. It should not force app code to import private setup. A package declares the public shape; Bitfield owns the admission path.

Folder shape

<package-set>/
  <package-name>/
    things-to-store-and-run.json
    slots/
    other package-owned files
<package-set> is the collection for one product or project. <package-name> is one package inside that collection.

Boundary file

Every package has one boundary file:
things-to-store-and-run.json
Minimum file:
{
  "package": "sample-package",
  "things": []
}
The package field names the package. The things array lists what the package declares.

Package sets

A package set is a named collection of packages for one product or project.Package sets matter because two projects can use the same package names without colliding. For example, two products can both have a package named search-package if they live in different package sets.

Record entry

Use record when the package needs one named piece of durable data.
{
  "type": "record",
  "address": "package::product-copy::welcome",
  "payload": {
    "headline": "Welcome back.",
    "body": "Your product can keep moving without every feature importing every other feature."
  }
}
The address is the stable package-owned name for that data. Keep the same address when you want to update the same piece of package data.A record chooses exactly one action:
ActionMeaning
payloadStore JSON-compatible data.
payload_textStore text.
payload_base64Store bytes encoded as base64.
remove: trueRemove the record at that address.
Do not combine those actions in one record.

Stored bytes entry

Use stored_bytes when a package brings a file.
{
  "type": "stored_bytes",
  "name": "getting-started-help",
  "source_path": "help/getting-started.txt"
}
source_path must point inside the package folder. That rule keeps packages from reading random files on the machine.Stored bytes are good for:
  • Help text.
  • JSON config.
  • Images or other package-owned assets.
  • Data files a callable slot needs.

Slot entry

Use slot when a package exposes a named target app code can call.
{
  "type": "slot",
  "name": "product.search",
  "methods": [
    {
      "name": "query"
    }
  ],
  "boundary": {
    "call_shape": "envelope-bytes-in-envelope-bytes-out",
    "methods": [
      {
        "name": "query"
      }
    ]
  },
  "artifact": {
    "source_path": "slots/search-slot.bin"
  }
}
The public parts are the slot name, method list, call boundary, and package-owned artifact path. The slot implementation is not app API.Your app calls the slot through the action name:
await sendRequestToBitfieldTarget({
  target: 'product.search',
  payload: { query: 'blue jacket' },
});

Validation rules

Runtime Kit should reject package material before it becomes active when:
ProblemWhy it is rejected
Missing things-to-store-and-run.jsonRuntime Kit needs one boundary file.
Unknown thing typeUnsupported package law cannot become active.
Record has no payload actionRuntime Kit cannot tell what the record should do.
Record has multiple payload actionsOne record should perform one data operation.
File path escapes the packagePackages must not read arbitrary local files.
Slot is missing a boundaryApp code needs a public call shape.

Before / after

Before packagesWith packages
Feature data is scattered through app code.Package data is declared in one boundary.
Files are copied by convention.Package-owned bytes are declared by name.
A callable feature is imported directly.The package exposes a named target.
Removing a feature means hunting through imports.Replacing a package can keep public names stable.

Common mistakes

Putting secrets in package filesDo not put private keys, tokens, or account secrets into package records or stored bytes.Pointing outside the packagesource_path must stay inside the package folder. Move the file into the package instead of using ../.Using package data as app codeThe package file declares data and callable slots. App code should still use Runtime Kit read/request calls.Making the slot name too specificUse a stable action name like product.search. Do not bake an implementation name into the public action name.

Quick reference

Minimum:
{
  "package": "sample-package",
  "things": []
}
Record:
{ "type": "record", "address": "package::sample::main", "payload": { "ok": true } }
Stored bytes:
{ "type": "stored_bytes", "name": "help", "source_path": "help.txt" }
Slot:
{
  "type": "slot",
  "name": "product.search",
  "methods": [{ "name": "query" }],
  "boundary": {
    "call_shape": "envelope-bytes-in-envelope-bytes-out",
    "methods": [{ "name": "query" }]
  },
  "artifact": { "source_path": "slots/search-slot.bin" }
}
For exact top-level fields, thing-type fields, valid examples, invalid examples, and path-safety rules, read Package file. For complete Runtime Kit recipes, read Runtime Kit Cookbook.

Now build the bigger version

Build one package that owns a complete feature slice: data, a help file, and a callable target.
{
  "package": "launch-assistant",
  "things": [
    {
      "type": "record",
      "address": "package::launch-assistant::checklist",
      "payload": {
        "items": ["Create account", "Activate device", "Run package"]
      }
    },
    {
      "type": "stored_bytes",
      "name": "launch-help",
      "source_path": "help/launch-help.txt"
    },
    {
      "type": "slot",
      "name": "launch.next-step",
      "methods": [{ "name": "query" }],
      "boundary": {
        "call_shape": "envelope-bytes-in-envelope-bytes-out",
        "methods": [{ "name": "query" }]
      },
      "artifact": { "source_path": "slots/next-step.bin" }
    }
  ]
}
That package gives the app three public names: a prepared checklist input, package-owned help bytes, and the launch.next-step target. The app uses those handles instead of importing package setup code.
Last modified on May 10, 2026