Developers

fabplane CLI

fabplane-cli is the open-source command line, MCP server and TypeScript client for the fabPlane API. Use it to keep shopping carts and team inventory in sync from a terminal, a CI job or an AI coding agent.

Install

npm i -g fabplane-cli
fabplane --help

Node.js 20 or newer. npx fabplane-cli … works without a global install. Source: github.com/fabPlane/fabplane-cli (from a clone: npm ci && npm pack && npm i -g ./fabplane-cli-*.tgz).

Sign in

fabplane login

The CLI prints a code and opens the approval page; approve it while signed in to fabPlane. The token is saved to ~/.config/fabplane/credentials.json ($XDG_CONFIG_HOME/fabplane when set, %APPDATA%\fabplane on Windows) with mode 0600.

For CI and servers, create a personal API token in the dashboard and use environment variables instead:

VariableMeaning
FABPLANE_TOKENAn fpk_… API token (or fpd_… device token)
FABPLANE_API_ORIGINAPI server, default https://api.fabplane.com
FABPLANE_ORGDefault organization id for commands and MCP tools

Commands

Every command takes --json, --org <id|slug> and --origin <url>; run fabplane help <command> for the rest. The organization comes from --org, then FABPLANE_ORG, then fabplane orgs use, then your personal org.

CommandWhat it does
fabplane login [--token fpk_…] [--origin URL] [--no-browser]Sign in with a device code, or save an API token.
fabplane logout · whoami · dashboard [--open]Forget the token, show the account, print or open the web dashboard URL.
fabplane orgs list | create <name> [--slug] | use <id|slug>List, create and pick the default organization.
fabplane orgs members | role <userId> <role>Members and role changes.
fabplane orgs invite [--email] [--role member|admin] [--days] | invites | accept <token|url>Invite links (no email is sent).
fabplane orgs joinable | join <id>Join an org through your verified email domain.
fabplane tokens list | create <name> [--days] | revoke <id>Personal API tokens.
fabplane destinations list | add --name --url [--kind] [--base builtin:digikey]Purchase destinations, e.g. a regional distributor.
fabplane carts list [--repo URL] [--project ID] | show <id> | delete <id>Carts, with items grouped by destination.
fabplane carts create <name> [--repo …] [--project] [--notes] [--fab builtin:jlcpcb]New cart; the fab house gets every line unless moved.
fabplane carts add <cartId> --mpn --qty [--dest] [--refs R1,R2] [--sku] [--price --currency] [--kind]Add a line.
fabplane carts import <cartId> <file.json|.jsonl|.csv|-> [--replace] [--source]Add lines from a BOM, or replace them all with --replace.
fabplane carts export <cartId> [--dest ID] [-o file.csv]CSV export, optionally one destination.
fabplane inventory list [--q] [--category] [--location] [--tag] [--limit] [--all]Search stock.
fabplane inventory add --name … [--mpn --qty --location …] [--tag …] [--attr k=v …] [--image path …]Add an item with photos.
fabplane inventory import <file.jsonl> [--source] · adjust <id> <delta> [--reason] · show · deleteBulk upsert by externalId, atomic stock changes.
fabplane inventory photos queue [--all] · claim [--limit N] [--lease SECONDS] [--worker NAME]Photo queue: items still missing a product photo, and leasing them.
fabplane inventory photos attach <itemId> (--url IMAGE_URL | --file PATH) [--source-url PAGE_URL] [--source web]Upload a found photo (URLs are downloaded on your machine).
fabplane inventory photos skip <itemId> [--note] · retry <itemId> · requeue <itemId>Release an item, or put a skipped one back (admin).
fabplane bot connect --name NAME [--org SLUG] [--agent openclaw|hermes|…] [--no-browser]Connect this machine's agent as a bot: prints a link and code, waits for an admin to approve, stores the bot token.
fabplane bots list | create <name> [--role] [--agent] | rotate <botId> | remove <botId>Manage the org's bots (admin).
fabplane mcp [--desktop]Stdio MCP server; --desktop adds tools for the local fabdesk app.
fabplane desktop status | projects | tools | call <tool> [json]Talk to the fabdesk desktop app on this machine.
fabplane api <METHOD> <path> [json|-]Raw API call, as an escape hatch.

MCP server for Claude Code and Codex

fabplane mcp speaks MCP over stdio and uses the same credentials as the CLI. It exposes these tools: org_list, destination_list, cart_list, cart_get, cart_create, cart_add_items, cart_update_item, cart_remove_item, inventory_search, inventory_add, inventory_adjust, inventory_photo_queue, inventory_photo_claim, inventory_photo_attach, inventory_photo_release.

Claude Code

claude mcp add fabplane -- fabplane mcp
# without a global install, or with a token for a headless machine:
claude mcp add fabplane -e FABPLANE_TOKEN=fpk_… -- npx -y fabplane-cli mcp

Codex

Add to ~/.codex/config.toml:

[mcp_servers.fabplane]
command = "npx"
args = ["-y", "fabplane-cli", "mcp"]
# env = { FABPLANE_TOKEN = "fpk_…", FABPLANE_ORG = "my-team" }

Other MCP clients

{
  "mcpServers": {
    "fabplane": { "command": "fabplane", "args": ["mcp"] }
  }
}

Bots for agents

Give an agent (openclaw, Hermes, a CI job) its own identity instead of your login. On the agent's machine:

npm i -g fabplane-cli
fabplane bot connect --name "openclaw on bench-pc" --agent openclaw

The CLI prints a link and a code. Open the link while signed in, pick the organization and role, and approve; the CLI then stores the bot token (fpb_…) with that org as its default. fabplane whoami shows kind: bot. A bot can work on carts, inventory and the photo queue of its own org only; it cannot create orgs, invite people, make API tokens or manage other bots. For headless machines an admin can instead run fabplane bots create <name> (or use the dashboard's Bots section) and set the printed token as FABPLANE_TOKEN. Ready-made skills live in the fabplane-cli repository under integrations/openclaw/ and integrations/hermes/.

Library

Every API operation is a method on FabplaneClient, named after its operationId. Errors throw FabplaneApiError with status and code.

import { FabplaneClient } from "fabplane-cli";

const client = new FabplaneClient({ token: process.env.FABPLANE_TOKEN });
const { orgs } = await client.listOrgs();
const org = orgs[0].id;

const { cart } = await client.createCart(org, { name: "Rev B", repos: ["https://github.com/acme/board"] });
await client.replaceCartItems(org, cart.id, [
  { kind: "pcb", description: "Main board", quantity: 5 },
  { mpn: "LM1117-3.3", quantity: 5, destinationId: "builtin:digikey" },
], "my-script");

await client.createInventoryItem(org, { name: "ESP32-S3 module", quantity: 12, location: "drawer A3" });

The package also exports fabplaneTools (the MCP tool definitions, for embedding in your own agent), dashboardUrlFor(apiOrigin) and FabdeskClient for talking to a local fabdesk desktop daemon.

Staying in sync with the API

The server publishes an OpenAPI 3.1 document at /v1/public/openapi.json, generated from its request schemas. The fabplane-cli repository's Sync API spec workflow runs every Monday at 03:00 UTC: it saves the document to spec/openapi.json, regenerates the operation list and opens or updates a chore/api-sync pull request naming any operationId that still lacks a FabplaneClient method.

Local AI, not server AI

fabPlane does not run AI on your photos or files yet: a request with serverAiProcessing: true gets 501 server_ai_unavailable. Let the agent on your machine (Claude Code or Codex through fabplane mcp, or fabdesk) read the part photo or BOM, then call inventory_add or cart_add_items with the fields it extracted.