@metamynd/agentsafe-guard 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@ re-implement the gate:
25
25
  ([markdown](https://metamynd.ai/specs/magp-v1.0.md))
26
26
 
27
27
  It defines agent identity, the canonical signed message (§8.3), the sixteen-stage order of
28
- checks (§8.5), all 59 reason codes (Appendix A), delegation narrowing (§5.4), and evidence
28
+ checks (§8.5), all 62 reason codes (Appendix A), delegation narrowing (§5.4), and evidence
29
29
  you can verify offline without MetaMynd (§13.4). If you are writing a client in a language
30
30
  other than JavaScript, read §8.3.3–8.3.5 first: key encoding, number stringification and
31
31
  signed-vs-sent field identity each surface only as `SIGNATURE_INVALID`.
@@ -78,6 +78,12 @@ you state *our agents must carry a merchant allow-list* and find out when one do
78
78
  `--json` for machine-readable output. Evaluation is local and pure: no holds are minted, no
79
79
  nonces spent, no budget consumed, and a run costs one GET.
80
80
 
81
+ **0.6.0 — `amount-unknown`.** The same discipline applied to the amount itself: a spend cap
82
+ is only as good as the number it's checked against, and a signed-transaction or nested x402
83
+ payload can carry its amount somewhere a naive check never looks. `amount-unknown` is a
84
+ deny-by-default atom for exactly that case — an action whose value the gate can't determine
85
+ is blocked, not silently waved through an untested cap.
86
+
81
87
  ```yaml
82
88
  # .github/workflows/governance.yml
83
89
  name: Governance
@@ -98,6 +104,36 @@ jobs:
98
104
  set `AGENT_KEY` in the environment — `AGENT_KEY`, `AGENT_DID` and `METAMYND_API` all
99
105
  override the file when present.
100
106
 
107
+ ### As a packaged Action
108
+
109
+ Same check, packaged so you don't hand-roll the workflow above — and it writes a
110
+ pass/fail table straight into the PR's checks summary instead of a log a reviewer has to
111
+ open:
112
+
113
+ ```yaml
114
+ # .github/workflows/governance.yml
115
+ name: Governance
116
+ on: [push, pull_request]
117
+
118
+ jobs:
119
+ mandate:
120
+ runs-on: ubuntu-latest
121
+ steps:
122
+ - uses: actions/checkout@v5
123
+ - uses: Metamynd/agentsafe-guard/packages/agentsafe-guard@v0.6.1
124
+ with:
125
+ config: ./agent.metamynd.json
126
+ require: merchants,perTxn
127
+ env:
128
+ AGENT_KEY: ${{ secrets.AGENT_KEY }}
129
+ ```
130
+
131
+ Pinned to a released tag, the same way you'd pin any third-party action — not `@main`,
132
+ which moves under you every time this repository resyncs. Inputs: `config` (default
133
+ `./agent.metamynd.json`), `require`, `version` (the `@metamynd/agentsafe-guard` npm range
134
+ to run, default `latest`), `working-directory`. Output: `ok` (`"true"`/`"false"`), if a
135
+ later step needs to branch on the result.
136
+
101
137
  ## Install
102
138
 
103
139
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamynd/agentsafe-guard",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "Zero-dependency runtime governance for any Node AI agent \u2014 gate tool calls through MetaMynd/AgentSafe (allow / block / escalate) against the agent's mandate, enforced Standards, and SOPs. Ed25519-signed, deterministic, fail-closed.",
5
5
  "type": "module",
6
6
  "main": "./agentsafe-guard.mjs",
package/policy-core.mjs CHANGED
@@ -11,6 +11,14 @@ var ATOM_REGISTRY = {
11
11
  return have !== void 0 && need !== void 0 && have >= need;
12
12
  },
13
13
  "amount-over": (c, cfg) => typeof c.amount === "number" && c.amount > Number(cfg?.limit ?? 0),
14
+ // Deny-by-default primitive for value-moving actions. Fires on ABSENCE (like the
15
+ // evidence atoms below, and unlike `amount-over`): true when the context carries no
16
+ // usable amount — the gate cannot tell how much value the call would move, so a
17
+ // spend cap authored next to it would silently never fire. Author it with BLOCK as
18
+ // the FIRST rule of a spend policy; the cap that follows then only ever judges a
19
+ // known number. Opt-in: only a rule that keys it runs it, so actions that carry no
20
+ // amount by nature are unaffected.
21
+ "amount-unknown": (c) => !(typeof c.amount === "number" && Number.isFinite(c.amount)),
14
22
  // Total budget: cumulativeSpend is a SERVER-derived, signed-last context field (never
15
23
  // shadowable by the agent's itinerary), so this compares already-spent + this amount.
16
24
  "cumulative-over": (c, cfg) => Number(c.cumulativeSpend ?? 0) + Number(c.amount ?? 0) > Number(cfg?.limit ?? 0),
@@ -58,8 +66,9 @@ ${c.output ?? ""}`.toLowerCase();
58
66
  };
59
67
  function notInAllowList(value, allowList) {
60
68
  const v = value != null ? String(value).toLowerCase().trim() : "";
69
+ if (v === "") return false;
61
70
  const allowed = (Array.isArray(allowList) ? allowList : []).map((x) => String(x).toLowerCase().trim());
62
- return v !== "" && allowed.length > 0 && !allowed.includes(v);
71
+ return !allowed.includes(v);
63
72
  }
64
73
 
65
74
  // src/policy-core/atom-catalog.ts
@@ -71,6 +80,13 @@ var ATOM_SPECS = [
71
80
  config: [{ key: "limit", type: "number", required: true, description: "Maximum allowed amount for one transaction" }],
72
81
  requiredContext: ["amount"]
73
82
  },
83
+ {
84
+ predicate: "amount-unknown",
85
+ label: "Amount not determinable",
86
+ description: "Fires when the action carries no usable amount \u2014 the gate cannot tell how much value it would move. A deny-by-default control for value-moving actions: author it with BLOCK ahead of a spend cap, otherwise an action whose amount is missing or unparseable passes the cap untested. Fires on ABSENCE, so only attach it to actions that must always carry an amount.",
87
+ config: [],
88
+ requiredContext: ["amount"]
89
+ },
74
90
  {
75
91
  predicate: "cumulative-over",
76
92
  label: "Total budget over limit",
@@ -191,7 +207,7 @@ function requiredContextFor(predicates) {
191
207
  }
192
208
 
193
209
  // src/policy-core/standards-rules.ts
194
- var PRECEDENCE = { allow: 0, observe: 1, escalate: 2, block: 3, suspend: 4, quarantine: 5 };
210
+ var PRECEDENCE = { allow: 0, observe: 1, escalate: 2, block: 3, suspend: 4, quarantine: 5, decommission: 6 };
195
211
  function atomFires(atom, ctx) {
196
212
  const pred = ATOM_REGISTRY[atom.predicate];
197
213
  if (!pred) return false;
@@ -399,7 +415,7 @@ function sumEventField(events, type, field) {
399
415
  }
400
416
 
401
417
  // src/policy-core/evaluate.ts
402
- var PRECEDENCE2 = { allow: 0, observe: 1, escalate: 2, block: 3, suspend: 4, quarantine: 5 };
418
+ var PRECEDENCE2 = { allow: 0, observe: 1, escalate: 2, block: 3, suspend: 4, quarantine: 5, decommission: 6 };
403
419
  function evaluate(input) {
404
420
  let decision = "allow";
405
421
  let reasonCode = "AUTHORIZED";