@engramx/idl 0.16.0-rc.19 → 0.16.0-rc.20

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/dist/engram.did CHANGED
@@ -70,9 +70,13 @@ type TimersWake =
70
70
  type TimerHealth =
71
71
  record {
72
72
  alertTimerArmed: bool;
73
+ checkInsUnfinished: opt nat;
74
+ ic402Maintenance: opt Ic402Maintenance;
75
+ ic402MaintenanceTimerArmed: opt bool;
73
76
  jobExpiryArmed: bool;
74
77
  jobExpiryFastMode: bool;
75
78
  sessionExpiryArmed: bool;
79
+ upkeepRejected: opt nat;
76
80
  };
77
81
  type StorageReport =
78
82
  record {
@@ -727,6 +731,17 @@ type PurgedAgent =
727
731
  purgedAtNs: int;
728
732
  root: principal;
729
733
  };
734
+ type PaymentsStop =
735
+ variant {
736
+ dailySignatureLimit;
737
+ paymentsBrake;
738
+ signingFloor;
739
+ };
740
+ type PaymentsNow =
741
+ record {
742
+ largestPayment: opt nat;
743
+ leftToday: opt nat;
744
+ };
730
745
  type PaymentSignatureCounts =
731
746
  record {
732
747
  agents: Page_5;
@@ -1149,6 +1164,15 @@ type KeyNomination =
1149
1164
  atNs: int;
1150
1165
  key: principal;
1151
1166
  };
1167
+ type Ic402Maintenance =
1168
+ record {
1169
+ dailySpendRemoved: nat;
1170
+ lastRunAtNs: int;
1171
+ more: bool;
1172
+ rateLimitRemoved: nat;
1173
+ revokedGrantsRemoved: nat;
1174
+ runs: nat;
1175
+ };
1152
1176
  type HttpResponse =
