Introduction

1muse is a credential broker. Your connector declares the upstream calls it needs to make, your user grants permission to make them, and 1muse performs each call with a credential the agent never sees. What comes back to the agent is a result, not a key.

There are two roles. A human owns credentials and decides what an agent may do with them. An agent invokes named capabilities and receives results. The agent never holds blanket access to a vault, and there is no API that returns a stored credential value.

Design note. Policy is evaluated before a credential is unwrapped. A denied call never causes a secret to exist in memory, which is also why denied and held calls are free.

Install

npx @1muse/cli init        # scaffold a connector
npm install @1muse/connector   # the SDK

Node 20 or newer. The CLI never asks for an upstream credential — those arrive from your users and go straight into their vaults.

Vaults

A vault holds one end user's secrets for one connector. Each secret is sealed with a per-user data key, which is itself wrapped by a key in a cloud HSM, so a database dump alone is inert.

Bindings

A binding is a declared upstream call: a method, a path, an argument schema and the credential it needs. The agent invokes it by name. Because arguments are typed, a malformed call fails at the edge rather than reaching your upstream.

"acme.invoice.pay": {
  "call":  "POST /v2/invoices/:id/pay",
  "uses":  "acme_api_key",
  "scope": "write"
}

Grants

Nothing is reachable until a person grants it. A grant names the subject, the bindings, the limits and the expiry. Every brokered call carries a reference back to one.

const url = await broker.grantUrl({
  subject:  "user_8812",
  bindings: ["acme.invoice.list", "acme.invoice.pay"],
  expires:  "90d"
});

Revoking is the inverse, and it does not disturb your other users or require rotating the upstream secret.

await broker.revoke({ grant: "gr_9f2a" });

Policy

Policy is declared per binding in the manifest, not in your application code, so a reviewer can read one file and know what the connector may do.

KeyEffect
maxPerCallHard ceiling on a value argument, in minor units.
maxPerDayRolling 24-hour ceiling across one grant.
approvalOverAbove this, park the call and ask the human who signed the grant.
argsFrom"user" refuses arguments that originated in content the agent merely read.
allowHostsRestrict egress to named hosts.
windowTime-of-day window in which the binding may run.
argsFrom is the agent-specific one. An agent that browses can be told things by a web page. Marking a write binding argsFrom: "user" means an argument traced to browsed content is refused rather than executed.

Ledger

Every decision is written to an append-only ledger in which each entry seals the one before it, so silent edits are detectable rather than merely discouraged.

Connector SDK

The SDK reads 1muse.connector.json at start-up and gives you one typed method per binding.

import { broker } from "@1muse/connector";

const receipt = await broker.invoke({
  binding:    "acme.invoice.pay",
  onBehalfOf: grant.subject,
  args:       { invoiceId: "in_8812", amount: 24000 }
});

Call outcomes

Every call resolves to one of three outcomes. Handle all three — a hold is not an error, and treating it as one is the most common integration mistake.

switch (receipt.status) {
  case "allowed": return receipt.result;
  case "held":    return askUser(receipt.approvalUrl);
  case "denied":  return explain(receipt.reason);
}
StatusMeaningBilled
allowedThe upstream ran; result holds the response.Yes
heldOver a threshold; approvalUrl is where the human decides.No
deniedNo grant, or policy refused it; reason says which.No

Manifest reference

FieldWhat it does
connectorStable identifier. Appears in every ledger entry.
surfacesWhere it may be invoked: muse.app, muse.code, mcp.
credentialsNamed secrets the connector needs, with type and rotation interval.
bindingsThe callable capabilities. One entry per upstream call.
bindings.*.callMethod and path. Path parameters use :name.
bindings.*.usesWhich credential to unwrap. Omit for unauthenticated calls.
bindings.*.scoperead or write. Granted separately.
bindings.*.policyThe policy block described above.

MCP server

The same bindings are exposed over the Model Context Protocol, so Muse Code and other MCP clients get an identical surface with no second integration.

{
  "mcpServers": {
    "1muse": {
      "command": "npx",
      "args": ["-y", "@1muse/mcp"],
      "env": { "ONEMUSE_AGENT_KEY": "omk_your_agent_key" }
    }
  }
}

The agent key scopes the client to the grants it has been given. On its own it unwraps nothing.

Errors

CodeMeaning
no_grantNo grant covers this binding for this subject.
grant_expiredThe grant existed but has passed its expiry.
cap_exceededAn argument exceeded maxPerCall or maxPerDay.
arg_provenanceAn argument was traced to browsed content on a argsFrom: "user" binding.
schema_invalidArguments failed the binding's schema; nothing was sent upstream.
upstream_errorThe upstream returned a failure; its status is on receipt.upstream.

Rate limits

Limits apply per grant, not per connector, so one noisy user cannot exhaust another's budget.

PlanBrokered callsBurst
Free2,500 / month20 / minute
Builder50,000 / month120 / minute
Studio500,000 / month600 / minute
Enterprise5,000,000 / monthNegotiated