npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tribe-nest/operator

v0.7.0

Published

tribenest-operator: operator CLI for TribeNest backstage (outreach POC workspaces and code website templates)

Readme

@tribe-nest/operator

tribenest-operator is the operator CLI for TribeNest backstage. It creates, lists and deletes proof-of-concept (POC) demo workspaces for outreach, against TribeNest or Mandetara (same codebase, different hosts), and it creates the code website templates that the tribenest CLI then builds.

It only ever calls /backstage/* endpoints. The HTTP client refuses any other path before a request is made, so an operator session cannot be pointed at the tenant API.

Installing it gives nobody any access. Every command needs an operator session, and login only completes for someone who already has a backstage operator account and approves the login with Google.

npm install -g @tribe-nest/operator
tribenest-operator login --env mandetara --api-url https://api.example.com --backstage-url https://backstage.example.com
tribenest-operator poc create --from batch.json > results.json

Commands

Every command takes --env <name>. Without it, the configured default env is used, and without a default, production.

| Command | What it does | | --- | --- | | login [--env] [--api-url] [--backstage-url] | Browser approval, then saves an operator session for the env. | | logout [--env] | Ends the session on the server, then clears it locally even if that call failed. | | whoami [--env] [--json] | Prints the operator's email and permissions. | | envs | Lists configured envs. * marks the default. | | poc create --name <n> --subdomain <s> [--owner-email <e>] [--template <slug>] [--label <l>] [--vertical <edition>] | Creates one POC. --vertical legal-us makes a Mandatera POC, served under mandatera.com. Every POC takes Stripe test payments only, on a test account made by API; Stripe needs about a minute before it can charge. | | poc create ... --practice-area <name[:price[:minutes]]> [--practice-areas-file <file>] [--timezone <zone>] | One consultation per practice area, sold by the POC's intake and its /book page. See below. | | poc create ... --feature <switch> [--feature <switch>] | Also turns on profile feature switches for the POC, e.g. --feature voice_agent. Repeatable. | | poc create --from <batch.json> | Creates many POCs from a JSON array. | | poc features --list [--json] | Lists the feature switches a POC can carry, with what each does. | | poc features <subdomain> [--add <switch>] [--remove <switch>] [--json] | Shows a POC's switches, or adds and removes them. --add and --remove repeat. | | poc list [--older-than <Nd>] [--search <q>] [--json] | Lists every POC, paging through all results. | | poc setup <subdomain> [--practice-area ...] [--json] | Finishes a legal-us POC's demo setup, repeating only the steps that are not done; adds consultations for new practice areas. | | poc delete <subdomain> [--yes] | Deletes a POC. Asks for confirmation unless --yes. |

| template create | Asks for a template's name, slug, category, demo business and owner, creates it, then offers to clone it. | | template create --from <batch.json> | Creates many templates from a JSON array. | | template clone [slug] [dir] | Clones a template's site with tribenest, to build it. | | template list [--status] [--json] | Lists code templates. | | template status [slug] | Whether the site is published and the template is in the gallery. | | template check [slug] | Whether starting from the template can rewrite all its words: lists any content field the code makes unreadable, with file and line. Exit 1 when any. | | template tag [slug] --add <a,b> --remove <c> | Adds or removes a template's tags, which a business search matches ("yoga studio" finds a fitness template tagged with it). Merges with the existing tags; refuses on a backend that does not list them. | | template publish [slug] | Lists a template in the gallery. Refused until its site is published and every field reads. | | template archive [slug] | Takes a template out of the gallery. Sites made from it are not affected. | | template categories | Lists categories as a tree: groups and their subcategories. | | template category create [--parent <group>] | Adds a group, or a subcategory under one. | | template category sync --from <file> [--dry-run] | Makes the tree match a file of groups and subcategories. Creates and fixes, never deletes. |

template

A code template is a real website on a demo profile, at template-<slug> (docs/code-website-templates.md). The work is split between the two CLIs:

  • tribenest-operator owns the catalogue: the category, the demo profile, the template row and whether it is in the gallery.
  • tribenest builds the site, as it builds any website. The demo profile's owner (you, unless you name another account) has the access to clone, push and publish it.

Every template command asks for what it needs, so there are no arguments to remember. A command that acts on one template shows a numbered list of them. Any question can still be answered with its flag (--name, --slug, --category, --demo-name, --demo-subdomain, --owner-email, --description, --tags), which is how a script runs it without a terminal.

$ tribenest-operator template create
Environment: production ([email protected])
Template name: Brightline
Slug [brightline]:
Category:
  1) Coaches
  2) Home Services
  3) + New category
Enter a number (1-3): 2
Demo business name [Brightline]: Brightline Electric
Demo subdomain [brightline-demo]:
Owner email [[email protected]]:
Description (optional):
Tags, comma separated (optional): electrician, trades
Create it on production? (Y/n)
✓ Created Brightline. Site: template-brightline
Clone it now into ./brightline? (Y/n)

Categories are a two-level tree: a group ("Hospitality") and its subcategories ("Restaurants & Cafes", "Hotels & Stays"). template create asks for the group, then the subcategory inside it, and can add a new subcategory on the spot. The tree itself lives in .claude/skills/template-factory/taxonomy.json and is applied with template category sync.

The handoff. Cloning runs tribenest clone <dir> --env <env> --website template-<slug> and writes TEMPLATE.md into the checkout: what the template is, the rules that make it a template, and how it ships. From there it is ordinary tribenest work: seed the demo profile, tribenest dev, push, publish. Then template check until every content field reads (starting from the template rewrites them all for the new business, so one the code hides would keep its demo words), and template publish lists it in the gallery.

A batch file is a JSON array; demoSubdomain defaults to <slug>-demo, and every category must already exist:

[
  { "name": "Brightline", "slug": "brightline", "category": "home_services", "demoName": "Brightline Electric", "tags": ["electrician"] },
  { "name": "Ledger", "slug": "ledger", "category": "professional_services", "ownerEmail": "[email protected]" }
]

Re-running a batch is safe: a slug that already exists is reported with created: false and left alone.

poc create

A batch file is a JSON array:

[
  { "name": "Smith & Lee Law", "subdomain": "smithlee-demo", "templateSlug": "mandetara-poc", "demoLabel": "wave-1" },
  { "name": "Garcia Immigration", "subdomain": "garcia-demo", "ownerEmail": "[email protected]" },
  { "name": "Reyes Law", "subdomain": "reyes-demo", "vertical": "legal-us", "features": ["voice_agent", "telephony"] }
]

features is an optional array of profile feature switch names. A malformed list (not an array, an empty name, more than 20 names) stops the whole batch before anything is sent. A name the server does not know comes back as a 400 that lists the valid names; run poc features --list to see them first.

Each entry is validated locally first: name is required, and subdomain must be 4 to 50 characters, match ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ and end in -demo. An invalid entry is reported as failed and never sent.

Entries are created one at a time and the batch continues past failures. Creation is idempotent by subdomain on the server, so re-running a batch is safe: existing POCs come back with created: false.

If the server answers 429 (the daily POC cap), the batch stops there and every remaining entry is reported as failed with that reason. An expired session that cannot be refreshed also stops the batch.

Output. With --json (the default when --from is used; --no-json turns it off), stdout carries exactly ONE JSON array, one entry per input, in input order:

[
  { "ok": true, "profileId": "...", "subdomain": "smithlee-demo", "websiteId": "...", "websiteVersionId": "...", "url": "https://smithlee-demo...", "created": true },
  { "ok": false, "subdomain": "garcia-demo", "status": 409, "error": "..." }
]

With features, each ok entry also carries "featureSwitches": [{ "name": "voice_agent", "assigned": true, "switchEnabled": true }]. Without --json, the line ends features: voice_agent, telephony (switch off platform-wide). switchEnabled: false means the POC is enrolled but the switch is off for the whole platform, so the feature stays off until an operator turns the switch on in backstage. assigned: false means that one switch failed; the POC itself was made, and running the create again (or poc features <subdomain> --add) finishes it.

status is null for a local validation failure or a network error. Progress and logs go to stderr only, so stdout can be piped straight into another tool. The exit code is 1 if any entry failed (or a setup step failed, below), else 0.

A legal-us POC is a working demo straight away. The server sets it up in the same call and reports each step under setup: the website agent on the owner's plan, demo credits, voice_agent (no --feature needed), the Stripe test account (pending until Stripe switches payments on, about a minute), one consultation per practice area (below; without any, one "Initial consultation", 30 minutes, USD 150), the "New client intake" playbook (conflict check, then the matching consultation through Book or buy), the "Front office" agent on the website (chat and "Call us"), and a demo matter, "Demo: Smith v. Jordan", so a conflict can be shown by naming Jamie Jordan. Without --json the line ends setup: done, or setup: 6/8 done followed by one line per step that is not done and its reason.

Practice areas. Each becomes a booking product " consultation" with weekday availability in the firm's time zone, and the intake sells all of them:

tribenest-operator poc create --vertical legal-us --name "The Town Law LLC" --subdomain townlaw-demo \
  --timezone America/New_York \
  --practice-area "Criminal Defense:0" --practice-area "DUI Defense:150:30" --practice-area "Gun Charges (VUFA):200"

--practice-area "Name[:price[:minutes]]" repeats: the price is in dollars (0 is a free consultation, the default is 150) and the length in minutes (15 to 120, default 30). Or --practice-areas-file firm.json, either a list of { name, priceCents?, durationMinutes?, description? } (or plain names) or { "practiceAreas": [...], "timezone": "...", "hours": [{ "dayOfWeek": 1, "from": "09:00", "to": "18:00" }] } (0 is Sunday; default Monday to Friday, 9:00 to 17:00). 1 to 12 areas. In a --from batch, put practiceAreas, timezone and hours on each entry.

poc setup

tribenest-operator poc setup reyes-demo
tribenest-operator poc setup townlaw-demo --practice-areas-file firm.json

Runs every setup step again and makes only what is missing, so it is safe to repeat: after a step failed, or a minute after create to see Stripe's pending turn done. It takes the same practice area flags: an area not there yet gets its consultation and the intake is published again to sell it; an area left out of the list keeps its consultation (the service line names it). One line per step (done, pending, failed, skipped) with the reason when it is not done, and the consultations on the service line. Exit code 1 when a step failed. A POC that is not legal-us has no setup and says so.

poc list

--older-than 30d (or 30) only lists POCs created more than that many days ago. --json prints the full array of { profileId, name, subdomain, url, ownerEmail, createdAt, websiteVersionId, featureSwitches }.

poc features

tribenest-operator poc features --list
tribenest-operator poc features reyes-demo
tribenest-operator poc features reyes-demo --add voice_agent --add telephony --remove film_rentals

Only POCs are reachable: any other subdomain is "No POC with the subdomain". Adding a switch the POC already has, or removing one it does not, changes nothing.

poc delete

Prompts for confirmation on a terminal. In a non-interactive shell it refuses unless --yes is passed. A 404 is reported as "No POC with the subdomain".

Config

~/.tribenest-operator/config.json, written with mode 0600 because it holds session tokens (set TRIBENEST_OPERATOR_CONFIG_DIR to use another directory):

{
  "defaultEnv": "mandetara",
  "envs": {
    "mandetara": {
      "apiUrl": "https://api.example.com",
      "backstageUrl": "https://backstage.example.com",
      "token": "...",
      "refreshToken": "...",
      "operatorEmail": "[email protected]"
    }
  }
}

Env presets:

| Env | API | Backstage | | --- | --- | --- | | production | https://api.tribenest.co | https://backstage.tribenest.co | | local | http://localhost:8000 | http://localhost:5174 |

Any other env (for example mandetara) has no preset: pass --api-url and --backstage-url on its first login. Later logins reuse the saved URLs.

The login flow

Operators sign in to backstage with Google only, so the CLI never handles a password.

  1. The CLI starts an HTTP server on 127.0.0.1 on a random free port and makes a random state.
  2. It opens the browser (and prints the URL) at ${backstageUrl}/cli-auth?port=<port>&state=<state>.
  3. The operator, already signed in to backstage, approves. Backstage redirects to http://127.0.0.1:<port>/callback?code=<code>&state=<state>.
  4. The CLI checks state, shows a "you can close this tab" page, then calls POST ${apiUrl}/backstage/cli-auth/exchange with { code } and receives { token, refreshToken }. Only a one-time code ever appears in a URL.
  5. It saves the session, makes the env the default, calls GET /backstage/auth/me and prints who is logged in.

The CLI gives up after 5 minutes without a callback.

Sessions. Every request sends Authorization: Bearer <token>. On a 401 the CLI refreshes once with POST /backstage/auth/refresh { refreshToken }, saves the new { token, refreshToken }, and retries the request once. If the refresh fails, it tells you to run tribenest-operator login --env <env>.

HTTP calls

| Command | Call | | --- | --- | | login | POST /backstage/cli-auth/exchange { code } (no auth), then GET /backstage/auth/me | | logout | DELETE /backstage/auth/session | | whoami | GET /backstage/auth/me | | poc create | POST /backstage/pocs { name, subdomain, ownerEmail?, templateSlug?, demoLabel?, vertical?, featureSwitches?, practiceAreas?, timezone?, hours? } per entry | | poc list | GET /backstage/pocs?page&limit&search&olderThanDays, page by page | | poc features --list | GET /backstage/pocs/feature-switches | | poc features <subdomain> | GET /backstage/pocs/<subdomain> | | poc features <subdomain> --add/--remove | PUT /backstage/pocs/<subdomain>/feature-switches { add?, remove? } | | poc setup <subdomain> | POST /backstage/pocs/<subdomain>/setup { practiceAreas?, timezone?, hours? } | | template create | GET /backstage/templates/categories, POST /backstage/templates/categories for a new one, POST /backstage/templates/code { slug, name, categoryId, description, tags, demo: { name, subdomain, ownerEmail } } | | template list / pickers | GET /backstage/templates?kind=code&status | | template status / clone | GET /backstage/templates/:id/site | | template check | GET /backstage/templates/:id/field-check | | template tag | GET /backstage/templates (current tags), PATCH /backstage/templates/:id/metadata | | template publish | GET /backstage/templates/:id/site and /field-check, then POST /backstage/templates/:id/publish | | template archive | POST /backstage/templates/:id/archive | | poc delete | DELETE /backstage/pocs/<subdomain> | | any, on 401 | POST /backstage/auth/refresh { refreshToken } |

Development

npm run build        # tsup, single ESM bundle in dist/
npm test             # vitest, fetch is stubbed
npm run check-types