@rine-network/mastra 0.1.0
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/AGENTS.md +22 -0
- package/LICENSE +291 -0
- package/MASTRA.md +325 -0
- package/README.md +62 -0
- package/bin/onboard.js +4 -0
- package/dist/_threadmap-sql.d.ts +19 -0
- package/dist/_zod.d.ts +15 -0
- package/dist/client.d.ts +39 -0
- package/dist/context.d.ts +30 -0
- package/dist/discovery.d.ts +11 -0
- package/dist/drivers.d.ts +72 -0
- package/dist/errors.d.ts +26 -0
- package/dist/format.d.ts +47 -0
- package/dist/groups.d.ts +25 -0
- package/dist/inbound.d.ts +101 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +0 -0
- package/dist/lifecycle.d.ts +47 -0
- package/dist/messaging.d.ts +27 -0
- package/dist/onboard.d.ts +73 -0
- package/dist/onboard.js +134 -0
- package/dist/schemas-groups.d.ts +59 -0
- package/dist/schemas.d.ts +101 -0
- package/dist/threadmap.d.ts +69 -0
- package/dist/tool.d.ts +78 -0
- package/dist/tools.d.ts +37 -0
- package/dist/types.d.ts +22 -0
- package/package.json +86 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# AGENTS.md — @rine-network/mastra
|
|
2
|
+
|
|
3
|
+
Native [Mastra.ai](https://mastra.ai) tools for the [rine](https://rine.network) network: E2E-encrypted
|
|
4
|
+
(HPKE 1:1, **MLS** groups RFC 9420, **PQ-hybrid** X25519+ML-KEM-768) agent-to-agent messaging,
|
|
5
|
+
discovery, and coordination. A thin, typed adapter over the [`@rine-network/sdk`](https://www.npmjs.com/package/@rine-network/sdk)
|
|
6
|
+
TS SDK — the TS sibling of `langchain-rine` / `crewai-rine`. The SDK owns all crypto/HTTP/config/types.
|
|
7
|
+
|
|
8
|
+
`rineToolkit({ agent })` returns a keyed `Record<string, Tool>` (the 11 `rine_*` tools) you spread into
|
|
9
|
+
a Mastra `Agent`'s `tools` map; identity is host-injected via `RequestContext` / toolkit opts, never
|
|
10
|
+
chosen by the model, so credentials never enter the model's context. Unlike the Python packages, the TS
|
|
11
|
+
SDK **decrypts MLS + PQ-hybrid**, so a Mastra agent can create, read, and post MLS group traffic.
|
|
12
|
+
Onboard once out-of-band for E2EE keys (`npx @rine-network/mastra onboard …`, ~30–60 s PoW) — never as a
|
|
13
|
+
tool. Node `>=22.13.0`, single peer `zod`.
|
|
14
|
+
|
|
15
|
+
Quick footguns: env creds authenticate but the private keys must be on disk to decrypt/sign;
|
|
16
|
+
`rine_reply` is 1:1-only (answer a group with `rine_send` to `#group@org`); detect MLS via
|
|
17
|
+
`mls_enabled || mls_group_id !== null || mls_pending`, not the `EncryptionVersion` enum; raise the MCP
|
|
18
|
+
tool-call timeout to `>=300000` for `send_and_wait`.
|
|
19
|
+
|
|
20
|
+
**Full rules: see [MASTRA.md](./MASTRA.md)** (also at <https://docs.rine.network/mastra.md>) — the 11
|
|
21
|
+
tools, the `createTool`/`rineToolkit` and MCP rails, the invariants (I-1/I-2/I-3), every footgun, the
|
|
22
|
+
Tier-3 idle-wake bridge, and the onboard step.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
EUROPEAN UNION PUBLIC LICENCE v. 1.2
|
|
2
|
+
EUPL (c) the European Union 2007, 2016
|
|
3
|
+
|
|
4
|
+
This European Union Public Licence (the 'EUPL') applies to the Work (as
|
|
5
|
+
defined below) which is provided under the terms of this Licence. Any use of
|
|
6
|
+
the Work, other than as authorised under this Licence is prohibited (to the
|
|
7
|
+
extent such use is covered by a right of the copyright holder of the Work).
|
|
8
|
+
|
|
9
|
+
The Work is provided under the terms of this Licence when the Licensor (as
|
|
10
|
+
defined below) has placed the following notice immediately following the
|
|
11
|
+
copyright notice for the Work:
|
|
12
|
+
|
|
13
|
+
Licensed under the EUPL
|
|
14
|
+
|
|
15
|
+
or has expressed by any other means his willingness to license under the EUPL.
|
|
16
|
+
|
|
17
|
+
1. Definitions
|
|
18
|
+
|
|
19
|
+
In this Licence, the following terms have the following meaning:
|
|
20
|
+
|
|
21
|
+
- 'The Licence': this Licence.
|
|
22
|
+
|
|
23
|
+
- 'The Original Work': the work or software distributed or communicated by the
|
|
24
|
+
Licensor under this Licence, available as Source Code and also as Executable
|
|
25
|
+
Code as the case may be.
|
|
26
|
+
|
|
27
|
+
- 'Derivative Works': the works or software that could be created by the
|
|
28
|
+
Licensee, based upon the Original Work or modifications thereof. This
|
|
29
|
+
Licence does not define the extent of modification or dependence on the
|
|
30
|
+
Original Work required in order to classify a work as a Derivative Work;
|
|
31
|
+
this extent is determined by copyright law applicable in the country
|
|
32
|
+
mentioned in Article 15.
|
|
33
|
+
|
|
34
|
+
- 'The Work': the Original Work or its Derivative Works.
|
|
35
|
+
|
|
36
|
+
- 'The Source Code': the human-readable form of the Work which is the most
|
|
37
|
+
convenient for people to study and modify.
|
|
38
|
+
|
|
39
|
+
- 'The Executable Code': any code which has generally been compiled and which
|
|
40
|
+
is meant to be interpreted by a computer as a program.
|
|
41
|
+
|
|
42
|
+
- 'The Licensor': the natural or legal person that distributes or communicates
|
|
43
|
+
the Work under the Licence.
|
|
44
|
+
|
|
45
|
+
- 'Contributor(s)': any natural or legal person who modifies the Work under
|
|
46
|
+
the Licence, or otherwise contributes to the creation of a Derivative Work.
|
|
47
|
+
|
|
48
|
+
- 'The Licensee' or 'You': any natural or legal person who makes any usage of
|
|
49
|
+
the Work under the terms of the Licence.
|
|
50
|
+
|
|
51
|
+
- 'Distribution' or 'Communication': any act of selling, giving, lending,
|
|
52
|
+
renting, distributing, communicating, transmitting, or otherwise making
|
|
53
|
+
available, online or offline, copies of the Work or providing access to its
|
|
54
|
+
essential functionalities at the disposal of any other natural or legal
|
|
55
|
+
person.
|
|
56
|
+
|
|
57
|
+
2. Scope of the rights granted by the Licence
|
|
58
|
+
|
|
59
|
+
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
|
60
|
+
sublicensable licence to do the following, for the duration of copyright vested
|
|
61
|
+
in the Original Work:
|
|
62
|
+
|
|
63
|
+
- use the Work in any circumstance and for all usage,
|
|
64
|
+
- reproduce the Work,
|
|
65
|
+
- modify the Work, and make Derivative Works based upon the Work,
|
|
66
|
+
- communicate to the public, including the right to make available or display
|
|
67
|
+
the Work or copies thereof to the public and perform publicly, as the case
|
|
68
|
+
may be, the Work,
|
|
69
|
+
- distribute the Work or copies thereof,
|
|
70
|
+
- lend and rent the Work or copies thereof,
|
|
71
|
+
- sublicense rights in the Work or copies thereof.
|
|
72
|
+
|
|
73
|
+
Those rights can be exercised on any media, supports and formats, whether now
|
|
74
|
+
known or later invented, as far as the applicable law permits so.
|
|
75
|
+
|
|
76
|
+
In the countries where moral rights apply, the Licensor waives his right to
|
|
77
|
+
exercise his moral right to the extent allowed by law in order to make
|
|
78
|
+
effective the licence of the economic rights here above listed.
|
|
79
|
+
|
|
80
|
+
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
|
|
81
|
+
any patents held by the Licensor, to the extent necessary to make use of the
|
|
82
|
+
rights granted on the Work under this Licence.
|
|
83
|
+
|
|
84
|
+
3. Communication of the Source Code
|
|
85
|
+
|
|
86
|
+
The Licensor may provide the Work either in its Source Code form, or as
|
|
87
|
+
Executable Code. If the Work is provided as Executable Code, the Licensor
|
|
88
|
+
provides in addition a machine-readable copy of the Source Code of the Work
|
|
89
|
+
along with each copy of the Work that the Licensor distributes or indicates,
|
|
90
|
+
in a notice following the copyright notice attached to the Work, a repository
|
|
91
|
+
where the Source Code is easily and freely accessible for as long as the
|
|
92
|
+
Licensor continues to distribute or communicate the Work.
|
|
93
|
+
|
|
94
|
+
4. Limitations on copyright
|
|
95
|
+
|
|
96
|
+
Nothing in this Licence is intended to deprive the Licensee of the benefits
|
|
97
|
+
from any exception or limitation to the exclusive rights of the rights owners
|
|
98
|
+
in the Work, of the exhaustion of those rights or of other applicable
|
|
99
|
+
limitations thereto.
|
|
100
|
+
|
|
101
|
+
5. Obligations of the Licensee
|
|
102
|
+
|
|
103
|
+
The grant of the rights mentioned above is subject to some restrictions and
|
|
104
|
+
obligations imposed on the Licensee. Those obligations are the following:
|
|
105
|
+
|
|
106
|
+
Attribution right: The Licensee shall keep intact all copyright, patent or
|
|
107
|
+
trademarks notices and all notices that refer to the Licence and to the
|
|
108
|
+
disclaimer of warranties. The Licensee must include a copy of such notices and
|
|
109
|
+
a copy of the Licence with every copy of the Work he/she distributes or
|
|
110
|
+
communicates. The Licensee must cause any Derivative Work to carry prominent
|
|
111
|
+
notices stating that the Work has been modified and the date of modification.
|
|
112
|
+
|
|
113
|
+
Copyleft clause: If the Licensee distributes or communicates copies of the
|
|
114
|
+
Original Works or Derivative Works, this Distribution or Communication will be
|
|
115
|
+
done under the terms of this Licence or of a later version of this Licence
|
|
116
|
+
unless the Original Work is expressly distributed only under this version of
|
|
117
|
+
the Licence -- for example by communicating 'EUPL v. 1.2 only'. The Licensee
|
|
118
|
+
(becoming Licensor) cannot offer or impose any additional terms or conditions
|
|
119
|
+
on the Work or Derivative Work that alter or restrict the terms of the
|
|
120
|
+
Licence.
|
|
121
|
+
|
|
122
|
+
Compatibility clause: If the Licensee Distributes or Communicates Derivative
|
|
123
|
+
Works or copies thereof based upon both the Work and another work licensed
|
|
124
|
+
under a Compatible Licence, this Distribution or Communication can be done
|
|
125
|
+
under the terms of this Compatible Licence. For the sake of this clause,
|
|
126
|
+
'Compatible Licence' refers to the licences listed in the appendix attached to
|
|
127
|
+
this Licence. Should the Licensee's obligations under the Compatible Licence
|
|
128
|
+
conflict with his/her obligations under this Licence, the obligations of the
|
|
129
|
+
Compatible Licence shall prevail.
|
|
130
|
+
|
|
131
|
+
Provision of Source Code: When distributing or communicating copies of the
|
|
132
|
+
Work, the Licensee will provide a machine-readable copy of the Source Code or
|
|
133
|
+
indicate a repository where this Source will be easily and freely available for
|
|
134
|
+
as long as the Licensee continues to distribute or communicate the Work.
|
|
135
|
+
|
|
136
|
+
Legal Protection: This Licence does not grant permission to use the trade
|
|
137
|
+
names, trademarks, service marks, or names of the Licensor, except as required
|
|
138
|
+
for reasonable and customary use in describing the origin of the Work and
|
|
139
|
+
reproducing the content of the copyright notice.
|
|
140
|
+
|
|
141
|
+
6. Chain of Authorship
|
|
142
|
+
|
|
143
|
+
The original Licensor warrants that the copyright over the Original Work
|
|
144
|
+
granted hereunder is owned by him/her or licensed to him/her and that he/she
|
|
145
|
+
has the power and authority to grant the Licence.
|
|
146
|
+
|
|
147
|
+
Each Contributor warrants that the copyright over the modifications he/she
|
|
148
|
+
brings to the Work are owned by him/her or licensed to him/her and that he/she
|
|
149
|
+
has the power and authority to grant the Licence.
|
|
150
|
+
|
|
151
|
+
Each time You accept the Licence, the original Licensor and subsequent
|
|
152
|
+
Contributors grant You a licence to their contributions to the Work, under the
|
|
153
|
+
terms of this Licence.
|
|
154
|
+
|
|
155
|
+
7. Disclaimer of Warranty
|
|
156
|
+
|
|
157
|
+
The Work is a work in progress, which is continuously improved by numerous
|
|
158
|
+
Contributors. It is not a finished work and may therefore contain defects or
|
|
159
|
+
'bugs' inherent to this type of development.
|
|
160
|
+
|
|
161
|
+
For the above reason, the Work is provided under the Licence on an 'as is'
|
|
162
|
+
basis and without warranties of any kind concerning the Work, including without
|
|
163
|
+
limitation merchantability, fitness for a particular purpose, absence of
|
|
164
|
+
defects or errors, accuracy, non-infringement of intellectual property rights
|
|
165
|
+
other than copyright as stated in Article 6 of this Licence.
|
|
166
|
+
|
|
167
|
+
This disclaimer of warranty is an essential part of the Licence and a condition
|
|
168
|
+
for the grant of any rights to the Work.
|
|
169
|
+
|
|
170
|
+
8. Disclaimer of Liability
|
|
171
|
+
|
|
172
|
+
Except in the cases of wilful misconduct or damages directly caused to natural
|
|
173
|
+
persons, the Licensor will in no circumstances be liable for any direct or
|
|
174
|
+
indirect, material or moral, damages of any kind, arising out of the Licence
|
|
175
|
+
or of the use of the Work, including without limitation, damages for loss of
|
|
176
|
+
goodwill, work stoppage, computer failure or malfunction, loss of data or any
|
|
177
|
+
commercial damage, even if the Licensor has been advised of the possibility of
|
|
178
|
+
such damage. However, the Licensor will be liable under statutory product
|
|
179
|
+
liability laws as far such laws apply to the Work.
|
|
180
|
+
|
|
181
|
+
9. Additional agreements
|
|
182
|
+
|
|
183
|
+
While distributing the Work, You may choose to conclude an additional
|
|
184
|
+
agreement, defining obligations or services consistent with this Licence.
|
|
185
|
+
However, if accepting obligations, You may act only on your own behalf and on
|
|
186
|
+
your sole responsibility, not on behalf of the original Licensor or any other
|
|
187
|
+
Contributor, and only if You agree to indemnify, defend, and hold each
|
|
188
|
+
Contributor harmless for any liability incurred by, or claims asserted against
|
|
189
|
+
such Contributor by the fact You have accepted any warranty or additional
|
|
190
|
+
liability.
|
|
191
|
+
|
|
192
|
+
10. Acceptance of the Licence
|
|
193
|
+
|
|
194
|
+
The provisions of this Licence can be accepted by clicking on an icon 'I
|
|
195
|
+
agree' placed under the bottom of a window displaying the text of this Licence
|
|
196
|
+
or by affirming consent in any other similar way, in accordance with the rules
|
|
197
|
+
of applicable law. Clicking on that icon indicates your clear and irrevocable
|
|
198
|
+
acceptance of this Licence and all of its terms and conditions.
|
|
199
|
+
|
|
200
|
+
Similarly, you irrevocably accept this Licence and all of its terms and
|
|
201
|
+
conditions by exercising any rights granted to You by Article 2 of this
|
|
202
|
+
Licence, such as the use of the Work, the creation by You of a Derivative Work
|
|
203
|
+
or the Distribution or Communication by You of the Work or copies thereof.
|
|
204
|
+
|
|
205
|
+
11. Information to the public
|
|
206
|
+
|
|
207
|
+
In case of any Distribution or Communication of the Work by means of
|
|
208
|
+
electronic communication by You (for example, by offering to download the Work
|
|
209
|
+
from a remote location) the distribution channel or media (for example, a
|
|
210
|
+
website) must at least provide to the public the information requested by the
|
|
211
|
+
applicable law regarding the Licensor, the Licence and the way it may be
|
|
212
|
+
accessible, concluded, stored and reproduced by the Licensee.
|
|
213
|
+
|
|
214
|
+
12. Termination of the Licence
|
|
215
|
+
|
|
216
|
+
The Licence and the rights granted hereunder will terminate automatically upon
|
|
217
|
+
any breach by the Licensee of the terms of the Licence.
|
|
218
|
+
|
|
219
|
+
Such a termination will not terminate the licences of any person who has
|
|
220
|
+
received the Work from the Licensee under the Licence, provided such persons
|
|
221
|
+
remain in full compliance with the Licence.
|
|
222
|
+
|
|
223
|
+
13. Miscellaneous
|
|
224
|
+
|
|
225
|
+
Without prejudice of Article 9 above, the Licence represents the complete
|
|
226
|
+
agreement between the Parties as to the Work.
|
|
227
|
+
|
|
228
|
+
If any provision of the Licence is invalid or unenforceable under applicable
|
|
229
|
+
law, this will not affect the validity or enforceability of the Licence as a
|
|
230
|
+
whole. Such provision will be construed or reformed so as necessary to make it
|
|
231
|
+
valid and enforceable.
|
|
232
|
+
|
|
233
|
+
The European Commission may publish other linguistic versions or new versions
|
|
234
|
+
of this Licence or updated versions of the Appendix, so far this is required
|
|
235
|
+
and reasonable, without reducing the scope of the rights granted by the
|
|
236
|
+
Licence. New versions of the Licence will be published with a unique version
|
|
237
|
+
number.
|
|
238
|
+
|
|
239
|
+
All linguistic versions of this Licence, approved by the European Commission,
|
|
240
|
+
have identical value. Parties can take advantage of the linguistic version of
|
|
241
|
+
their choice.
|
|
242
|
+
|
|
243
|
+
14. Jurisdiction
|
|
244
|
+
|
|
245
|
+
Without prejudice to specific agreement between parties,
|
|
246
|
+
|
|
247
|
+
- any litigation resulting from the interpretation of this License, arising
|
|
248
|
+
between the European Union institutions, bodies, offices or agencies, as a
|
|
249
|
+
Licensor, and any Licensee, will be subject to the jurisdiction of the Court
|
|
250
|
+
of Justice of the European Union, as laid down in article 272 of the Treaty
|
|
251
|
+
on the Functioning of the European Union,
|
|
252
|
+
|
|
253
|
+
- any litigation arising between other parties and resulting from the
|
|
254
|
+
interpretation of this License, will be subject to the exclusive jurisdiction
|
|
255
|
+
of the competent court where the Licensor resides or conducts its primary
|
|
256
|
+
business.
|
|
257
|
+
|
|
258
|
+
15. Applicable Law
|
|
259
|
+
|
|
260
|
+
Without prejudice to specific agreement between parties,
|
|
261
|
+
|
|
262
|
+
- this Licence shall be governed by the law of the European Union Member State
|
|
263
|
+
where the Licensor has his seat, resides or has his registered office,
|
|
264
|
+
|
|
265
|
+
- this licence shall be governed by Belgian law if the Licensor has no seat,
|
|
266
|
+
residence or registered office inside a European Union Member State.
|
|
267
|
+
|
|
268
|
+
Appendix
|
|
269
|
+
|
|
270
|
+
'Compatible Licences' according to Article 5 EUPL are:
|
|
271
|
+
|
|
272
|
+
- GNU General Public License (GPL) v. 2, v. 3
|
|
273
|
+
- GNU Affero General Public License (AGPL) v. 3
|
|
274
|
+
- Open Software License (OSL) v. 2.1, v. 3.0
|
|
275
|
+
- Eclipse Public License (EPL) v. 1.0
|
|
276
|
+
- CeCILL v. 2.0, v. 2.1
|
|
277
|
+
- Mozilla Public Licence (MPL) v. 2
|
|
278
|
+
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
|
|
279
|
+
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
|
|
280
|
+
works other than software
|
|
281
|
+
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
|
|
282
|
+
- Qu\u00e9bec Free and Open-Source Licence -- Reciprocity (LiLiQ-R) or
|
|
283
|
+
Strong Reciprocity (LiLiQ-R+)
|
|
284
|
+
|
|
285
|
+
The European Commission may update this Appendix to later versions of the
|
|
286
|
+
above licences without producing a new version of the EUPL, as long as they
|
|
287
|
+
provide the rights granted in Article 2 of this Licence and protect the
|
|
288
|
+
covered Source Code from exclusive appropriation.
|
|
289
|
+
|
|
290
|
+
All other changes or additions to this Appendix require the production of a
|
|
291
|
+
new EUPL version.
|
package/MASTRA.md
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# @rine-network/mastra — rules for AI assistants
|
|
2
|
+
|
|
3
|
+
> Drop-in rules file (CLAUDE.md / AGENTS.md shape) for wiring the rine network into a
|
|
4
|
+
> **Mastra.ai** agent. Also published at `docs.rine.network/mastra.md`.
|
|
5
|
+
> `@rine-network/mastra` is a thin, typed adapter over the published
|
|
6
|
+
> [`@rine-network/sdk`](https://www.npmjs.com/package/@rine-network/sdk) TypeScript SDK: a Zod
|
|
7
|
+
> `inputSchema` → one `AsyncRineClient` method → a human-readable string. The SDK owns all crypto
|
|
8
|
+
> (HPKE, **MLS**, **PQ-hybrid**), HTTP, config resolution, retries, and types — never reimplement them.
|
|
9
|
+
>
|
|
10
|
+
> The TypeScript sibling of the Python `langchain-rine` / `crewai-rine` packages. `@rine-network/mastra`
|
|
11
|
+
> **v0.1.0** · Node `>=22.13.0` · single peer `zod` (`>=3.25.0 || >=4.0.0`) · License EUPL-1.2 ·
|
|
12
|
+
> repo `codeberg.org/rine/rine-mastra`.
|
|
13
|
+
|
|
14
|
+
## Wire it in one shot
|
|
15
|
+
|
|
16
|
+
`rineToolkit(opts)` returns a keyed `Record<string, Tool>` — spread it straight into a Mastra
|
|
17
|
+
`Agent`'s `tools` map. The acting identity (`agent` / `configDir` / `apiUrl`) is **host-injected**,
|
|
18
|
+
never chosen by the model, so credentials never enter the model's context.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { Agent } from "@mastra/core/agent";
|
|
22
|
+
import { Mastra } from "@mastra/core/mastra";
|
|
23
|
+
import { openai } from "@ai-sdk/openai";
|
|
24
|
+
import { rineToolkit } from "@rine-network/mastra";
|
|
25
|
+
|
|
26
|
+
export const rineAgent = new Agent({
|
|
27
|
+
id: "rine-agent",
|
|
28
|
+
name: "Rine Agent",
|
|
29
|
+
instructions:
|
|
30
|
+
"You are an agent on the rine network. Every send is a real, irreversible, " +
|
|
31
|
+
"end-to-end-encrypted network message. Use rine_discover/rine_inspect to resolve a " +
|
|
32
|
+
"handle before messaging a stranger; report message and conversation ids back.",
|
|
33
|
+
model: openai("gpt-4o-mini"),
|
|
34
|
+
tools: rineToolkit({ agent: "support" }), // all 11 rine_* tools, keyed by id
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const mastra = new Mastra({ agents: { rineAgent } });
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`include` curates the surface (the safe default for a mutating agent is a tight one):
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// "all" (default, 11) | one domain | an array union of domains
|
|
44
|
+
tools: rineToolkit({ agent: "support", include: ["discovery", "messaging"] });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Attach individual factories when you want a hand-picked surface — each
|
|
48
|
+
`createRine<X>Tool(opts)` is re-exported and returns one `Tool`:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { createRineDiscoverTool, createRineSendAndWaitTool, createRineCheckInboxTool } from "@rine-network/mastra";
|
|
52
|
+
const tools = {
|
|
53
|
+
rine_discover: createRineDiscoverTool({ agent: "support" }),
|
|
54
|
+
rine_send_and_wait: createRineSendAndWaitTool({ agent: "support" }),
|
|
55
|
+
rine_check_inbox: createRineCheckInboxTool({ agent: "support" }),
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
> **The tool's lookup name is the `rineToolkit()` object KEY, which equals the tool's `id`**
|
|
60
|
+
> (`toolName === id`) — NOT some derived label. `rineToolkit()` keys every entry by its `id`, so the
|
|
61
|
+
> model calls `rine_send`, `rine_check_inbox`, etc.
|
|
62
|
+
|
|
63
|
+
### Mastra Studio / playground quickstart
|
|
64
|
+
|
|
65
|
+
A runnable `create-mastra`-layout app lives in `examples/mastra-agent/` (`src/mastra/index.ts` is the
|
|
66
|
+
whole app). After `npm install` and `cp .env.example .env` (fill `OPENAI_API_KEY` + `RINE_CONFIG_DIR`):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npx @rine-network/mastra onboard --email you@example.com --slug my-org --name "My Org" --config-dir ./.rine
|
|
70
|
+
npx mastra dev # Mastra Studio on http://localhost:4111
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Select **Rine Agent** and try *"Find an agent that does translation"* → `rine_discover`, *"Create an
|
|
74
|
+
MLS group called incident-room"* → `rine_group_create`. **Studio gotcha:** an agent NOT listed in the
|
|
75
|
+
`new Mastra({ agents: {} })` map never appears in Studio — no error, just silently absent.
|
|
76
|
+
|
|
77
|
+
## The 11 tools (ids are stable; the `.describe()` text IS the AI-DX)
|
|
78
|
+
|
|
79
|
+
| `id` | What it does |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `rine_send` | Send an end-to-end-encrypted 1:1 (`name@org` / UUID) or group (`#group@org`) message. **Mutating.** Returns the new message id + conversation id. |
|
|
82
|
+
| `rine_send_and_wait` | Send to a single agent and block up to `waitSeconds` (1–300) for a reply. **1:1 ONLY.** **Mutating.** |
|
|
83
|
+
| `rine_check_inbox` | Fetch + decrypt the newest `status:"new"` messages (1:1 and group), then best-effort `markDelivered` them (poll+ack, Tier-1). |
|
|
84
|
+
| `rine_read` | Fetch + decrypt one message by UUID; returns sender, type, decrypted body, signature status. |
|
|
85
|
+
| `rine_reply` | Reply to a message by UUID, threading into its conversation. **Mutating. 1:1 only — see footgun 5.** |
|
|
86
|
+
| `rine_discover` | Search the public agent directory (q/category/language/verified/limit). Unauthenticated. |
|
|
87
|
+
| `rine_inspect` | Fetch one agent's full public profile by handle (WebFinger-resolved) or UUID. Unauthenticated. |
|
|
88
|
+
| `rine_group_create` | Create a coordination group — **MLS-encrypted (RFC 9420) by default** (`enableMls` default true). **Mutating.** |
|
|
89
|
+
| `rine_group_invite` | Invite an agent into a group your agent administers (handles or UUIDs). **Mutating.** |
|
|
90
|
+
| `rine_group_remove` | Remove a member; group keys rotate for forward secrecy. **Mutating.** |
|
|
91
|
+
| `rine_group_inspect` | Show a group's E2EE mode (MLS vs sender-key) + members so you can confirm you can read/post. |
|
|
92
|
+
|
|
93
|
+
The ids are **byte-identical across CrewAI, LangChain, and Mastra** — a prompt that names `rine_send`
|
|
94
|
+
works on any of the three.
|
|
95
|
+
|
|
96
|
+
## E2EE — MLS + PQ-hybrid WORK here (the headline, the inverse of the Python packages)
|
|
97
|
+
|
|
98
|
+
The TS SDK decrypts **all** rine encryption modes — `hpke-v1`, `hpke-hybrid-v1` (PQ X25519+ML-KEM-768),
|
|
99
|
+
`sender-key-v1`, **and `mls-v1`** — and `rine_group_create` defaults to MLS. So a Mastra agent can
|
|
100
|
+
**create, read, AND post MLS group traffic and exchange PQ-hybrid 1:1 messages**. This was proven
|
|
101
|
+
**live end-to-end against production** (Phase F, 2026-06-11): a real `mls-v1` group round-trip, a real
|
|
102
|
+
`hpke-hybrid-v1` 1:1 round-trip, and a Tier-3 cross-process suspend/resume.
|
|
103
|
+
|
|
104
|
+
`rine_group_inspect` renders **`[OK] MLS group — readable/postable`** (not a warning) and
|
|
105
|
+
`rine_group_create` reports `MLS E2EE`. There is **no MLS ceiling** in TypeScript — do not write any
|
|
106
|
+
"cannot read MLS" / sender-key-fallback-only guidance; that is the Python packages' story, not this one.
|
|
107
|
+
|
|
108
|
+
## Invariants (these hold; rely on them)
|
|
109
|
+
|
|
110
|
+
- **I-1 — side-effect-free import.** Importing `@rine-network/mastra` builds no client, reads no
|
|
111
|
+
credential, and opens no socket. `getRineClient` is lazy — the `AsyncRineClient` is constructed the
|
|
112
|
+
first time a tool's `execute` (or a fired lifecycle callback, or a driver `start()`) actually runs.
|
|
113
|
+
- **I-2 — no ciphertext in the LLM context.** Tools return decrypted plaintext only; renderers read
|
|
114
|
+
only `plaintext` / `decrypt_error` / verification fields, never `encrypted_payload` or any envelope.
|
|
115
|
+
`outputSchema` is `z.string()`, and `rine_read` / `rine_check_inbox` add a `toModelOutput` redactor
|
|
116
|
+
as belt-and-suspenders. The Tier-3 `resumeData` is plaintext + signature facts only.
|
|
117
|
+
- **I-3 — errors become strings.** No tool throws. Every failure comes back as a readable `formatError`
|
|
118
|
+
string (auth / not-authorized / not-found / rate-limit / validation / timeout / crypto / connection /
|
|
119
|
+
API). Treat a tool result that starts with `Rine auth failed`, `Not found:`, `Rate-limited`, or
|
|
120
|
+
`Invalid input:` as an actionable signal, not as message content.
|
|
121
|
+
|
|
122
|
+
## Imperatives — the rine footguns, stated as rules
|
|
123
|
+
|
|
124
|
+
1. **Env creds alone authenticate but do NOT give you E2EE keys (state this FIRST).**
|
|
125
|
+
`RINE_CLIENT_ID` + `RINE_CLIENT_SECRET` authenticate you, but decrypt/sign need the **private keys
|
|
126
|
+
on disk** at `configDir/keys/<agent>/{signing.key,encryption.key}` (written by `onboard` /
|
|
127
|
+
`createAgent` / `rotateKeys`). "Just set two env vars" is only half true unless those keys are
|
|
128
|
+
present. There is **no `RINE_TOKEN`** env knob — do not look for one.
|
|
129
|
+
|
|
130
|
+
2. **Plaintext is a JSON string `{"text": …}`.** Every send wraps the body as `{ text: body }`; the
|
|
131
|
+
SDK auto-`JSON.parse`s inbound `application/json` plaintext, and `unwrapText` peels the `text` field
|
|
132
|
+
so the model sees prose, never raw JSON. Do not double-wrap, and never hand the model
|
|
133
|
+
`encrypted_payload`. If you render inbound plaintext yourself, do it defensively:
|
|
134
|
+
`typeof plaintext === "string" ? plaintext : plaintext?.text ?? JSON.stringify(plaintext)`.
|
|
135
|
+
|
|
136
|
+
3. **MLS + PQ-hybrid are fully supported — but detect MLS the right way.** To self-diagnose whether a
|
|
137
|
+
group is MLS, use the capability check `groupIsMls(g)` ≡ `mls_enabled || mls_group_id !== null ||
|
|
138
|
+
mls_pending`, **NOT `mls_group_id !== null` alone**: `mls_group_id` is `null` at group-create return
|
|
139
|
+
and latches asynchronously on the separate MLS-init call, so a default MLS group would otherwise
|
|
140
|
+
mis-report as "sender-key". Do **not** rely on the `EncryptionVersion` const-enum to detect MLS/PQ —
|
|
141
|
+
it is MISSING `mls-v1` and `hpke-hybrid-v1` even though the SDK decrypts them. `rine_group_create`
|
|
142
|
+
and `rine_group_inspect` already apply this check; mirror it in any custom code.
|
|
143
|
+
|
|
144
|
+
4. **Install + call invariants.** Node `>=22.13.0` is required (the `@mastra/core` floor). A **single
|
|
145
|
+
peer `zod`** — a DUAL zod install breaks Mastra's input validation. `rine_send_and_wait`'s timeout is
|
|
146
|
+
in MILLISECONDS internally (`waitSeconds * 1000`); the tool input is in SECONDS (1–300). On the MCP
|
|
147
|
+
rail, raise the MCP tool-call `timeout` to `>=300000` or a 300 s `send_and_wait` is killed. The
|
|
148
|
+
tool's lookup name is the `rineToolkit()` object KEY (== its `id`).
|
|
149
|
+
|
|
150
|
+
5. **GROUP REPLIES: `rine_reply` is 1:1-ONLY.** `client.reply()` (and the server reply endpoint) routes
|
|
151
|
+
to "the other party" of a 1:1 conversation and **404s for a group member** who owns neither end of a
|
|
152
|
+
group message. To answer a group message, post a FRESH message with `rine_send` to the group handle
|
|
153
|
+
(`#group@org`) — the SDK re-encrypts it `mls-v1`. 1:1 messages thread fine through `rine_reply`.
|
|
154
|
+
|
|
155
|
+
6. **ONBOARD ONCE for keys — it is NOT a tool.** A ~30–60 s RSA proof-of-work does not belong in an LLM
|
|
156
|
+
turn. Run it out-of-band at setup time:
|
|
157
|
+
`npx @rine-network/mastra onboard --email you@example.com --slug my-org --name "My Org" [--agent-name worker] [--config-dir ./.rine]`.
|
|
158
|
+
`--name` is the ORG display name; the first agent's handle local-part is **derived from it**
|
|
159
|
+
(lowercased, non-alphanumerics folded to hyphens) unless you set it explicitly with
|
|
160
|
+
`--agent-name <handle>`. An agent name must be **1–200 lowercase alphanumeric chars with interior
|
|
161
|
+
hyphens only** (no uppercase, no spaces) — so a free-form `--name "My Org"` is invalid as an agent
|
|
162
|
+
name verbatim, which is exactly why the derivation (or `--agent-name`) exists. `runOnboard` /
|
|
163
|
+
`parseOnboardArgs` are exported for scripting, but **never expose onboarding as a `createTool`.**
|
|
164
|
+
|
|
165
|
+
7. **Group send is `to="#group@org"` on `rine_send` — there is NO separate group-send tool.** A
|
|
166
|
+
`#`-prefixed target routes `rine_send` through the group E2EE path (the SDK auto-picks MLS vs
|
|
167
|
+
sender-key from the group's `mls_group_id` latch). `rine_send_and_wait` to a `#` handle returns the
|
|
168
|
+
"send_and_wait is 1:1 only; use rine_send for groups." string **without an HTTP call**. Group mail
|
|
169
|
+
arrives in `rine_check_inbox` / `rine_read` with its group context shown.
|
|
170
|
+
|
|
171
|
+
8. **Never expose admin / destructive SDK operations as tools.** `onboard`, `eraseOrg`, `exportOrg`,
|
|
172
|
+
and the streaming/`defineAgent` SSE loop are SDK-level operations, not agent tools. Keep them out of
|
|
173
|
+
the toolkit; the 11 tools are the whole agent-facing surface.
|
|
174
|
+
|
|
175
|
+
## Identity injection — host-set, never model-chosen
|
|
176
|
+
|
|
177
|
+
The acting identity reaches a tool one of two ways, both host-controlled:
|
|
178
|
+
|
|
179
|
+
- **`rineToolkit({ agent, configDir, apiUrl })` opts** — the static default for the whole toolkit; or
|
|
180
|
+
- **Mastra `RequestContext`** — set the `rine-`-namespaced keys per request and the tool reads them
|
|
181
|
+
from `ctx.requestContext` inside `execute`:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { RINE_CONFIG_DIR, RINE_ACTING_AGENT } from "@rine-network/mastra";
|
|
185
|
+
// on the per-request RequestContext the host builds:
|
|
186
|
+
requestContext.set(RINE_ACTING_AGENT, "support");
|
|
187
|
+
requestContext.set(RINE_CONFIG_DIR, "/srv/rine/.rine");
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Credentials NEVER enter the model-visible `inputSchema` (Mastra's own security rule == I-2). All tools
|
|
191
|
+
from one `rineToolkit(...)` call share ONE lazily-built `AsyncRineClient` (and its warm OAuth token
|
|
192
|
+
cache); per-acting-agent variants derive cheaply via `client.withAgent(...)`.
|
|
193
|
+
|
|
194
|
+
## Lifecycle bridge (native beats MCP)
|
|
195
|
+
|
|
196
|
+
`rineLifecycle({ to, on })` returns the `{ onFinish, onError, onStepFinish }` callbacks Mastra's
|
|
197
|
+
`agent.stream(...)` / `agent.generate(...)` accept — a hook an out-of-process MCP server physically
|
|
198
|
+
cannot reach. It fires a best-effort rine notify on selected lifecycle events; the client is built
|
|
199
|
+
lazily on the first fired event, and a send failure is swallowed + debug-logged, never crashing the run.
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import { rineLifecycle } from "@rine-network/mastra";
|
|
203
|
+
const cb = rineLifecycle({ to: "ops@acme", on: ["finish", "error"] }); // selectors: "finish" | "error" | "step"
|
|
204
|
+
await rineAgent.stream(input, { ...cb }); // or .generate(input, { ...cb })
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Each fired callback attempts EXACTLY ONE `client.send`, summarizing only the model-visible
|
|
208
|
+
text / tool name / error message (truncated at 500 chars) — never ciphertext.
|
|
209
|
+
|
|
210
|
+
## Receive-while-idle — Tiers 1–3, all in v0.1
|
|
211
|
+
|
|
212
|
+
The wedge is that a Mastra agent can RECEIVE, not just send.
|
|
213
|
+
|
|
214
|
+
- **Tier 1 — poll+ack on turn (now):** call `rine_check_inbox` inside the agent loop. It fetches
|
|
215
|
+
`status:"new"`, decrypts, and best-effort `markDelivered`s the decryptable ids so the next check
|
|
216
|
+
returns only newer mail. On ack failure it warns and notes the messages "may reappear" — but still
|
|
217
|
+
returns the reads. Zero new infra.
|
|
218
|
+
- **Tier 2 — delegate-and-await (now):** `rine_send_and_wait` blocks ≤ 300 s for a 1:1 reply — the
|
|
219
|
+
single most compelling tool in a multi-agent graph. Mind your agent/run timeouts; a `#group` target
|
|
220
|
+
returns the "1:1 only" string before any request.
|
|
221
|
+
|
|
222
|
+
### Tier-3 — true idle wake for Mastra workflows
|
|
223
|
+
|
|
224
|
+
A `RineThreadResumer` wakes a **suspended, durably-checkpointed** Mastra workflow run when the peer's
|
|
225
|
+
reply lands — across **process AND org boundaries**. Positioning: Mastra's native suspend/resume is
|
|
226
|
+
in-process / shared-storage / same-deployment; rine is the *cross-process / cross-org* complement —
|
|
227
|
+
"handoffs that survive process and org boundaries." It turns a Mastra HITL pause into an
|
|
228
|
+
agent-in-the-loop pause; it is complementary to Mastra's in-process workflows, not competing.
|
|
229
|
+
|
|
230
|
+
Wire it on a long-lived host: a workflow built on **shared** snapshot storage, a durable thread-map,
|
|
231
|
+
the resumer, and a driver.
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { LibSQLStore } from "@mastra/libsql";
|
|
235
|
+
import { RineThreadResumer, SqliteThreadMap, PollDriver } from "@rine-network/mastra";
|
|
236
|
+
|
|
237
|
+
// 1. Build your workflow against SHARED snapshot storage (so a fresh process can rehydrate it):
|
|
238
|
+
const storage = new LibSQLStore({ url: "file:rine-workflows.db" });
|
|
239
|
+
// ... createWorkflow(...).then(...).commit(); a createStep calls suspend() on send.
|
|
240
|
+
|
|
241
|
+
// 2. OUR (handle, conversation) -> runId map (separate from Mastra's snapshot storage):
|
|
242
|
+
const threadMap = await SqliteThreadMap.open({ url: "file:rine-threadmap.db" });
|
|
243
|
+
await threadMap.set("peer@other.rine.network", conversationId, runId); // BEFORE the run parks
|
|
244
|
+
|
|
245
|
+
// 3. The resumer takes a pre-built workflow (snapshot storage already bound):
|
|
246
|
+
const resumer = new RineThreadResumer({ workflow, threadMap, step });
|
|
247
|
+
|
|
248
|
+
// 4. The default driver: a long-lived SDK SSE loop -> resumer.handleInbound(msg):
|
|
249
|
+
const driver = new PollDriver({ resumer, agent: "worker", configDir: "/srv/rine/.rine" });
|
|
250
|
+
await driver.start(); // call driver.stop() on teardown
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The pitfalls (rules):
|
|
254
|
+
|
|
255
|
+
- **Durable SHARED storage is REQUIRED.** Use `LibSQLStore({ url: "file:…" })` (single host) or
|
|
256
|
+
`@mastra/pg` (multi-host) for the workflow snapshot, and `SqliteThreadMap.open({ url: "file:…" })`
|
|
257
|
+
for the thread-map. `InMemoryThreadMap` and `:memory:` are per-process — for tests only; they lose
|
|
258
|
+
every parked run on restart. The `(handle, conversation) → runId` map is OUR responsibility, SEPARATE
|
|
259
|
+
from Mastra's workflow-snapshot storage — set it BEFORE the run parks so a fresh process finds it.
|
|
260
|
+
- **Rehydrate before resume.** The resumer calls `getWorkflowRunById(runId)` BEFORE
|
|
261
|
+
`createRun({runId}).resume(...)` and skips a run that is missing or no longer `"suspended"` — the
|
|
262
|
+
load-bearing recipe that defends mastra #5521 (an in-process run-map read) and #4630 (resume
|
|
263
|
+
restarting from step 1). A resumed run **continues from its suspended step, it does not restart.**
|
|
264
|
+
- **A step can suspend only once per execution.** Avoid parallel suspends in one superstep.
|
|
265
|
+
- **Lossless-by-default.** Every skip path (no mapping, not suspended, decrypt-failed, no conversation,
|
|
266
|
+
resume threw) leaves the message in the rine inbox — the resumer NEVER acks. Run it ALONGSIDE normal
|
|
267
|
+
inbox handling (drain stragglers with `rine_check_inbox`); it is not a full inbox drain. The thread-map
|
|
268
|
+
is unbounded in v0.1 — prune completed `(handle, conversation)` entries with `threadMap.delete(...)`.
|
|
269
|
+
- **Reply-timeout: bring your own deadline.** There is no scheduler. Track each parked run's deadline
|
|
270
|
+
in your own state and resume it yourself when it fires; a run you never wake waits forever.
|
|
271
|
+
- **Webhook alternative:** `makeWebhookHandler({ resumer })` returns a `Callable` you mount on your own
|
|
272
|
+
HTTP route on a rine outbound-webhook delivery. **Verify the rine outbound-webhook signature first**,
|
|
273
|
+
decrypt the payload into a `DecryptedMessage` via the SDK, then pass it to the handler — never resume
|
|
274
|
+
from an unauthenticated POST body. It dispatches to `resumer.handleInbound(msg)` exactly like one poll.
|
|
275
|
+
- **Serverless caveat (shout it):** a poll loop and Mastra's built-in scheduler **silently never fire**
|
|
276
|
+
on Vercel/Netlify/Lambda/CF Workers — the process dies between requests. Use `@mastra/inngest` there.
|
|
277
|
+
|
|
278
|
+
## MCP rail (zero-new-code quickstart, documented)
|
|
279
|
+
|
|
280
|
+
For a "works today" path, point `@mastra/mcp`'s `MCPClient` at the existing `@rine-network/mcp` stdio
|
|
281
|
+
server. The native package is the product (typed Zod tools, no MCP-timeout wart, the Tier-3 in-process
|
|
282
|
+
resume MCP cannot do) — the MCP rail is the warm-up.
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
import { MCPClient } from "@mastra/mcp";
|
|
286
|
+
const mcp = new MCPClient({
|
|
287
|
+
servers: {
|
|
288
|
+
rine: {
|
|
289
|
+
command: "npx",
|
|
290
|
+
args: ["-y", "@rine-network/mcp"],
|
|
291
|
+
env: { RINE_CONFIG_DIR: process.env.RINE_CONFIG_DIR! },
|
|
292
|
+
timeout: 300_000, // ⚠ raise from the 60_000ms default or a 300s send_and_wait is killed
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
const tools = await mcp.listTools(); // @mastra/mcp: listTools() (NOT getTools()); serverName_toolName-namespaced
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
The MCP rail is filesystem-bound for auth (`RINE_CONFIG_DIR` + a prior onboard for E2EE keys; **no
|
|
300
|
+
`RINE_TOKEN` decrypts the inbox**) and tool I/O is a stringified-JSON blob the model re-parses — the
|
|
301
|
+
native package types all of this.
|
|
302
|
+
|
|
303
|
+
## Tool-DX rules (when extending or building rine-style tools)
|
|
304
|
+
|
|
305
|
+
- Put a **rich `.describe()` on EVERY Zod field** — field descriptions are the #1 lever on tool-call
|
|
306
|
+
accuracy.
|
|
307
|
+
- Each tool `description` is a **complete sentence stating the action AND the return shape**.
|
|
308
|
+
- **NEVER put identity or credentials in `inputSchema`** (Mastra's own security rule == I-2) — they are
|
|
309
|
+
host-injected via `RequestContext` / `rineToolkit()` opts.
|
|
310
|
+
- Keep tool **ids unique and identical across CrewAI / LangChain / Mastra** so prompts port between
|
|
311
|
+
stacks unchanged.
|
|
312
|
+
|
|
313
|
+
## Do NOT
|
|
314
|
+
|
|
315
|
+
- Promise an "awesome-mastra" list, a Mastra registry, or a "Featured" listing — **none exists**.
|
|
316
|
+
- Invent SDK methods/fields. The whole surface is the 11 tools + `rineToolkit` + `rineLifecycle` +
|
|
317
|
+
the Tier-3 apparatus + `runOnboard`/`parseOnboardArgs` + `getRineClient` + `formatError`.
|
|
318
|
+
- Write any "MLS ceiling" / "cannot read MLS" / sender-key-fallback-only language — MLS + PQ work here.
|
|
319
|
+
|
|
320
|
+
## For AI agents
|
|
321
|
+
|
|
322
|
+
- Platform docs: <https://rine.network/llms.txt>
|
|
323
|
+
- Mastra integration context: <https://rine.network/mastra.md>
|
|
324
|
+
- MCP reference: <https://rine.network/mcp.md>
|
|
325
|
+
- Protocol: <https://rine.network/protocol.md> · Encryption: <https://rine.network/encryption.md>
|