# Sharing — move agents, tools and providers as a file

Export an agent, a tool or a provider with everything it depends on as one .bylm.json file, and import such a file with every conflict, mapping and host consent decided by you before anything is written.

Status: Shipped

An agent is only useful with the provider it binds to and the tools it attaches, so Bring Your LM
exports all of that together: one `.bylm.json` file that another install reads back. Nothing goes
through a server — you hand the file over however you like, and the other side imports it. The
[marketplace](/docs/features/marketplace) on the website is one place to hand it over: you upload the file
there in a browser and others download it, and the app itself never talks to it.

## Why it matters

A setup that took an afternoon to get right — a provider endpoint, a fetch tool with the right
headers, an agent whose prompt finally behaves — is worth handing to a friend, to your other
laptop, or to a phone that does not sync. Retyping it is where the mistakes creep in. The file
carries the definitions; the person importing keeps control over what binds to what, and the
secrets never leave.

## Exporting

Every agent, tool and provider page has **Export** in its menu, beside Copy. The agent list's
selection bar — long-press an agent, tick the rest — has an **Export** too, so a few agents that
share tools and a provider go out as one file with the shared things in it once.

Export works from one workspace at a time. A file names what it holds by name, and two workspaces
can each have an agent or a tool of the same name, so under **All workspaces** the list's Export
stays off and a tool's page has none; pick the workspace first.

Before the file is written you see a review of everything that travels:

- Every agent, tool and provider in the file, with the workspace each sat in. Selecting an agent
  pulls in its provider, its tools, the providers those tools' output filters name, and every
  agent its `sub_agent-call` allowlist reaches — each once, however many roads lead to it.
- Each provider, with a switch that starts off — on for a provider you export from its own page.
  Left out, the provider is not in the file: each agent and model filter that ran on it keeps only
  the id of its model, its generation settings and what its model must handle, and whoever
  imports it picks a provider of their own, with that model preselected where their provider
  lists it. The review lists those under _Model chosen on import_. Switched on, the provider
  travels with its name and address, and its models with it. A provider on your local network,
  such as `192.168.1.20` or `gpu-box.local`, is flagged once it is on: the importer most likely
  cannot reach it, and the file tells them about your network. One at `localhost` is flagged too:
  on the importer's device it means their own machine.
- Every host the file's fetch tools send to; whoever imports the file will be asked to accept
  each one.