1153
1177
  record {
1154
1178
  body: blob;
@@ -1567,6 +1591,16 @@ type Engram =
1567
1591
  ///
1568
1592
  /// A principal that is already a GUARDIAN cannot become an agent — a guardian is an
1569
1593
  /// independent check on agents, so one wallet must not hold both.
1594
+ ///
1595
+ /// ⟨2026-10-29, the owner's ruling "a"⟩ `name` MAY BE EMPTY (or only whitespace): the agent is then
1596
+ /// named after its key when it pairs — "agent-" and the key's first five characters, e.g.
1597
+ /// "agent-hsffu" (`People.nameAtPairing` says why five, and the first). ⟨2026-10-29, later, beside "its key"⟩ Its
1598
+ /// PERMANENT key (the root it enrolled with), not the key that pairs, so the name stays right across
1599
+ /// a key replacement and matches the app's "Copy permanent key". A name the owner gives
1600
+ /// always wins. Before this an empty name was refused, so an app that wanted no name had to invent
1601
+ /// one ("agent"), and two agents read alike.
1602
+ /// ⟨2026-10-29, review F7⟩ A name the owner gives meets the rule `renameAgent` applies: a line break
1603
+ /// or another control character is `#Invalid` (`People.nameRefusal`), as a rename to it would be.
1570
1604
  createAgentInvite: (name: text, permissions: AgentPermissions) ->
1571
1605
  (Result_53);
1572
1606
  /// Owner-only: mint an invite for a GUARDIAN — an independent check on agents, not a
@@ -2124,6 +2158,14 @@ type Engram =
2124
2158
  /// The pause's id sweep cancels ic402's sweeps, but ic402 keeps their stale ids, so its own
2125
2159
  /// "armed" reads would answer true for a timer that no longer exists (a fabricated answer,
2126
2160
  /// ADR-0002). `alertTimerArmed` needs no guard: the sweep nulls `alertTimerId` itself.
2161
+ /// ⟨2026-10-29, the owner's ruling "A", beside the line above⟩ …the sweep zeroes the arm, and an arm
2162
+ /// past its due time reads stale. `alertTimerArmed` is TRUE ONLY WHILE A DELIVERY IS OWED OR RETRYING
2163
+ /// (the alert drain is a one-shot armed per owed delivery); alerts configured on a quiet engram read
2164
+ /// false, and that is correct — the IDLE STEADY STATE line above now holds with a webhook set too.
2165
+ /// It reads the arm's DUE TIME, not only its id (`ActionAlerts.armLive`): a job that traps before its
2166
+ /// first await rolls back its own `alertTimerId := null`, so a bare id would read armed forever.
2167
+ /// ONE BOUNDED UNTRUTH (the spec's critic, F12): for ARM_STALE_NS (120 s) after the due time of such a
2168
+ /// trapped job, the flag reads true although no timer exists.
2127
2169
  getTimerHealth: () -> (TimerHealth) query;
2128
2170
  /// PUBLIC: a cap identifies no user, and a caller deserves to know the rule before it stops them.
2129
2171
  ///
@@ -2758,6 +2800,13 @@ type Engram =
2758
2800
  /// owner by name (`People.OWNER_HAS_NO_GRANT`), a revoked or resigned agent ("Agent is revoked" /
2759
2801
  /// "Agent has resigned" — an ended agent may do nothing, and its old grant would read as powers),
2760
2802
  /// a guardian and a stranger ("Not authorized"), the anonymous caller. A query: it writes nothing.
2803
+ ///
2804
+ /// ⟨2026-10-29, the owner's ruling "b: fix"⟩ It also says whether the payments brake is on and what
2805
+ /// the key could pay now (`paymentsFrozen`, `paymentsNow`), read from the values `x402SignFor`
2806
+ /// checks — the brake, the key's policy and stored total, the engram-wide ceiling and total — so
2807
+ /// the caps alone no longer read as money an agent can spend. `People.SpendState` names each one.
2808
+ /// ⟨2026-10-29, review F2⟩ And which whole-key refusal stops every payment now, if one does
2809
+ /// (`paymentsStoppedBy`: the brake, the signing floor, the daily count of payment signatures).
2761
2810
  myGrant: () -> (Result_26) query;
2762
2811
  /// The AGENT's current key nominates the key that will replace it. Nothing moves yet: the new
2763
2812
  /// key must accept, by its own call, within 24 hours (`acceptAgentKeyNomination`). One pending
@@ -3349,7 +3398,8 @@ type Engram =
3349
3398
  sessionReadMemory: (voucher: Voucher, path: text) -> (Result_12);
3350
3399
  /// Configure action alerts: an https webhook that receives new chained-audit entries matching the
3351
3400
  /// enabled event classes (money / approvals / guardian / agentWrites), batched, at most one
3352
- /// POST per minute. Owner-only. Payloads carry audit METADATA (operation, caller, role, bounded
3401
+ /// POST per minute. ⟨2026-10-29⟩ Delivered within seconds of the action (a 5 s batch window), and
3402
+ /// nothing runs while nothing is owed. Owner-only. Payloads carry audit METADATA (operation, caller, role, bounded
3353
3403
  /// details) — never memory file contents. Setting a URL (re)arms delivery FROM NOW: the cursor
3354
3404
  /// jumps to the current end of the log so history is not replayed. Passing url = null disables.
3355
3405
  /// The URL itself is never written to the audit log (webhook URLs often embed secret tokens).
@@ -3976,10 +4026,12 @@ type Engram =
3976
4026
  text, amount: nat, tokenName: text, tokenVersion: text, rationale:
3977
4027
  opt text, approvalId: opt text) -> (Result_4);
3978
4028
  /// Write an `alerts.test` entry into the audit log; the drain timer delivers it to the webhook
3979
- /// within ~60s. Owner-only; requires a configured URL so the test can actually go somewhere.
4029
+ /// within ~60s. ⟨2026-10-29, beside "within ~60s"⟩ Within seconds (a minute if a delivery was just
4030
+ /// made). Owner-only; requires a configured URL so the test can actually go somewhere.
3980
4031
  testActionAlert: () -> (Result_2);
3981
4032
  /// Guardian test alert — an audited guardian action (`alerts.test`, role Guardian) that every
3982
- /// armed channel (owner + guardians) receives within ~60s. Requires the caller's own channel
4033
+ /// armed channel (owner + guardians) receives within ~60s (⟨2026-10-29⟩ within seconds; a minute if
4034
+ /// a delivery was just made). Requires the caller's own channel
3983
4035
  /// to be armed so the test has somewhere to land for them.
3984
4036
  testGuardianAlert: () -> (Result_2);
