Reference / Changelog
Changelog
What changed in each release of the two packages, newest first. Read every line marked Breaking before you upgrade: it can need a change in your code or change what your agent does. Each version is a link you can share.
SDK
@vulsight/guard on npm. Set it up with the SDK page.
Upgrade to the current release with one command. Then read the Breaking lines of every release you skipped.
npm install @vulsight/ guard@0.7.00.7.0
Added
- An agent set to observe on the guard gets one
console.warnnaming the decision enforce mode would have given, with its reasons. DecisionRecordcarries the agent's dashboard name as optionalagentNameon listed decisions.
Changed
reportSettlementfinds a payment's decision through x402'sonPaymentResponsehook, whichguard()now registers. It no longer reads the signedPAYMENT-SIGNATUREheader.- Breaking Pass
reportSettlementthe responsewrapFetchWithPaymentreturned, and callguard()before you register anyonPaymentResponsehook of your own. - Breaking For a paid request sent without
wrapFetchWithPayment, pass its response toprocessPaymentResultonnew x402HTTPClient(client)beforereportSettlement. - An x402 client with no
onPaymentResponsegets a warning and cannot report a settlement. - Breaking
guard()also registers a payment policy, soHookablerequiresregisterPolicy. Anx402Clientfrom@x402/core2.24 or later has it. A structural wrapper must expose it. - Breaking A second
guard()on the same x402 client throws. Give each session its own x402 client. - Breaking
observemode lets a payment through only when the guard did not answer in time. That means it was unreachable, sent a 408 or a 5xx other than 503payment_screening_unavailable, or ran past its time budget. - A rate limit, and a page sent for checking that the guard refused, now abort the payment in both modes.
- A page whose read failed or was still arriving after 5 s now aborts the payment in both modes.
- A 402 or decision the SDK cannot read, and a held payment whose review poll failed, now abort in both modes.
- Breaking
guard()throws whensessionis not 1 to 200 characters with no NUL character. - Breaking
guard()andnew GuardClient()throw whenapiKeyis missing or blank. 0.6.0 built and failed on each call. - Breaking
X402ProposalandX402Paymentrefuse an unknown field, so a caller ofvulsight.api.decidemust drop fields the API does not take. - Breaking
X402ProposalandX402Paymentrefuse aschemethat is not lowercase letters, digits, and hyphens. Sendexactas the 402 writes it. X402ProposalandX402Paymentacceptx402Version(2 only),assetTransferMethod,paymentFlow, and the 402'sextra.- Breaking TypeScript change
RuleIdincludespayment_method_supported; handle it in exhaustive maps and switches. - When a seller offers several options, the x402 client pays with one the guard supports instead of aborting on an unsupported first one.
- When a seller offers no supported option, the payment hook refuses before signing, in both modes, and lists up to five of the options offered.
- The payment hook refuses before signing, in both modes, a 402 that is not x402 version 2.
- On Solana, the payment hook refuses before signing a transfer method other than the default.
- The payment carries the 402's declared
assetTransferMethodandpaymentFlowto the guard. X402_SUPPORTandpaymentSupport(payment)from@vulsight/guard/typesare the supported payments and their check. The API, the advisory MCP tool, and the proxy use the same.- A refusal of an unsupported payment names the payment's own network.
reportSettlementreads the olderX-PAYMENT-RESPONSEheader too, and reports each receipt once. A repeat returns the recorded settlement.reportSettlementkeeps up to 1000 receipts. It refuses a receipt two payments name, a response from the unsignedvulsight.fetch, and a payment the guard did not decide.- On a second 402, or a receipt whose
successis false,reportSettlementnames the seller's reason only for known x402 refusal codes. Anything else is an unknown outcome. - A
reportSettlementerror for a short-funded wallet says to wait until the signed payment expires: on EVM when the 402 offer's time limit passes, on Solana when its recent blockhash is no longer valid. reportSettlementreports a used or expired authorization, a failed simulation, andsettlement_pendingas possibly settled.- A possibly settled error says to check the wallet's transfers to the payee on chain before paying again, and that an allowed or approved amount still counts toward the daily cap for the UTC day the guard checked it.
- In observe mode, a payment's amount counts toward the cap only if enforce mode would have allowed it, or held it and the review timeout has not passed.
reportSettlementerrors that name the paid URL drop its query.- A payment waits only for pages from its own site, and for text sent for checking under a label that names no site. Another site's unchecked page blocks only payments to that site.
- The review wait tries again after a poll the guard did not answer or rate limited. A refused or unreadable poll aborts at once and names the held decision to check before a retry.
- A held payment prints one
console.warnwhen the wait starts. It names the decision, the Review page at<baseUrl>/review, and how long the SDK waits. - A payment still held when the wait ends says to deny the open review on the Review page first, then run the payment again. The open review counts toward today's cap until it expires.
- An expired review says to run the payment again and approve it before it expires, or to raise the Review timeout and
waitForReviewSecondswith it. - A refused or failed last review poll links the decision at
<baseUrl>/decisions/<id>. - Breaking The held payment sentences changed, so code that matched the old "Ask your user to review it in the VulSight Guard dashboard." sentence must update.
file()givenundefinedornullsends nothing for checking and answerspass.file()given any other value that is not a string sends nothing, answersunavailable, and logs a warning.- A text sent for checking that the guard refused or still rate limits aborts the next payment it concerns, in both modes.
- Breaking Every guard call refuses a base URL that redirects and names the address to set.
- Every guard call sends an
x-vulsight-clientheader with the SDK version, and a 408 counts as an outage. - An error for an answer that is not the guard's names the host and status, and an answer this SDK cannot read says to update it.
- README and
Policydocs: the daily cap is one USDC budget per key across every network and lane. - README: how long the proxy holds an EVM payment for review, and what its
review_pendingandresign_requiredanswers mean. - README: where to answer a held payment's review, and to give the HTTP client a read timeout of at least 60 seconds.
- README: the proxy's Solana receipt statuses, and the 16 MiB daily ceiling on text sent for checking.
- README: the
vs_test_prefix as only a key format, and the MCP tool as advisory, not enforced. - README: the sample reads its keys from the environment, pays the demo seller, and says how to run it.
Fixed
- When a seller answers the signed retry with a redirect, the wrapped fetch returns it unfollowed with a warning that the payment may have been made, where it used to throw. A browser hides redirects, so there it throws that warning.
- A page the guard passed is sent for checking again when it is read a minute or more later. That replaces a pass the guard no longer honors.
- A cited excerpt is cut between characters, so a page with an emoji at its 2000th unit no longer fails the decision.
- A payment still held when the wait ends mentions Approve and always allow this payee only when a first payment is the only reason for the hold.
Security
- Breaking
TxHashrefuses the all-zero hash andSolanaSignaturethe all-zero signature, the unsigned placeholders. - The payment hook refuses, before signing, terms that are not one of the 402's offers.
- The hook that runs after signing blocks, in every mode, a payment whose x402 version, offer, or resource URL changed after the check, or whose 402 was replaced so no decision matches it.
reportSettlementrefuses, as the proxy does, a receipt whose transaction is the payment's own EIP-3009 nonce, the buyer's own Solana signature, or an unsigned placeholder. The error never repeats the value.- On Base,
reportSettlementrecords the signing wallet as the payer of a receipt that names none, and refuses one naming another payer, as the proxy does. A paid 402 can be reported too. vulsight.fetchthrows on a URL under the guard's own/p/proxy path, and on a read redirected onto one, so a proxied payment is not decided twice and its proxy token stays out of decision records.
0.6.0
What changed
Added
- The wrapped fetch sends every 402 for checking, the unpaid one and one answering a signed retry, with the text the proxy sends for it: the description in its terms, then its body.
- The next payment waits for a 402's check, and cites the 402 when it was the last read from that origin.
file(text, origin)sends the text under the origin of an http(s) URL given asorigin, so text read from a seller's page is linked to that seller.
Changed
- A text is posted once per origin rather than once per hash, so identical text two sellers serve is linked to each of them.
- README: what is checked in a body, and which text sent for checking holds payments.
Fixed
- A binary body (a NUL byte in its first 8 KiB) up to 4 MiB sends the readable text inside it for checking, where it sent 64 KiB of replacement characters.
- A binary body over 4 MiB is still sent at the cap and stays unchecked, since the rest was never read.
- A payment no longer cites a page with no text, such as an empty body or an image with no readable text, which the guard read as a page it never received and held for review.
0.5.0
What changed
Added
- Breaking TypeScript change
Policyincludes requiredblocklistEnabled; addfalseto constructed values, or usePolicy.parse(input)to apply the default. - Breaking TypeScript change
RuleIdincludeswallet_blocklist; handle it in exhaustive maps and switches.
Changed
- Allow more time for pending reads, sending context for checking, one retry, and the payment decision, matching the longer content check budget.
- README: explain that completed content blocks deny payments and review results hold them when content enforcement is enabled.
Fixed
- Keep each payment attempt's quote identity separate so reused quotes cannot mix decision identifiers.
- Keep the content check's answer, a person's review clearance, and whether the check is enforced in context and decision responses.
Security
- README: treat the proxy token as a secret, keep its URL out of history, logs, and screenshots, and rotate the key if it leaks.
0.4.1
What changed
Added
observed402PayToandpayercarry descriptions.
Changed
- A page read that failed aborts the payment with the page's origin and what cut the read short.
reportSettlementnames the header, the field, and the next step when a seller's receipt cannot be recorded, in place of a raw decoder or zod error.reportSettlementrefuses a receipt whose network is not the payment's before it posts.- A decision's sentences open with the rule that denied or held the payment and end with the notes.
Fixed
- The review poll rounds the time left up to a whole second, so
waitForReviewSeconds1 polls once where 0.4.0 could abort without a poll. - A NUL byte in a page is sent as the replacement character, and a leading byte order mark is kept.
- A page the guard refused blocks one payment rather than every later one.
- The origin sent with a text is clipped to 200 characters.
0.4.0
What changed
Added
- The payment hook sends an
Idempotency-Keyper payment attempt, so a retried call is decided once. - Solana Devnet and Solana Mainnet USDC beside Base Sepolia and Base, with base58 address checks.
holdOverAtomiconPolicyand theamount_hold_overreason.decisions.listpages with abeforecursor.
Changed
- A policy list holds at most 200 payees.
Security
- Every request field carries its own sentence, and a resource URL with credentials is refused.
0.3.0
What changed
Added
- The seller URL cap is the exported
RESOURCE_URL_MAX, 2000 characters.
Changed
- Abort reasons name the cause. A 200 that is not the guard's JSON names the host, and a 402 with no resource aborts instead of throwing.
- A review still open at the wait budget keeps its rule sentences.
Security
- A NUL byte in any field is refused at the boundary.
0.2.2
What changed
Changed
- Inputs are bounded and every 422 is worded.
- README: a text at the 64 KiB cap counts as unavailable, never a pass.
Fixed
- Every page sent for checking is kept until the guard has taken it.
0.2.1
What changed
Changed
- Longer payment verification deadlines.
0.2.0
What changed
Added
allowedResourcesonPolicy: a payment for a resource outside the declared task is held.- Every tool result can be sent for checking, with a Claude Code hook.
BASE_MAINNETbesideBASE_SEPOLIA; a payment on any other network is blocked before the guard is asked.
Changed
- The default review wait is 120 seconds, the default policy's review timeout.
- The excerpt sent for checking is the API's full 2000 characters, and a flagged page read again renews the hold.
Fixed
- A rejected API key aborts with the key sentence instead of blaming the page.
0.1.2
What changed
Changed
- "Seller" for the party the agent pays, in the sentences and the README.
0.1.1
What changed
Changed
@x402/coreunpinned.- Error sentences name the host, the code, and the next step.
Fixed
- The page sent for checking is clipped to 64 KiB of UTF-8, and the payment hook stays inside its 5 s budget.
- Settlement reports are verified, deduplicated, and awaited.
0.1.0
What changed
Added
- First publish:
guard()with the x402 payment hook, the API client, and the shared types.
MCP server
@vulsight/guard-mcp on npm. Set it up with its setup page.
The MCP tool is advisory. The agent chooses whether to ask. For a check it cannot skip, use the proxy URL or the SDK hook.
0.4.0
Added
- A
file_contexttext or hook result that could not be sent for checking because the guard was out (a 408, a 429, a 5xx, or no answer) is kept. - The next
check_paymenta kept text concerns sends it first, and fails closed while the guard is still out. - The Claude Code hook keeps unsent results, at most 200 a session, in a file under the system temp directory that only the server's operating system user can read, so a restarted server still sends them.
- A reused
idempotency_keyanswers with a sentence that names the causes and asks for a new key. list_recent_decisionsnames each agent and takes abeforecursor.
Changed
check_paymentforwards an x402 payment'sx402Version, the requirement'sextra,assetTransferMethod, andpaymentFlow.check_paymentrefuses locally what the guard cannot judge: any scheme but exact, an upfront or escrow flow, and a transfer method other than EIP-3009 on Base or the default on Solana.- Breaking
check_paymentrefuses apaymentwith a field it does not take, where 0.3.0 dropped it. Pass only the listed fields, not the whole 402acceptsentry. - Breaking
check_paymentrefuses aschemethat is not lowercase letters, digits, and hyphens. Pass it as the 402 writes it. - The printed skill (
--skill,--skill codex) says the tool is advisory, not enforced. - The printed skill adds a step that lists the payment methods the guard supports.
- The printed skill says when to skip the tool for a payment sent through the proxy URL.
- The printed skill says which terms and receipts to report.
- The printed skill says the
vs_test_prefix is only a key format, not test money. - The printed skill asks for the proxy URL shown with the user's API key when it needs one. It does not pay until it has it.
- The printed skill tells the user to install the server with
--scope user. - The printed skill says a 409
resign_requiredafter a content wait means nothing was sent, and to request the URL through the proxy again and sign the fresh 402. - A flagged page sent for checking under its URL origin holds that seller in every lane, the proxy included.
check_paymentsends kept texts for checking one at a time, within its own time budget, and stops on a cancel between them.- A
check_paymentthat runs out of time fails closed, and the next one sends the rest. - A refused kept text is reported as one kept from earlier, not one sent with this payment.
- A page's kept text tells the agent to send it again with
file_contextbefore a payment through the proxy URL. check_payment's held and expired answers name the Review page at<baseUrl>/review.- A held answer says to repeat
check_paymentwith the same payment,context,seller_402, andidempotency_keywhen nothing new was read. Otherwise, or with no key, have the review denied, send any new content withfile_context, and check again. - An expired answer says to check again with a new
idempotency_keyand approve it before it expires, or to raise the Review timeout andwait_seconds. - A hold whose answer could not be read links
<baseUrl>/decisions/<id>. report_settlementand the printed skill say a receipt whosesuccessis false may still have settled.file_contextsays so too.report_settlementand the printed skill say the seller can use the signed payment until it expires: the 402 offer's time limit on EVM, the recent blockhash on Solana.report_settlementand the printed skill say to check the wallet's transfers to the payee on chain before paying again.report_settlementand the printed skill say an allowed or approved amount still counts toward the daily cap for the UTC day the guard checked it.- In observe mode, a payment's amount counts toward the cap only if enforce mode would have allowed it, or held it and the review timeout has not passed.
get_policyprints limits and thresholds in USDC instead of the asset's smallest unit.get_policysays an allowed payee skips the wallet blocklist and the guard's issuer freeze check, while the token contract still refuses a transfer to a frozen account.- A failed, rate-limited, or unreadable review poll is tried again until
wait_secondsruns out, and a wait whose every poll failed says the answer could not be read. - Breaking Guard calls refuse a missing key and a base URL that redirects; set the key and the final base URL.
- Guard calls send
x-vulsight-clientand treat a 408 as an outage. - The daily cap is one budget per key across networks, and
get_policysays so. - README: install with
--scope user, the guard's tools do not pay (the agent brings its own x402 payment tool and wallet), and how to get a lost proxy URL. - Breaking Node 20.3 or later.
Fixed
- A cancelled
check_paymentstops before it decides, and a response the guard refuses is told to thereport_settlementcall that sent it, not sent again in another client's check. - The Claude Code hook reports a missing key or a failed send for checking to the agent, and a bare unknown command prints usage and exits 1.
- An excerpt cut inside a character is sent whole, and text with nothing to read counts as a pass.
Security
report_settlementrefuses an all-zerotxHashor Solana signature, the unsigned placeholders, before it asks the guard, as the proxy does.
0.3.0
What changed
Added
check_paymenttakesseller_402, the seller's 402 answer, and sends it for checking before deciding, likecontext; the decision citescontextwhen both are given.report_settlementtakesresponse, the body of the paid answer. It sends the body for checking under the paid seller's origin, and the nextcheck_paymentwaits for it.- If
report_settlementcannot sendresponsefor checking, the settlement stays recorded, and the nextcheck_paymentsends it first, failing closed while the guard is out. - A paid
responsethe guard refuses fails one check and is then dropped, as in the SDK.
Changed
file_contextand the skill ask for a web page's origin as a URL inorigin, so a flagged page holds only payments to that seller. Any other label, such as a bare host or a tool's name, still holds every payment in the session.file_contextand the skill say to send for checking a paid answer that has no receipt to report.- The hook sends a tool result fetched from an http(s)
urlfor checking under that url's origin, and anything else under the tool's name.
Fixed
- An empty
responserecords the settlement and sends nothing for checking.
Security
- A retry that reuses
idempotency_keywith a changedseller_402is decided again instead of replaying the earlier answer.
0.2.8
What changed
Fixed
- Return 404 for malformed request paths without stopping the server.
Security
- Reject browser requests from foreign origins on the local HTTP endpoint.
0.2.7
What changed
Added
check_paymentasks forobserved402PayTo, the payee the seller's own 402 named, so a redirected payee is denied, and its schema carries the field descriptions.
Changed
- The dashboard step follows every pending review, with or without a wait.
- The denying sentence comes before the notes in every answer.
- README: a NUL is sent as the replacement character, a leading byte order mark is kept, and the stored excerpt carries the flagged passages.
Fixed
- The hook command sends a tool result as
reportContextclips it, and a review poll with under a second left still polls for one. - A NUL in a
check_paymentcontext posts as the replacement character.
0.2.6
What changed
Added
check_paymenttakes anidempotency_key, so a retried call is decided once.- Solana Devnet and Solana Mainnet USDC beside Base Sepolia and Base.
- The policy read names the hold threshold.
Fixed
- The review poll's remaining wait is clamped at zero, ending the negative timeout warning.
0.2.5
What changed
Added
--helpon the CLI, and abort reasons that name the cause.
Fixed
- A session's texts are sent for checking in one chain, and a payment waits for it to drain. So a page sent with the payment reaches the guard before it decides.
0.2.4
What changed
Fixed
- A text at the 64 KiB cap counts as unavailable, never a pass.
0.2.3
What changed
Changed
- README claims corrected before the release.
0.2.2
What changed
Changed
- Longer payment verification deadlines.
- README: any MCP client can take the server.
0.2.1
What changed
Changed
- The default review wait is 120 seconds like the SDK, and the documented Codex config carries the tool timeout.
0.2.0
What changed
Added
- A payment for a resource outside the declared task is held.
file_contextsends every tool result for checking, and a Claude Code hook does it for that client.- Base beside Base Sepolia as a policy network.
Changed
- The excerpt sent for checking is the API's full 2000 characters.
0.1.3
What changed
Changed
- "Seller" for the party the agent pays.
0.1.2
What changed
Changed
- Version bump beside sdk 0.1.1, which unpinned
@x402/core.
0.1.1
What changed
Added
--skillprints the bundled Claude Code skill,--skill codexthe Codex snippet.
0.1.0
What changed
Added
- First publish: the MCP server with
check_paymentandget_policy, and the bundled skill.