Documentation

Guides and reference for OutLayer verifiable compute and agent custody.

Docs navigation

Agent Connect

Leased agent accounts — an account a partner provisions, funds and lends to an agent under an on-chain spend grant.

Status. Agent Connect is the House of Stake lease programme. The lane is implemented end to end — binding, decoding, grant enforcement and refusal classes — and its rules are derived from the published hos-wallet contract source. It has been exercised on testnet against a partner-provisioned account under a real grant, with the account's own on-chain spend meters moving. Mainnet is not open yet. For the calls, arguments and refusal classes, see the Binding API reference. If you want an agent to act as an account you own, you want Personal Account Binding instead — that mode is live.

What a lease is#

The account is not yours and never was. A partner provisions it, installs the wallet contract, and issues a spend grant on chain before the agent is bound to it. Nobody signs a setup transaction, which is why the setup-kit endpoint answers 400 for this mode — asking for one means the two modes have been confused.

Binding it is the same call as any other, with the two fields a lease requires:

PUT /wallet/v1/binding
{
  "asset_account_id": "agent.tla",
  "kind": "hos_lease",
  "owner_account_id": "partner.near",
  "impl_version": 6
}

The agent's executor — its own implicit account — is what the partner grants to, so that is the identifier they need from you before any of this works.

Two modes, and they are not interchangeable#

Which one applies is decided by who owns the account, not by preference.

personal_accounthos_lease
Whose accountThe user's own alice.nearA leased, keyless agent account
Who installs the contractThe user, with one transaction the agent hands themThe partner, before the agent ever sees it
impl_version in PUTRejected — versioned by the account's code hashRequired
owner_account_id in PUTOptional; if sent, must equal the asset accountRequired
Spending limitsThe owner's policy onlyThe owner's policy and an on-chain spend grant
Setup kit endpointYesNo — answers 400

The grant is a second ceiling#

Two limits apply at once and the stricter wins: the owner's policy, and the on-chain grant. A call the policy would allow is still refused if the grant does not cover it. The grant carries a native cap, per-token budgets in that token's own units, an NFT fence by token id, an expiry, and a reserve_yocto floor the account's balance may not fall through.

Three details decide more arguments than the rest of the page put together:

  • Re-granting carries the spent total over. Raising a cap does not hand back what was already spent against it — only revoking and issuing a fresh grant resets the counter.
  • The 1 yoctoNEAR marker on a token call is not spend. It is protocol overhead and stays out of the native budget — but it does count against the reserve floor, which is measured over every promise in the request.
  • Ownership rotation ends the binding. The contract tracks a rotation sequence; when the account changes hands the grants are cleared and the binding terminates rather than silently following the new owner. The sequence is numbered within an implementation epoch: a migration that moves the epoch renumbers it, and under the same owner the binding re-establishes its pin instead of ending. A different owner ends it in any epoch — a name sold during an upgrade does not keep its binding.

The policy half has a shape requirement of its own that the grant does not: a policy governing this lane must permit call, list the bound account in its address rules, and allow native — because the lane IS a call, it goes through that account, and a call is denominated in NEAR whatever token moves inside it. It is written out under Bind Your Own Account and applies identically here.

Methods are default-deny by name: only transfer, ft_transfer and nft_transfer are grantable, and a token call's arguments are parsed strictly — memo is the only extra field the contract tolerates.

A lease accepts a narrower request#

Under a lease a call must stand alone in its promise, carry exactly 1 yoctoNEAR, set no refund_to, and name no approval_id. These are not style rules — each closes a way of smuggling a second effect into a call the grant was checked against.

A promise carrying only transfers is fine and may carry several. The stand-alone rule applies to a promise that contains a call: there, the call is all it may contain.

Refusals name which rule failed first#

Every refusal carries a class, and the shape violations carry a subcode as class:subcode. The order is the contract's own: a missing or expired grant is decided before any promise is looked at.

ClassMeans
grant_missingNo grant for this executor at all
grant_expiredThere was one; its expiry has passed
grant_unreadableThe grant could not be read — refused, never assumed
grant_exhaustedThe native cap is spent
receiver_not_grantedMoney aimed at an account the grant does not name
token_not_grantedA token contract the grant does not cover
token_budget_exceededCovered token, over its budget
collection_not_grantedThe whole NFT collection is outside the grant
item_not_grantedCollection granted, this token id outside the fence
insufficient_vs_reserveThe request would take the balance below the reserve
grant_shape_violationThe request form is wrong; the subcode says which rule

The distinction between the two NFT classes is the one worth keeping: telling an owner to add a token id when the entire collection is missing is advice that cannot work.

Running under the leased name#

Identical to a personal binding: the agent asks per call with use_bound_identity, on both the HTTPS and the on-chain door, and billing stays with the agent's own key. See Running under the bound name.

Ending it is the partner's side: revoking the grant or letting the lease expire stops the lane within five seconds — an allow we checked a moment ago is cached for that long and a denial is never cached, so five seconds is the bound rather than the usual case. A lifecycle webhook from the partner collapses it to the next call. DELETE /wallet/v1/binding ends OutLayer's side and cancels approvals still waiting on that account.