3985
4037
  /// RENAMED from `init` (L2.4). This is the OWNERSHIP-TRANSFER method — the most consequential
@@ -4396,8 +4448,11 @@ type AnchorPushStatus =
4396
4448
  attemptTotal: nat;
4397
4449
  cadenceSeconds: nat;
4398
4450
  carrierArmedAtNs: int;
4451
+ checkInIntervalSeconds: opt nat;
4399
4452
  currentTotal: nat;
4400
4453
  lastError: text;
4454
+ nextAnchorAttemptAtNs: opt int;
4455
+ nextCheckInDueAtNs: opt int;
4401
4456
  okAtNs: opt int;
4402
4457
  okTotal: nat;
4403
4458
  skipCursor: nat;
@@ -4498,6 +4553,9 @@ type AgentGrant =
4498
4553
  key: principal;
4499
4554
  name: text;
4500
4555
  paymentLimits: PaymentLimits;
4556
+ paymentsFrozen: opt bool;
4557
+ paymentsNow: opt PaymentsNow;
4558
+ paymentsStoppedBy: opt PaymentsStop;
4501
4559
  permissions: AgentPermissions;
4502
4560
  };
4503
4561
  type AgentEnding =
@@ -4534,12 +4592,14 @@ type ActionAuth =
4534
4592
  };
4535
4593
  type About =