- The [constants](/docs/features/tools#constants-an-account-id-typed-once) the importer will be asked
  for, such as an account id a provider's address or a fetch tool's URL places. Each travels by
  its name, hint and link alone: an account id is personal even when it is not secret. Switch one
  on to share its text too — worth it for a public namespace or a region, not for a customer's
  account. Each goes by the name you gave it here; edit the name and hint, or use the generated
  name, the slot it fills, such as "accountId". On import, each secret and constant shows its hint
  and a "Where to get it" link when the file has one.
- The secrets the importer will be asked for: a provider's API key, each `{secrets.<name>}` a
  provider's headers or a fetch tool's request places, one entry for a secret that several of
  them share here, with where it is sent. Each goes by the name, hint and link of the secret it
  is linked to here. Edit the name and hint the importer reads, such as where to get an API key,
  or pick the generated name, made from the host it is first sent to, such as "openrouter.ai API
  key"; a secret linked to nothing here starts with it. The names you gave your secrets can say
  something about you: **Use generated names** renames every secret at once. A secret a fetch tool
  can do without is left out unless you include it. No secret's value ever goes into a bundle.
- Anything that could not travel: an attached tool that no longer exists, a provider that is gone,
  a tool another device made with an older version of the app and that has not been saved here
  since — save it once to share it — or an item holding settings only a newer version of the app
  can read — export it from that version instead.
- Anything that keeps the file from being imported: a provider header that would carry a
  credential, a field longer than its limit, a list with too many entries, agents that would call
  each other in a loop, or a character nobody reading the file could see — an invisible space, a
  character that reverses the direction of the text around it. Each names the item it is in, and
  Save stays disabled until it is fixed in that item's editor.

A provider that runs on the device — the embedded engine — never travels: no other device can reach
it, so it cannot be exported. A tool kind that ships with the app travels as a reference, never as
a copy. A model on the embedded engine travels as a description of its GGUF files: name,
quantization, size and a fingerprint of their contents, with the vision projector if it has one.
The files themselves never go into the bundle. The review lists each such file
under _Models run on this device_, the model and its vision projector apart, where you can add the
page each can be downloaded from. If a file's own header names a page, the review offers it, but
that page is often the model the file was converted from rather than where the GGUF is kept, so it
is only used once you take it. A
memory tool takes its definition, never what it has remembered. What is yours alone — starred
items, pinned models, an agent's compaction and title settings — stays behind.

The file is named after what you exported and saved wherever you choose. On Android that is the
system document picker; on Linux, the save dialog.

**Publish**, beside Save, takes the reviewed bundle straight to the
[marketplace](/docs/features/marketplace#publishing) instead: it opens the publish page in your browser with
the file already filled in, and nothing is sent until you press Publish there. The bundle travels in
the address, so your browser keeps it in its history. A bundle too large for an address is offered
only Save; upload the file on the marketplace instead.

## Importing

**Settings → Import** opens a `.bylm.json` file; so does the **Import** button an empty agent or
provider list shows. Nothing is written until you press Import; first
you see a plan, one card per item, and every change you make re-plans the rest. Above the cards is
the workspace the file goes into: the active one, until you pick another. Picking one plans the
file against that workspace, keeping the answers you have already given.

Before a file is open, the page also has **Browse the marketplace**, which opens the
[marketplace](/docs/features/marketplace) in your browser: download a file there, then open it here.

A bundle can also be opened from outside the app, straight onto the same plan. On Android, open it
from a file manager or a browser's downloads, or share it to Bring Your LM. That works when the
system knows the file as a Bring Your LM bundle, as it does for one downloaded from the
marketplace; a file it records as plain JSON is still opened through Settings → Import. On Linux,
the AppImage opens `.bylm.json` files from your file manager once **Settings → Desktop entry**
has installed its entry. You can also pass the file when you start it, and with the app already
running, the file goes to the open window.

Below it, one line each says what the import writes, what it uses as it already is here, and what
it leaves out. The cards follow in the order you are most likely to read them: the agents, the
model each agent and model filter runs, the tools, the providers, the constants and the secrets.

Import stays closed while something is unanswered, and its button says how many things are left.
Each one shows on the card that asks it, and the list above the button takes you to that card.
A file that cannot be imported at all lists every reason, each after the item it is in.

- **A provider already here is reused.** One pointing at the same endpoint — the same kind, the
  same base URL — is reused, and the agents in the file bind to it. Otherwise the file's provider
  is created, with its name and base URL editable and the same third-party data-sharing consent
  the create form asks for. You can also point the item at any provider already here, or leave it
  out, and pick a provider and a model of your own for what used it.
- **Each agent and each model filter is answered on its own, under _Models_.** One card per
  place says what its model must handle — image input, tool calling, reasoning, structured
  output — and what the file ran there: a model on one of its providers, a model whose provider
  the sharer kept back, or a model's files. A model the file uses in several places is answered
  for each of them, so you can keep it for one agent and change it for another. A place on a
  provider the file carries follows that provider by default; pick any provider of yours instead.
  A place whose provider the sharer kept back, or you left out, waits for you to pick one, with
  the model it ran on preselected where your provider lists it. The first provider you pick is
  offered for the places still without one, with the same model where their needs match. An
  agent that ran on the sharer's embedded engine names its model's files, and the app looks for
  them in the models folder of each of your embedded providers. The very file is picked when it
  is there. Otherwise another quantization of the same model is picked, and the card says so. The
  card also says when the vision projector is missing, or when your folder holds nothing of the
  model, and links to the pages the sharer gave for downloading the files. Import stays closed
  until every place that will be written has a provider and a model.
- **An address that was the sharer's own is said so.** One at `localhost` meant the sharer's own
  machine; here it means yours, so a provider of yours of the same kind is used if you have one. One
  on the sharer's local network, such as `192.168.1.20`, is flagged as one that may not answer
  here. Before creating a provider that takes no key, **Test connection** asks the address you
  typed for its models — the only request the import makes to it before you press Import.
- **Each constant is answered before the secrets.** The **Constants** section lists every
  constant the file's items place. Keep the text the sharer shared, type your own, pick one you
  already saved — one of the same name is pointed out, but never picked for you, since a name says
  nothing of whose account it is — or leave it for later, which leaves the slot unlinked. Text that
  a constant cannot hold, such as an empty one or one with a line break, holds Import until you
  change it. A secret is offered by where it is sent, and a constant may name that host, so the
  **Secrets** section shows the host with your constant in place, or with its slot in braces until
  you answer it.
- **Each secret is answered once, before Import.** The **Secrets** section lists every secret the
  file names, with what uses it and where it is sent. Tap its field to pick a secret you already
  saved — the ones already sent to the same hosts come first, and one that would reach a new host
  asks first — or **Create new** to name and type one; leave the field empty to answer later. A
  new secret is saved when you press Import, as one secret every item that uses it links to, and
  leaving the import saves nothing. **Where to get it**, in the create step, opens the page the
  sharer pointed to in your browser.
- **A model is checked against the provider it lands on.** The app asks each provider a place
  runs on for its model list, again each time you point a place or a provider item at another
  provider. A model the provider lists is kept. One it does not is run on the listed model it most
  likely means — a model id that differs only by a vendor prefix, case, date or tag — or, with no
  such model, saved as it is to be tried anyway, and its card says so. You can pick any listed model
  instead.
- **Tools land in the chosen workspace's bucket** unless you switch them to global — each new tool
  on its own card, or every one at once with the switch above them. A tool whose name is already
  taken there — by the workspace's own tool or a global one — is kept by default, with the file's
  agents attaching to it. You can instead replace it (it keeps its id, its key, its
  icon, its age and its star, and takes the file's configuration), import the file's under another
  name, or skip it. A tool that sends somewhere shows the host and waits for **Accept** or
  **Decline**: declined, the tool is skipped. A replacement that keeps the host the tool already
  sends to is not asked again, and neither is a tool you keep or skip, since nothing of the file's
  is written.
- **Agents land in the chosen workspace**, bound to whatever the provider step produced. One whose
  name is already taken there is imported under another name, suggested for you and editable, unless
  you choose to replace the agent of that name.
  Each card lists what the agent will attach, and marks anything that will be missing — a tool you
  skipped or declined, a built-in tool this version of the app does not have — so nothing is
  dropped silently: the attachment stays on the agent and its page shows it as missing, and a later
  version that knows the tool picks it up without an edit. A `sub_agent-call` allowlist is rewritten
  to the agents as they land here; a target you skipped shows as unavailable.

Import runs providers, then tools, then agents, and does not stop at the first thing that fails.
The results page lists what landed, with a link to each page; what did not, with why; the
secrets still to type, each linked to the page where you enter it; and the agents and tools saved
on a model their provider does not list, each linked to its page so you can check it.

### Importing the same file again

Every imported agent, tool and provider remembers where it came from — the namespace and id it had
in the file. A second import of the same file is therefore offered as an **update** of what the
first one created, not as a name clash: the provider is updated in place and keeps its key, the tool
is replaced in place — or kept as it is when it already matches the file, so nothing is written and
no key is asked for — and the agent is updated under its own id. A namesake the file did not create
— your own agent, or one imported from a copy of the file the marketplace re-published under its own
ids — is replaced only when you choose **Replace**; by default the file's agent goes in beside it
under another name. A replaced agent remembers the file, so the next import of it is an update.

A card that updates or replaces something here lists **what the update changes**, one entry per
setting: the value it has now and the value it takes. A prompt or a template is compared line by
line, with the lines around each change. A provider is named as it is named on this device, or as
the one the import creates. A tool kept rather than replaced lists the same comparison as what
keeping leaves out of the file's tool, and an agent imported beside a namesake lists how it
differs from that agent, apart from its name. When the file matches what is here, the card says
so.

## What the file is

One JSON document, media type `application/vnd.bylm.bundle+json`. It names the format, its
version, the build that wrote it, the namespace its items belong to — the id of the device that
exported it, or for a marketplace download the publishing account — the secrets and constants its
items ask for, each by its name and hint and never by a secret's value, and three lists:
providers, tools and agents. Each item is the id it had where it
was exported, where it came from if it was itself imported, and its configuration as the app
holds it. Wherever a model runs — an agent, a model filter — the provider and the model it runs
on are one `binding`, which the file may leave out for whoever imports it to choose; the
generation settings beside it travel either way. An agent names its provider and the agents it may
call by their items' ids, and a tool by its kind and name. Its JSON Schema is published with the
website at `/schema/bundle/v1.json`.

The version is a major and a minor, `1.0` today. A later minor only adds fields; a later major
changes what they mean. Every object in the file has a declared set of fields, and a field this
version of the app does not know refuses the file, naming the field. When the file says a later
version of the format wrote it, the message says so: update the app, then import. The marketplace
reads a file the same way.

### Limits

Every text field that travels has a length limit, generous for its purpose: 80 characters for a
name, 2,000 for a welcome message, 50,000 for a system prompt. The editors count once a field is
near its limit and refuse typing or a paste that would pass it. They also name characters that
cannot be seen — zero-width spaces, direction overrides, invisible tag characters — for you to take
out. Names hold one line; prompts and programs keep their tabs. A file that breaks a limit
is refused on import, with the field and the limit.

## What it doesn't do yet

- Conversations and memory contents do not travel; only definitions do.
- Icons are not part of the file, so nothing about them is asked on import: an imported item draws
  its kind's glyph until you set one.
- Nothing verifies who wrote a file. Import what you would run.
- Whether a provider lists a model is checked when the provider's model list answers within a few
  seconds; otherwise the model is marked unchecked and lands as it is, and the agent's page shows
  the usual notice if the model turns out not to be listed. A provider the import creates has no
  list yet, so its models are not checked.

More in [Features](/docs/features): [Providers — bring your own LLM](/docs/features/providers) · [On-device models — run fully offline](/docs/features/embedded-models) · [Agents — the thing you build](/docs/features/agents) · [Tools — giving an agent more than the model knows](/docs/features/tools) · [Workspaces — keep your work in scopes](/docs/features/workspaces) · [Conversations — how a turn runs](/docs/features/conversations) · [Attachments — images and files in a message](/docs/features/attachments) · [Context management — what the model still sees](/docs/features/context-management) · [Background turns — replies that keep running](/docs/features/background-turns) · [Local-first & private by design](/docs/features/local-first) · [Sync — your data across your devices](/docs/features/sync) · [Marketplace — find and publish shared agents, tools and providers](/docs/features/marketplace) · [Running a Couchbase Edge Server](/docs/features/couchbase-edge-server) · [Spell checking — catch typos while you write](/docs/features/spell-check)

---

[Bring Your LM](/) · [Docs](/docs/features) · [Marketplace](/marketplace)

[Articles](/articles) · [Releases](/releases) · [Bundle Format](/marketplace/bundle-format) · [Marketplace Terms](/terms) · [App Privacy](/privacy) · [Website Privacy](/website-privacy) · [Open Source](/open-source) · [llms.txt](/llms.txt)
