
Security News
Ruby's Bundler 4.0.18 Extends Cooldown to bundle lock and bundle cache
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.
@moneolabs/wallet
Advanced tools
An account per AI agent, with keys the model never sees.
npm install @moneolabs/wallet
Agents leak. They paste their context into logs, into tools, into other models. So this package is built on the assumption that anything the agent can read is already public: the wallet holds a handle to a signer, and the signing happens somewhere the agent cannot reach.
import { createWallet, localSigner, memoryRail } from "@moneolabs/wallet";
const wallet = await createWallet({
agent: "research-agent-01",
signer: localSigner(),
rail: memoryRail(),
asset: "USD",
funding: "$500",
});
wallet.address; // "0x4a91...c7d2", safe to log and to share
await wallet.balance(); // $500.00
await wallet.pay({ to: "x402:api.pricefeed.dev/quote", amount: "$0.04" });
await wallet.sweep({ to: "treasury", leave: "$50" });
There is no field anywhere on the wallet that returns key material.
A wallet with no limits is a liability. Pass a guard and every payment is checked before it is signed.
import { createGuard } from "@moneolabs/guard";
const guard = createGuard({
perTransaction: { max: "$25" },
rolling24h: { max: "$100" },
counterparties: "allowlist-only",
allow: ["x402:*"],
});
const wallet = await createWallet({ agent: "a", signer, rail, guard, funding: "$500" });
await wallet.pay({ to: "0xstranger", amount: "$5" });
// throws PolicyDeniedError: counterparty 0xstranger is not on the allowlist
Ask first without paying:
const decision = await wallet.preflight({ to: "vendor:acme", amount: "$400" });
decision?.verdict; // "block"
decision?.reason; // "$400.00 exceeds the $25.00 per-transaction limit"
balance() is what the rail holds. available() subtracts anything the guard has reserved but not
yet settled, which is usually the number you want before promising to spend.
Signer is an interface. Two implementations ship:
localSigner(); // real Ed25519, key stays in this process
localSigner({ seed }); // deterministic, for tests
remoteSigner({ address, sign }); // an enclave, an MPC quorum, your own KMS
remoteSigner sends a digest out and gets a signature back. Nothing about the key crosses into
your process, so there is nothing in it worth stealing.
const signer = remoteSigner({
address: "0x4a91...c7d2",
custody: "tee",
async sign(digest) {
const res = await fetch("https://enclave.internal/sign", {
method: "POST",
body: JSON.stringify({ digest }),
});
return res.json(); // { value, algorithm }
},
});
Rail is where value actually moves: a chain, a card processor, an internal ledger. memoryRail
is a complete double-entry ledger that happens to live in memory. Balances go down on the sender
and up on the receiver, overdrafts are refused, and every transfer gets a reference.
const rail = memoryRail({
fee: (amount) => scaleMoney(amount, 0.001), // 10 basis points
balances: { treasury: { USD: money("10000", "USD") } },
});
Implement transfer, balance, and optionally credit to connect a real one. Everything above the
interface stays the same.
Tool definitions in the shapes model APIs expect, with handlers wired to the wallet.
import { toolkit } from "@moneolabs/wallet";
const tools = toolkit(wallet, { guard });
tools.anthropic; // [{ name, description, input_schema }]
tools.openai; // [{ type: "function", function: { ... } }]
await tools.handle("pay", { to: "x402:api.dev", amount: "$0.04" });
Five tools: get_balance, preflight_payment, pay, get_spending_limits, list_payments.
Restrict them with include.
The important detail is what a refusal looks like:
{
"ok": false,
"refused": true,
"reason": "$900.00 exceeds the $25.00 per-transaction limit",
"rule": "perTransaction",
"hint": "This limit is set by the wallet owner. Ask them to raise it rather than retrying."
}
A result, not an exception. A model that receives a stack trace retries until the loop gives up. A model that receives this stops and tells the user.
If the rail refuses or the signer fails, the guard reservation is released rather than left stuck. Budgets do not leak from failed payments.
await wallet.pay({ to: "v", amount: "$50" }); // rail throws InsufficientFundsError
(await guard.usage()).budgets[0].used; // $0.00
MIT
FAQs
An account per AI agent, with keys the model never sees.
The npm package @moneolabs/wallet receives a total of 171 weekly downloads. As such, @moneolabs/wallet popularity was classified as not popular.
We found that @moneolabs/wallet demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.