Skip to main content

Tools & connections

Think of a key and the machine it opens. The key on its own does nothing; the machine on its own won't start. A connection (credentials) is the key — the login that proves you're allowed into Stripe, HubSpot, your own API. A tool (tools) is the machine — one concrete action that turns the key and does something: create a contact, fetch an invoice, post an update.

That split is the whole page. Your assistant runs machines. It never holds keys.


The verbs

Two areas, and they always work in the same order: find (or set up) the connection, then build or run the tool that uses it.

tools — the action

VerbScopeWhat it does
tools.userunRuns one saved tool in Nirvai's cloud. Needs a session.
tools.<alias>runThe same run, addressed directly — every saved tool is callable by its own alias.
tools.describe_schemareadThe grammar for authoring a tool. Pure documentation, no side effects.
tools.proposecreateDrafts one or many tools onto a review page. Creates nothing.
tools.createcreateCreates the tools for real, each bound to a connection that already exists.
tools.editwriteChanges a tool you already have — its address, its parameters, or which connection it uses.

Where you finish this — the tool page

tools.propose drafts; you create. The link opens /external/tools/… inside Nirvai, where you can run the tool once to see what it returns before it exists at all.

  • Test before you commit. A tool that returns the wrong thing is easier to spot here than after an agent has been using it for a week.
  • You have to be signed in, and only you can open it. A proposal link is not shareable.
  • It can't be clicked twice — re-opening shows Created ✓, and your assistant reads the new tool back from the feed rather than proposing again.

credentials — the login

VerbScopeWhat it does
credentials.listreadEvery connection you have, each with a stable id and whether it's authorized.
credentials.searchreadThe same list, narrowed by a query.
credentials.describereadOne connection's live state — kind, label, and whether it's authorized yet.
credentials.describe_schemareadWhich fields each kind of connection needs, and which of them are secret.
credentials.proposecreateWrites a step-by-step setup guide onto a page you open and complete.
credentials.createcreateCreates a connection directly — only when you handed it the value yourself.
credentials.editwriteChanges a connection's non-secret settings, like its display name.

Listing and inspecting your tools goes through the master tools instead — nirvai_list_resources(kind="tools") for the catalogue, nirvai_describe(kind="tools", ref=…) for one tool's live parameters. Always describe before you run: the parameters your assistant may fill come from that answer, never from memory. Connections are addressed by their id, tools by their alias or id — never by display name, because names collide.

Where you finish this — the connection page

credentials.propose sends field names only, never a value. The link opens /external/credentials/… inside Nirvai, and you type the secret there, on Nirvai's own page.

  • The secret is yours alone. It never enters your assistant's context, its result, or the feed.
  • A provider login finishes in your browser. The action can come back as needs_auth with a link; you complete the provider's own sign-in, then your assistant lists your connections again to check it worked. There is no signal it can wait on.
  • You have to be signed in, and only you can open it. A proposal link is not shareable, and re-opening a completed one shows Connected ✓ rather than making a second connection.
  • Something wrong on the page? Hand back its copy-paste block and your assistant re-proposes — see the review page.

The secret rule

A secret never reaches your assistant

Your assistant cannot complete a connection. It proposes the field names — "a secret key goes here", "this one is the header name" — and hands you a link. You type the secret on Nirvai's own page. The value never enters your assistant's context, never appears in the result it gets back, and never lands in the Activity Feed. A secret value placed inside a proposal is refused outright. (The single exception is a value you deliberately hand over yourself to pass through once — a proposal never carries one.)

Connections that use a provider login can't be finished headlessly at all: the provider's own approval window has to open on your screen. Once it does, your assistant learns it worked the same way you would — by reading the list back and checking whether the connection is authorized. There is no completion signal it can wait on, so it verifies rather than polls.

When a tool runs, the key is turned on Nirvai's side: tools.use resolves and decrypts the bound connection in the cloud, runs the tool there, and returns a bounded preview. The secret does not cross back with the result.


Channels are not connections

WhatsApp, Slack and the rest are set up in Nirvai, not here

WhatsApp · Instagram · Messenger · Meta Ads · Telegram · Slack · Discord · Microsoft Teams · web chat are not connections and not tools. They're set up in the Nirvai app and then attached to an agent. credentials.propose actively refuses them and replies with where to go instead — because a connection named after one of them could never exist, and you'd only find out after approving it. If your assistant offers to "connect WhatsApp for you", it is wrong; ask it to point you at the page.


Worked examples

Set up a new connection, then use it. The whole loop, in the order it actually happens:

# 1. Look first — the connection may already be there.
nirvai_execute(alias="credentials.list", args={},
description="Check whether Stripe is already connected")

# 2. Nothing matched. Propose one — field NAMES only, no value.
nirvai_execute(alias="credentials.propose",
args={ items: [{ type: "apikey", label: "Stripe (live)", provider: "stripe",
steps: [ …a guide: where to get the key, then a field to type it into… ] }] },
session="stripe-setup",
description="Propose a Stripe connection for the user to complete")
# → a link to a review page. You open it, you type the key, you click Connect.

# 3. Verify it landed and pick up its id.
nirvai_execute(alias="credentials.list", args={},
description="Read back the new connection's id")

Run a saved tool. Once a tool exists, it is callable by its own alias:

nirvai_execute(
alias = "tools.hubspot_create_contact",
args = { body: { properties: { email: "ada@acme.com", firstname: "Ada" } } },
description = "Add Ada to the CRM after today's call",
session = "crm-cleanup"
)

Only the parameters marked fillable get sent. Fixed settings are applied in the cloud, and the login is resolved there — your assistant never passes either.


Limits & guarantees

  • Nothing is created silently. propose stages a draft and returns a review page; the real create happens when you click. Once you have, the draft is marked done and cannot be created twice.
  • No delete. There is no verb to remove a tool or a connection over this connection, at any permission level.
  • Runs are capped. tools.use is blocking and time-limited, with no background worker to finish an overrun. Long jobs belong in an automation or a skill.
  • Results are previewed, not pasted. Large results come back as a summary plus a handle your assistant can fetch — see What comes back.
  • An expired login is honest about it. Mid-run expiry returns a needs_auth status with a link to reconnect, instead of failing quietly. Your assistant should stop and hand you the link.
  • Edits are complete, not partial. Re-sending a tool's parameters replaces that whole set, so your assistant sends the full shape and re-reads the tool afterwards to confirm.

What's next