4536
4594
  record {
4595
+ activeAgentCount: opt nat;
4537
4596
  agentCount: nat;
4538
4597
  agentMemoryReads: nat;
4539
4598
  agentMemoryWrites: nat;
4540
4599
  auditLogSize: nat;
4541
4600
  backupCount: nat;
4542
4601
  encryptionEnabled: bool;
4602
+ endedAgentCount: opt nat;
4543
4603
  firstAgentWriteAtNs: opt int;
4544
4604
  firstWriteAtNs: opt int;
4545
4605
  guardianCount: nat;
@@ -10,9 +10,11 @@ export interface About {
10
10
  lastWriteAtNs: [] | [bigint];
11
11
  totalBackupSize: bigint;
12
12
  backupCount: bigint;
13
+ endedAgentCount: [] | [bigint];
13
14
  lastAgentReadAtNs: [] | [bigint];
14
15
  firstWriteAtNs: [] | [bigint];
15
16
  agentCount: bigint;
17
+ activeAgentCount: [] | [bigint];
16
18
  paidMemoryReadEnabled: boolean;
17
19
  version: string;
18
20
  timersPausedSinceDayNs: [] | [bigint];
@@ -59,6 +61,9 @@ export interface AgentGrant {
59
61
  key: Principal;
60
62
  permissions: AgentPermissions;
61
63
  name: string;
64
+ paymentsStoppedBy: [] | [PaymentsStop];
65
+ paymentsFrozen: [] | [boolean];
66
+ paymentsNow: [] | [PaymentsNow];
62
67
  paymentLimits: PaymentLimits;
63
68
  }
64
69
  export interface AgentPaymentSignatures {
@@ -140,12 +145,15 @@ export interface AnchorPushStatus {
140
145
  currentTotal: bigint;
141
146
  timerTickAtNs: [] | [bigint];
142
147
  okTotal: bigint;
148
+ checkInIntervalSeconds: [] | [bigint];
143
149
  carrierArmedAtNs: bigint;
144
150
  attemptAtNs: [] | [bigint];
145
151
  skipCursor: bigint;
146
152
  timersPauseReason: [] | [string];
147
153
  lastError: string;
154
+ nextCheckInDueAtNs: [] | [bigint];
148
155
  timersPausedAtNs: [] | [bigint];
156
+ nextAnchorAttemptAtNs: [] | [bigint];
149
157
  }
150
158
  export interface ApprovalRequest {
151
159
  id: string;
@@ -676,6 +684,16 @@ export interface Engram {
676
684
  * /
677
685
  * / A principal that is already a GUARDIAN cannot become an agent — a guardian is an
678
686
  * / independent check on agents, so one wallet must not hold both.
687
+ * /
688
+ * / ⟨2026-10-29, the owner's ruling "a"⟩ `name` MAY BE EMPTY (or only whitespace): the agent is then
689
+ * / named after its key when it pairs — "agent-" and the key's first five characters, e.g.
690
+ * / "agent-hsffu" (`People.nameAtPairing` says why five, and the first). ⟨2026-10-29, later, beside "its key"⟩ Its
691
+ * / PERMANENT key (the root it enrolled with), not the key that pairs, so the name stays right across
692
+ * / a key replacement and matches the app's "Copy permanent key". A name the owner gives
693
+ * / always wins. Before this an empty name was refused, so an app that wanted no name had to invent
694
+ * / one ("agent"), and two agents read alike.
695
+ * / ⟨2026-10-29, review F7⟩ A name the owner gives meets the rule `renameAgent` applies: a line break
696
+ * / or another control character is `#Invalid` (`People.nameRefusal`), as a rename to it would be.
679
697
  */
680
698
  createAgentInvite: ActorMethod<[string, AgentPermissions], Result_53>;
681
699
  /**
@@ -1316,6 +1334,14 @@ export interface Engram {
1316
1334
  * / The pause's id sweep cancels ic402's sweeps, but ic402 keeps their stale ids, so its own
1317
1335
  * / "armed" reads would answer true for a timer that no longer exists (a fabricated answer,
1318
1336
  * / ADR-0002). `alertTimerArmed` needs no guard: the sweep nulls `alertTimerId` itself.
1337
+ * / ⟨2026-10-29, the owner's ruling "A", beside the line above⟩ …the sweep zeroes the arm, and an arm
1338
+ * / past its due time reads stale. `alertTimerArmed` is TRUE ONLY WHILE A DELIVERY IS OWED OR RETRYING
1339
+ * / (the alert drain is a one-shot armed per owed delivery); alerts configured on a quiet engram read
1340
+ * / false, and that is correct — the IDLE STEADY STATE line above now holds with a webhook set too.
1341
+ * / It reads the arm's DUE TIME, not only its id (`ActionAlerts.armLive`): a job that traps before its
1342
+ * / first await rolls back its own `alertTimerId := null`, so a bare id would read armed forever.
1343
+ * / ONE BOUNDED UNTRUTH (the spec's critic, F12): for ARM_STALE_NS (120 s) after the due time of such a
1344
+ * / trapped job, the flag reads true although no timer exists.
1319
1345
  */
1320
1346
  getTimerHealth: ActorMethod<[], TimerHealth>;
1321
1347
  /**
@@ -2022,6 +2048,13 @@ export interface Engram {
2022
2048
  * / owner by name (`People.OWNER_HAS_NO_GRANT`), a revoked or resigned agent ("Agent is revoked" /
2023
2049
  * / "Agent has resigned" — an ended agent may do nothing, and its old grant would read as powers),
2024
2050
  * / a guardian and a stranger ("Not authorized"), the anonymous caller. A query: it writes nothing.
2051
+ * /
2052
+ * / ⟨2026-10-29, the owner's ruling "b: fix"⟩ It also says whether the payments brake is on and what
2053
+ * / the key could pay now (`paymentsFrozen`, `paymentsNow`), read from the values `x402SignFor`
2054
+ * / checks — the brake, the key's policy and stored total, the engram-wide ceiling and total — so
2055
+ * / the caps alone no longer read as money an agent can spend. `People.SpendState` names each one.
2056
+ * / ⟨2026-10-29, review F2⟩ And which whole-key refusal stops every payment now, if one does
2057
+ * / (`paymentsStoppedBy`: the brake, the signing floor, the daily count of payment signatures).
2025
2058
  */
2026
2059
  myGrant: ActorMethod<[], Result_26>;
2027
2060
  /**
@@ -2677,7 +2710,8 @@ export interface Engram {
2677
2710
  /**
2678
2711
  * / Configure action alerts: an https webhook that receives new chained-audit entries matching the
2679
2712
  * / enabled event classes (money / approvals / guardian / agentWrites), batched, at most one
2680
- * / POST per minute. Owner-only. Payloads carry audit METADATA (operation, caller, role, bounded
2713
+ * / POST per minute. ⟨2026-10-29⟩ Delivered within seconds of the action (a 5 s batch window), and
2714
+ * / nothing runs while nothing is owed. Owner-only. Payloads carry audit METADATA (operation, caller, role, bounded
2681
2715
  * / details) — never memory file contents. Setting a URL (re)arms delivery FROM NOW: the cursor
2682
2716
  * / jumps to the current end of the log so history is not replayed. Passing url = null disables.
2683
2717
  * / The URL itself is never written to the audit log (webhook URLs often embed secret tokens).
@@ -3373,12 +3407,14 @@ export interface Engram {
3373
3407
  >;
3374
3408
  /**
3375
3409
  * / Write an `alerts.test` entry into the audit log; the drain timer delivers it to the webhook
3376
- * / within ~60s. Owner-only; requires a configured URL so the test can actually go somewhere.
3410
+ * / within ~60s. ⟨2026-10-29, beside "within ~60s"⟩ Within seconds (a minute if a delivery was just
3411
+ * / made). Owner-only; requires a configured URL so the test can actually go somewhere.
3377
3412
  */
3378
3413
  testActionAlert: ActorMethod<[], Result_2>;
3379
3414
  /**
3380
3415
  * / Guardian test alert — an audited guardian action (`alerts.test`, role Guardian) that every
3381
- * / armed channel (owner + guardians) receives within ~60s. Requires the caller's own channel
3416
+ * / armed channel (owner + guardians) receives within ~60s (⟨2026-10-29⟩ within seconds; a minute if
3417
+ * / a delivery was just made). Requires the caller's own channel
3382
3418
  * / to be armed so the test has somewhere to land for them.
3383
3419
  */
3384
3420
  testGuardianAlert: ActorMethod<[], Result_2>;
@@ -3592,6 +3628,14 @@ export interface HttpResponse {
3592
3628
  upgrade: [] | [boolean];
3593
3629
  status_code: number;
3594
3630
  }
3631
+ export interface Ic402Maintenance {
3632
+ revokedGrantsRemoved: bigint;
3633
+ dailySpendRemoved: bigint;
3634
+ more: boolean;
3635
+ runs: bigint;
3636
+ rateLimitRemoved: bigint;
3637
+ lastRunAtNs: bigint;
3638
+ }
3595
3639
  export interface KeyNomination {
3596
3640
  key: Principal;
3597
3641
  atNs: bigint;
@@ -3946,6 +3990,12 @@ export interface PaymentSignatureCounts {
3946
3990
  agents: Page_5;
3947
3991
  limit: bigint;
3948
3992
  }
3993
+ export interface PaymentsNow {
3994
+ leftToday: [] | [bigint];
3995
+ largestPayment: [] | [bigint];
3996
+ }
3997
+ export type PaymentsStop =
3998
+ { paymentsBrake: null } | { dailySignatureLimit: null } | { signingFloor: null };
3949
3999
  export interface PurgedAgent {
3950
4000
  principal: Principal;
3951
4001
  pairedAtNs: bigint;
@@ -4237,8 +4287,12 @@ export interface StorageReport {
4237
4287
  export interface TimerHealth {
4238
4288
  jobExpiryFastMode: boolean;
4239
4289
  jobExpiryArmed: boolean;
4290
+ ic402Maintenance: [] | [Ic402Maintenance];
4240
4291
  alertTimerArmed: boolean;
4292
+ upkeepRejected: [] | [bigint];
4241
4293
  sessionExpiryArmed: boolean;
4294
+ ic402MaintenanceTimerArmed: [] | [boolean];
4295
+ checkInsUnfinished: [] | [bigint];
4242
4296
  }
4243
4297
  export interface TimersWake {
4244
4298
  gap: bigint;
@@ -7,9 +7,11 @@ export const idlFactory = ({ IDL }) => {
7
7
  lastWriteAtNs: IDL.Opt(IDL.Int),
8
8
  totalBackupSize: IDL.Nat,
9
9
  backupCount: IDL.Nat,
10
+ endedAgentCount: IDL.Opt(IDL.Nat),
10
11
  lastAgentReadAtNs: IDL.Opt(IDL.Int),
11
12
  firstWriteAtNs: IDL.Opt(IDL.Int),
12
13
  agentCount: IDL.Nat,
14
+ activeAgentCount: IDL.Opt(IDL.Nat),
13
15
  paidMemoryReadEnabled: IDL.Bool,
14
16
  version: IDL.Text,
15
17
  timersPausedSinceDayNs: IDL.Opt(IDL.Int),
@@ -247,12 +249,15 @@ export const idlFactory = ({ IDL }) => {
247
249
  currentTotal: IDL.Nat,
248
250
  timerTickAtNs: IDL.Opt(IDL.Int),
249
251
  okTotal: IDL.Nat,
252
+ checkInIntervalSeconds: IDL.Opt(IDL.Nat),
250
253
  carrierArmedAtNs: IDL.Int,
251
254
  attemptAtNs: IDL.Opt(IDL.Int),
252
255
  skipCursor: IDL.Nat,
253
256
  timersPauseReason: IDL.Opt(IDL.Text),
254
257
  lastError: IDL.Text,
258
+ nextCheckInDueAtNs: IDL.Opt(IDL.Int),
255
259
  timersPausedAtNs: IDL.Opt(IDL.Int),
260
+ nextAnchorAttemptAtNs: IDL.Opt(IDL.Int),
256
261
  });
257
262
  const AuditHead = IDL.Record({
258
263
  headHash: IDL.Vec(IDL.Nat8),
@@ -479,11 +484,23 @@ export const idlFactory = ({ IDL }) => {
479
484
  sessionFilesCount: IDL.Nat,
480
485
  });
481
486
  const Result_59 = IDL.Variant({ Ok: StorageReport, Err: Error });
487
+ const Ic402Maintenance = IDL.Record({
488
+ revokedGrantsRemoved: IDL.Nat,
489
+ dailySpendRemoved: IDL.Nat,
490
+ more: IDL.Bool,
491
+ runs: IDL.Nat,
492
+ rateLimitRemoved: IDL.Nat,
493
+ lastRunAtNs: IDL.Int,
494
+ });
482
495
  const TimerHealth = IDL.Record({
483
496
  jobExpiryFastMode: IDL.Bool,
484
497
  jobExpiryArmed: IDL.Bool,
498
+ ic402Maintenance: IDL.Opt(Ic402Maintenance),
485
499
  alertTimerArmed: IDL.Bool,
500
+ upkeepRejected: IDL.Opt(IDL.Nat),
486
501
  sessionExpiryArmed: IDL.Bool,
502
+ ic402MaintenanceTimerArmed: IDL.Opt(IDL.Bool),
503
+ checkInsUnfinished: IDL.Opt(IDL.Nat),
487
504
  });
488
505
  const WalletBalances = IDL.Record({
489
506
  icpE8s: IDL.Nat,
@@ -965,6 +982,15 @@ export const idlFactory = ({ IDL }) => {
965
982
  items: IDL.Vec(SignIn),
966
983
  });
967
984
  const Result_27 = IDL.Variant({ Ok: Page, Err: Error });
985
+ const PaymentsStop = IDL.Variant({
986
+ paymentsBrake: IDL.Null,
987
+ dailySignatureLimit: IDL.Null,
988
+ signingFloor: IDL.Null,
989
+ });
990
+ const PaymentsNow = IDL.Record({
991
+ leftToday: IDL.Opt(IDL.Nat),
992
+ largestPayment: IDL.Opt(IDL.Nat),
993
+ });
968
994
  const PaymentLimits = IDL.Record({
969
995
  maxSessionDeposit: IDL.Opt(IDL.Nat),
970
996
  maxPerDay: IDL.Opt(IDL.Nat),
@@ -978,6 +1004,9 @@ export const idlFactory = ({ IDL }) => {
978
1004
  key: IDL.Principal,
979
1005
  permissions: AgentPermissions,
980
1006
  name: IDL.Text,
1007
+ paymentsStoppedBy: IDL.Opt(PaymentsStop),
1008
+ paymentsFrozen: IDL.Opt(IDL.Bool),
1009
+ paymentsNow: IDL.Opt(PaymentsNow),
981
1010
  paymentLimits: PaymentLimits,
982
1011
  });
983
1012
  const Result_26 = IDL.Variant({ Ok: AgentGrant, Err: Error });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@engramx/idl",
3
- "version": "0.16.0-rc.19",
3
+ "version": "0.16.0-rc.20",
4
4
  "description": "The Candid interfaces of the EngramX canisters (engram, registry, market) — the .did files and the JS/TS IDL factories generated from them, published with every release so code that calls them pins the interface by version.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "EngramX <developer@engramx.ai>",