Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 40 additions & 2 deletions skills/tool-bridge/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: tool-bridge
description: Discover and invoke self-described tools through a Tool Bridge gateway using the shortest safe tb CLI path, and use operational feedback when it materially affects a call. Use when an agent needs to find an available organizational tool, inspect an HTBP/MCP/HTTP capability, query connected context, call a gateway tool, explore the visible tool tree, or troubleshoot abnormal tool behavior. Requires an authenticated Tool Bridge target.
description: Discover and invoke self-described tools through a Tool Bridge gateway using the shortest safe tb CLI path, and use operational feedback when it materially affects a call. Use when an agent needs to find an available organizational tool, inspect an HTBP/MCP/HTTP capability, query connected context, call a gateway tool, reach a device command that may be offline via durable mailbox delivery, explore the visible tool tree, or troubleshoot abnormal tool behavior. Requires an authenticated Tool Bridge target.
---

# Tool Bridge
Expand All @@ -16,6 +16,8 @@ Use the gateway's live descriptions as the source of truth. Never guess a path,
- Do not register providers, mount nodes, create keys, change secrets, or administer the gateway unless the user explicitly asks for that management action.
- Interpret `404` as either nonexistent or invisible. Do not probe around it to infer hidden paths.
- Do not automatically retry calls that may have side effects. Check the error's `retryable` signal and the command effect first.
- Treat a mailbox operation ending in `result_unknown`, or `expired` with `executionMayHaveOccurred: true`, as execution ambiguity: the device may have run the command. Do not re-call, re-enqueue, or retry; create a new execution only when business idempotency is independently proven and the user authorizes it.
- Delivery mode never relaxes authorization: `effect`, `confirm`, and the user's confirmation boundary apply identically to realtime, mailbox, and fallback calls.
- Never publish credentials, customer data, private payloads, or unverified speculation as feedback. Prefer voting on an existing matching entry over creating a duplicate.

## Choose the shortest safe path
Expand All @@ -36,6 +38,8 @@ If the exact full command path, arguments schema, `effect: read`, and `confirm:
tb call '<node>/<command>' --args '<json-object>' --json
```

For a known device command that must also work while the device is offline, the fast path is still a single call: add `--delivery fallback` (see the device delivery section) instead of adding discovery or a second request.

If `tb` is missing, tell the user that Node.js 22+ and `@tool-bridge/cli` are required. Ask before installing a global package. If authentication fails, ask the user to configure a profile or inject `TB_BASE_URL` and `TB_SK`; do not ask them to paste a secret into chat when a secret-input mechanism is available.

### Discovery path: unknown capability or contract
Expand All @@ -54,7 +58,7 @@ tb ls '<path>' --json
tb help '<path>' --json
```

JSON search results already carry `items[].tool.inputSchema`, `effect`, and `confirm`. If one result is unambiguous and contains enough information for a read-only call, use its exact `<items[].path>/<items[].tool.name>` pair and call it without another help request.
JSON search results already carry `items[].tool.inputSchema`, `effect`, `confirm`, and — for device commands — `delivery`. If one result is unambiguous and contains enough information for a read-only call, use its exact `<items[].path>/<items[].tool.name>` pair and call it without another help request.

Open command-level help only when a required field is missing, results are ambiguous, the command is unfamiliar or failure-prone, or the operation may mutate state:

Expand All @@ -78,6 +82,30 @@ Do not list feedback on every normal read call, and do not fetch every visible e

For any write, destructive, or `confirm: true` operation, inspect command help and apply the user's authorization boundary before calling.

### Device delivery: one call, no second enqueue

Device commands carry a `delivery` capability in live metadata: `realtime` (default when absent), `mailbox` (durable enqueue only), or `both`. Separately, each call chooses a policy with `--delivery realtime|mailbox|fallback` (default `realtime`). Do not confuse the two: metadata says what the command supports, the flag says what this call wants.

When the full path, schema, and `delivery` are known and the task must tolerate an offline device, make exactly one call:

```sh
tb call '<node>/<command>' --args '<json-object>' --delivery fallback --json
```

The gateway owns the fallback decision. For a `both` command it tries realtime first and enqueues only when it can prove the call was never dispatched; for a mailbox-only command it enqueues directly. A completed realtime result — including a business error from the device — and an outcome-unknown send never enqueue, and outcome-unknown is never retryable. Never follow a failed synchronous call with a second "enqueue" request of your own; that is the gateway's decision, not a client retry strategy.

A `200` response with `x-tb-delivery: realtime` is the command result. A `202` with `x-tb-delivery: mailbox` is an operation identity (`operationId`, state `queued`). When a call returns an operation identity, the synchronous flow is finished: report the queued operation and stop. Do not poll on a fixed interval. Only when the user's current goal actually needs the state or terminal result, read it once:

```sh
tb device op get '<device-id>' '<operation-id>' --json
```

`tb device op ls '<device-id>' --json` lists a device's operations and `tb device op cancel` requests cancellation — cancel of an already-claimed operation is cooperative and does not prove the device stopped. Claiming, renewing, and completing operations belong to the device runtime, never to the calling agent.

Offline presence does not hide a device: an offline device and its mailbox-capable commands stay discoverable, and enqueueing to them is normal.

For any write, destructive, or `confirm: true` operation, delivery mode changes nothing: inspect command help and apply the user's authorization boundary before calling.

### Recovery path: abnormal behavior

Treat errors, timeouts, schema-valid but surprising results, and upstream inconsistencies as abnormal behavior:
Expand All @@ -91,6 +119,16 @@ Keep recovery bounded: normally make at most one workaround retry. Do not claim

Feedback writes are not part of the happy path. After securing the task result, vote for a useful existing entry or submit a verified new lesson only when gateway writes are already authorized and doing so adds value. Otherwise mention a draft only when it would materially help the user.

## Store references in results

A result containing a `store://default/...` URI is an object identity, not content. Read the current owner's object with `tb store stat` / `tb store get`. Create a share only when the user explicitly asks to hand the file to an external audience:

```sh
tb store share 'store://default/<key>' --json
```

Treat the successful share output as a secret being delivered to the user: hand it over immediately and never copy it into logs, feedback, or other diagnostics. Revoke with `tb store revoke-share` when it is no longer needed. Stable `store://` URIs may be persisted; grants, share URLs, and presigned URLs may not.

## Validate and report

Check the returned data against the task, not merely the process exit code. Summarize which gateway path and tool were used, the relevant result, and any limitation or partial failure. Never include the secret key.
Expand Down
49 changes: 48 additions & 1 deletion skills/tool-bridge/references/cli-reference.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Tool Bridge CLI reference

Load this reference when target configuration or command syntax is unclear, a Context write/upload is needed, or discovery, authentication, invocation, or feedback handling fails. It is not a required preflight for a known read-only call.
Load this reference when target configuration or command syntax is unclear, a Context write/upload is needed, a durable device operation or Store object must be inspected or managed, or discovery, authentication, invocation, or feedback handling fails. It is not a required preflight for a known read-only call.

## Target configuration

Expand Down Expand Up @@ -61,6 +61,7 @@ Node-level help is an index; it lists the commands under a node. Request `<node>
- `scope`: required permission
- `effect`: typically `read`, `write`, or `destructive`
- `confirm`: whether the user must confirm before the call
- `delivery`: for device commands, the supported channels — `realtime`, `mailbox`, or `both`; absent means realtime-only
- `feedback`: high-value operational notes from prior users

Unknown optional fields are forward-compatible and should be ignored.
Expand Down Expand Up @@ -97,6 +98,52 @@ Prefer `--args-file` for long payloads. Keep sensitive temporary files outside t

Do not reuse a failed write or destructive call automatically. A timeout can leave the remote outcome unknown.

## Device delivery and durable operations

`tb call` accepts a per-call delivery policy for device-backed commands:

```sh
tb call '<node>/<command>' --args '<json-object>' --delivery fallback --json
tb call '<node>/<command>' --args '<json-object>' --delivery mailbox --ttl 3600 --idempotency-key '<key>' --json
```

- `--delivery` is `realtime` (default), `mailbox` (enqueue a durable operation), or `fallback` (gateway decides).
- `--ttl <seconds>` bounds how long a queued operation stays deliverable; `--idempotency-key <key>` makes a retried enqueue reuse the same operation. Both require `--delivery mailbox` or `fallback`.
- The command's metadata `delivery` (`realtime`/`mailbox`/`both`, absent = realtime-only) limits which policies can succeed; the flag never expands a command's capability.

`fallback` semantics are owned by the gateway: for a `both` command it attempts realtime and enqueues only when the gateway can prove the call was never dispatched to the device. A completed realtime call — success or business error — never enqueues. An outcome-unknown send never enqueues either and returns `retryable: false`; do not send a manual follow-up enqueue.

A `200` response carries the command result with header `x-tb-delivery: realtime`. A `202` carries the operation detail with `x-tb-delivery: mailbox`; in `--json` mode the CLI prints that operation object, in human mode it prints `queued <operationId> (queued)`.

Inspect and manage operations with the `tb device` commands, scoped to the caller's visibility:

```sh
tb device ls --json
tb device op ls '<device-id>' --state queued --json
tb device op get '<device-id>' '<operation-id>' --json
tb device op cancel '<device-id>' '<operation-id>' --json
```

Operation states: `queued`, `claimed`, then a terminal `succeeded`, `rejected`, `failed`, `result_unknown`, `cancelled`, or `expired`. Interpretation rules:

- Cancelling a `queued` operation terminates it before execution; cancelling a `claimed` one only records the request — the device stops cooperatively, and side effects are not proven stopped.
- `result_unknown`, and `expired` with `executionMayHaveOccurred: true`, mean the device may have executed the command without a recoverable result. Never re-enqueue or re-call on that basis alone.
- Claiming, renewing, and completing operations are the device runtime's protocol. A calling agent reads state with `op get` at most when the current task needs it; there is no fixed polling loop in the default flow.

## Store objects

Deployment-level objects live in the default Store and appear in results as stable `store://default/...` URIs. Owner-scoped commands:

```sh
tb store list --json
tb store stat 'store://default/<key>' --json
tb store get 'store://default/<key>' --out '<local-file>'
tb store upload '<local-file>' --json
tb store rm 'store://default/<key>' --json
```

`tb store share 'store://default/<key>' --json` creates a short-lived revocable bearer link for an external audience; `tb store revoke-share '<share-id>'` revokes it. The share output is a secret: deliver it to the user and keep it out of logs, feedback, and generated artifacts. Persist only the `store://` URI itself.

## Context writes and uploads

Use `tb ctx put` for text or JSON that can be sent inline, from a UTF-8 file, or through stdin. It creates or replaces an entry and supports metadata and optimistic concurrency:
Expand Down
Loading