@rizom/ops 0.2.0-alpha.12 → 0.2.0-alpha.121

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.
Files changed (43) hide show
  1. package/README.md +7 -3
  2. package/dist/age-key-bootstrap.d.ts +17 -0
  3. package/dist/brains-ops.js +281 -160
  4. package/dist/cert-bootstrap.d.ts +3 -3
  5. package/dist/content-repo.d.ts +4 -0
  6. package/dist/deploy.js +3 -170
  7. package/dist/entries/deploy.d.ts +2 -2
  8. package/dist/index.d.ts +4 -0
  9. package/dist/index.js +280 -159
  10. package/dist/load-registry.d.ts +12 -3
  11. package/dist/observed-status.d.ts +1 -1
  12. package/dist/origin-ca.d.ts +1 -1
  13. package/dist/parse-args.d.ts +2 -0
  14. package/dist/push-secrets.d.ts +1 -1
  15. package/dist/run-command.d.ts +1 -2
  16. package/dist/schema.d.ts +64 -10
  17. package/dist/secrets-encrypt.d.ts +32 -0
  18. package/dist/secrets-push.d.ts +1 -1
  19. package/dist/ssh-key-bootstrap.d.ts +1 -1
  20. package/dist/user-add.d.ts +15 -0
  21. package/dist/verify-user.d.ts +19 -0
  22. package/package.json +7 -3
  23. package/templates/rover-pilot/.env.schema +21 -2
  24. package/templates/rover-pilot/.github/workflows/build.yml +13 -5
  25. package/templates/rover-pilot/.github/workflows/deploy.yml +64 -27
  26. package/templates/rover-pilot/.github/workflows/reconcile.yml +16 -2
  27. package/templates/rover-pilot/README.md +6 -3
  28. package/templates/rover-pilot/deploy/scripts/decrypt-user-secrets.ts +79 -0
  29. package/templates/rover-pilot/deploy/scripts/provision-server.ts +1 -1
  30. package/templates/rover-pilot/deploy/scripts/resolve-deploy-handles.ts +15 -6
  31. package/templates/rover-pilot/deploy/scripts/resolve-user-config.ts +12 -12
  32. package/templates/rover-pilot/deploy/scripts/update-dns.ts +14 -4
  33. package/templates/rover-pilot/docs/onboarding-checklist.md +43 -14
  34. package/templates/rover-pilot/docs/operator-playbook.md +159 -10
  35. package/templates/rover-pilot/docs/user-onboarding.md +156 -295
  36. package/templates/rover-pilot/package.json +3 -0
  37. package/templates/rover-pilot/pilot.yaml +3 -0
  38. package/templates/rover-pilot/users/alice.yaml +2 -1
  39. package/dist/user-secret-names.d.ts +0 -6
  40. package/templates/rover-pilot/.kamal/hooks/pre-deploy +0 -9
  41. package/templates/rover-pilot/deploy/Caddyfile +0 -72
  42. package/templates/rover-pilot/deploy/Dockerfile +0 -38
  43. package/templates/rover-pilot/deploy/kamal/deploy.yml +0 -40
@@ -1,356 +1,217 @@
1
- # Rover Pilot User Onboarding
1
+ # Welcome to Rover
2
2
 
3
- Welcome to the Rover pilot.
3
+ Rover is your own AI. Not a chatbot you share with the rest of the
4
+ world — a private assistant deployed just for you, that holds your
5
+ notes, links, and ideas, and gets more useful the more you put into
6
+ it.
4
7
 
5
- This document is written for **first-time users**. You do **not** need prior experience with Rover, MCP, git, or the rest of the system to get started.
8
+ This guide walks you through your first days. You don't need
9
+ experience with any particular tools — if you can use a browser, you
10
+ can use Rover.
6
11
 
7
- ## What Rover is
12
+ ## Get in and say hello
8
13
 
9
- Rover is your private AI assistant for working with your own notes, links, and ideas.
14
+ 1. **Open the setup email** we sent you and click the setup link.
15
+ 2. **Register a passkey** — your browser will offer fingerprint,
16
+ face, or PIN. This becomes how you sign in; there is no password.
17
+ 3. **Open your chat**: `https://<handle>.rizom.ai/chat` — sign in
18
+ with the passkey you just made.
19
+ 4. **Say hello.** Ask Rover:
10
20
 
11
- In this pilot, Rover is intentionally simple:
21
+ > What can you help me do?
12
22
 
13
- - you talk to it through an **MCP client**
14
- - **there is no website to browse**
15
- - Discord is optional
16
- - Obsidian fits through the git-sync/content-repo workflow, not as the main chat interface
23
+ That's the whole setup. The chat in your browser is where you and
24
+ Rover will spend most of your time.
17
25
 
18
- You can think of Rover as a private knowledge companion that helps you:
26
+ One caution: the setup link works once and then expires. Don't
27
+ forward it, and if it has already expired when you click it, just
28
+ tell us — we'll send a fresh one.
19
29
 
20
- - save notes
21
- - save links
22
- - reflect on your own material
23
- - find patterns in what you have collected
24
- - think through questions with AI
30
+ ## What your Rover holds
25
31
 
26
- ## What you will receive from us
32
+ Everything in Rover is one of a few simple kinds of things:
27
33
 
28
- We will send you the details you need to connect.
34
+ - **Notes** thoughts, ideas, observations in your own words.
35
+ - **Links** — things from the web, saved with why they matter to you.
36
+ - **Documents** — files you drop into chat: Markdown, PDFs, images.
37
+ - **Topics** — the themes running through your material. You don't
38
+ create these; Rover notices them.
39
+ - **Wishes** — things you asked for that Rover can't do yet.
40
+ - **Agents** — other people's brains, saved to your directory so you
41
+ can ask them things.
29
42
 
30
- That usually includes:
43
+ You'll meet each of these as you go. The first three you put in; the
44
+ last three grow out of how you use it.
31
45
 
32
- - your Rover URL: `https://<handle>.rizom.ai/mcp`
33
- - your **Bearer token**
34
- - confirmation of whether Discord is enabled for you
35
- - if needed, an invite to your **private** Rover content repo
36
- - any extra instructions if we are testing a specific workflow with your cohort
46
+ ## The way of working
37
47
 
38
- Treat the **Bearer token** like a password. Do not share it.
48
+ Rover is built around a simple loop:
39
49
 
40
- ## One important idea: MCP is just the connection method
50
+ **Capture ask back shape.**
41
51
 
42
- If you have never used MCP before, the shortest explanation is:
52
+ What makes it work: every note, link, and document you hand Rover
53
+ lands in one connected memory. Rover reads what you save, links it
54
+ to what's already there, and notices the topics running through it.
55
+ Nothing sits in a folder waiting to be found — every capture makes
56
+ the next answer better. Ten notes in, Rover is a notebook; a hundred
57
+ notes in, it starts knowing how you think.
43
58
 
44
- - **Rover** is the assistant
45
- - **MCP** is the way your AI client connects to Rover
59
+ The important part is what you _don't_ do: you don't organize. No
60
+ folders, no tags, no filing things in the right place. You throw
61
+ material in as it comes, and Rover makes sense of it when you need
62
+ it.
46
63
 
47
- You do not need to understand the protocol details.
64
+ ### Capture
48
65
 
49
- For the pilot, the practical meaning is simple:
66
+ Notes for what's in your head:
50
67
 
51
- - open a supported client
52
- - add your Rover URL
53
- - paste your Bearer token
54
- - start talking to Rover
68
+ > Save a note: I keep explaining the same idea to clients — maybe
69
+ > it should be a workshop.
55
70
 
56
- ## What to use first
71
+ Links for what's on your screen:
57
72
 
58
- For most users, the easiest first setup is:
73
+ > Save this link with my workshop idea — it's how someone else
74
+ > structures theirs: https://example.com
59
75
 
60
- - **Claude Desktop** for talking to Rover
61
- - **Obsidian** only if you also want to work directly with markdown files later
62
- - **Discord** only if we explicitly enable it for you
76
+ Documents for what you already have: drop a Markdown file, a PDF, or
77
+ an image into the chat and ask Rover to save or import it. If you
78
+ have notes living somewhere else, this is the fastest way to give
79
+ Rover a head start.
63
80
 
64
- ## How to connect
81
+ ### Ask back
65
82
 
66
- Use an MCP client that supports:
83
+ Ask in whatever words occur to you — Rover searches by meaning, not
84
+ exact phrases, so you don't have to remember what you called
85
+ something:
67
86
 
68
- - **HTTP / Streamable HTTP MCP**
69
- - **Bearer token authentication**
87
+ > What have I added about the workshop idea?
70
88
 
71
- When your client asks for connection details, use:
89
+ > What did I save this week?
72
90
 
73
- - **Server URL:** `https://<handle>.rizom.ai/mcp`
74
- - **Authentication type:** Bearer token
75
- - **Bearer token:** the token we sent you
91
+ And as material accumulates, the topics surface — the themes you
92
+ keep returning to without noticing:
76
93
 
77
- If the client asks for a name, use something simple like:
94
+ > What themes do you see in what I've collected?
78
95
 
79
- - `Rover (<handle>)`
96
+ ### Shape
80
97
 
81
- ## Claude Desktop setup
98
+ When you want to make something from what you've gathered:
82
99
 
83
- If your Claude Desktop version supports connecting to a **remote HTTP / Streamable HTTP MCP server**, enter:
100
+ > Turn my workshop notes into a one-page outline.
84
101
 
85
- - **Server URL:** `https://<handle>.rizom.ai/mcp`
86
- - **Authentication:** Bearer token
87
- - **Token:** the token we sent you
102
+ > Make a reading list from the links I saved.
88
103
 
89
- Then try a first message like:
104
+ Capture is cheap, asking back is instant, and shaping turns a pile
105
+ of fragments into something you can use. That loop is Rover — and it
106
+ only proves itself on real material, so start with things you
107
+ actually want to keep.
90
108
 
91
- > What can you help me do, and what should I use you for?
109
+ ## When Rover can't do something: make a wish
92
110
 
93
- Or:
111
+ Sooner or later you'll ask for something Rover can't do yet. That's
112
+ where wishes come from: Rover says so honestly and offers to save
113
+ the request as a wish:
94
114
 
95
- > Help me save my first note.
115
+ > I wish you could remind me about this next Monday.
96
116
 
97
- If your Claude Desktop version only supports local MCP servers and not remote HTTP MCP cleanly, tell us what version you are using and we will help you.
117
+ Wishes flow back to us and shape what gets built next. Asking for
118
+ things Rover can't do is not a failure — it's one of the most useful
119
+ things a pilot user can do.
98
120
 
99
- ## Your first 5 minutes
121
+ ## Your Rover in the network
100
122
 
101
- Once you are connected, try this sequence:
123
+ The loop has a second payoff. Rover isn't only a private assistant —
124
+ it's your agent in a network of brains, and the connection runs both
125
+ ways.
102
126
 
103
- ### 1. Check that Rover responds
127
+ **Other people's brains become sources.** When someone you know runs
128
+ a brain, you don't have to send them a message and wait — you ask
129
+ their brain directly, from your own chat. Save it to your agents
130
+ once:
104
131
 
105
- Ask:
132
+ > Add yeehaa.io to my agents.
106
133
 
107
- > What can you help me do?
134
+ Then ask questions that put their knowledge next to yours:
108
135
 
109
- ### 2. Save a first note
136
+ > Ask yeehaa.io what they've published about designing workshops,
137
+ > and compare it with my own workshop notes.
110
138
 
111
- Ask:
139
+ One ask, both directions: Rover pulls their public knowledge over
140
+ the network, sets it against the material you've been capturing, and
141
+ answers in terms of your situation. What comes back you can think
142
+ with, push back on, or capture:
112
143
 
113
- > Save a note: I want to use Rover to collect ideas from my work, reading, and conversations.
144
+ > Save that comparison as a note with my workshop idea.
114
145
 
115
- ### 3. Save a useful link
146
+ That's the loop again, with someone else's knowledge feeding your
147
+ capture. Rover never contacts an agent you haven't saved without
148
+ telling you first, and your private material is never shared — only
149
+ the question you send.
116
150
 
117
- Ask:
151
+ **Your brain becomes a source for others.** The same way you ask
152
+ other agents, they can ask yours. Your Rover answers on your behalf,
153
+ drawing only on what you've chosen to make public — and it builds
154
+ its picture of what you know from everything you capture.
118
155
 
119
- > Save this link and note why it matters to me: <paste URL>
156
+ So the network is the quiet consequence of the loop: the more you
157
+ put in, the more useful your Rover is to you — and the better it
158
+ speaks for you when you're not in the room.
120
159
 
121
- ### 4. Ask Rover to reflect back what it knows
160
+ ## The other doors
122
161
 
123
- Ask:
162
+ Chat is the primary interface, but your Rover has a few more
163
+ entrances. All optional — ignore them until you're curious:
124
164
 
125
- > Based on what I’ve stored so far, what themes are starting to emerge?
165
+ - **Dashboard** `https://<handle>.rizom.ai/` is your Rover's home
166
+ page in the browser: a quick overview that everything is running.
167
+ - **CMS** — `https://<handle>.rizom.ai/cms` is a browser editor for
168
+ your content, useful when you want to write or restructure
169
+ something longer than a chat message. If it asks for GitHub
170
+ access, use the instructions we sent; if we didn't send any, skip
171
+ the CMS for now.
172
+ - **Your own AI client (MCP)** — Rover can plug into AI apps you
173
+ already use (Claude, Cursor, and others), signed in with the same
174
+ passkey. If you want this, ask us and we'll send the short setup.
175
+ - **Discord** — available for some pilot cohorts as a secondary
176
+ chat. If it's enabled for you, we'll send the invite separately.
126
177
 
127
- ### 5. Use it as a thinking partner
178
+ Under the hood, everything you save is plain Markdown in a private
179
+ repository that belongs to you. You never have to touch it — but
180
+ your material is never locked in, either.
128
181
 
129
- Ask:
182
+ ## What to expect from the pilot
130
183
 
131
- > I am thinking through a problem in my work. Help me structure the question and identify what context is missing.
184
+ This is a real, working system, and an early one. Expect occasional
185
+ rough edges and visible improvement while you use it. Your Rover is
186
+ deployed specifically for you, your content lives in your own
187
+ private store, and sign-in is by passkey. One ask: avoid putting
188
+ highly sensitive material in during the pilot unless we've agreed
189
+ it's in scope — when unsure, ask.
132
190
 
133
- ## Wishlist: when Rover cannot do something yet
191
+ For questions, feedback, or anything that feels off, join our
192
+ Discord server: `<discord-invite>`. That's the fastest way to reach
193
+ us, and you'll meet the other pilot users there too.
134
194
 
135
- Rover has a built-in **wishlist**.
195
+ ## If something doesn't work
136
196
 
137
- This is important for first-time users because Rover will not be able to do everything yet.
197
+ - **No setup email** check spam first, then tell us which address
198
+ to use.
199
+ - **Setup link expired** — tell us; we'll reissue it.
200
+ - **Browser asks for a passkey** — expected; use the one you
201
+ registered during setup.
202
+ - **Anything else** — post in the Discord server with the exact
203
+ error text or a screenshot and we'll sort it out. Never paste your
204
+ setup link anywhere except your own browser.
138
205
 
139
- If you ask for something Rover cannot do, it should add that request to the wishlist instead of just failing silently.
206
+ ## Tell us what you notice
140
207
 
141
- You can think of the wishlist as:
208
+ The feedback that helps most is small and honest — drop it in the
209
+ Discord server as it occurs to you:
142
210
 
143
- - a backlog of missing capabilities
144
- - a record of things users want Rover to do
145
- - a way for the pilot team to see which missing features matter most
211
+ - where setup confused you
212
+ - what felt useful right away, and what felt pointless
213
+ - what you expected Rover to do that it couldn't
214
+ - whether the capture → ask back → shape loop fits how you work
215
+ - whether you'd keep using Rover after the pilot
146
216
 
147
- ### When the wishlist is useful
148
-
149
- The wishlist is especially useful when you ask Rover to do something like:
150
-
151
- - connect to a tool it does not support yet
152
- - perform an action it cannot perform yet
153
- - add a workflow or feature that does not exist yet
154
-
155
- Examples:
156
-
157
- > I want Rover to draft and send emails for me.
158
-
159
- > I want Rover to connect to my calendar.
160
-
161
- > I want Rover to summarize voice notes automatically.
162
-
163
- If Rover cannot actually do those things yet, it should tell you that and add the request to the wishlist.
164
-
165
- ### What happens when something is added to the wishlist
166
-
167
- When a request is added to the wishlist:
168
-
169
- - it is saved as a **wish**
170
- - it starts in a **new** state
171
- - similar requests can be grouped together instead of creating endless duplicates
172
- - repeated demand can increase the count of how many times that wish was requested
173
-
174
- That helps us see which gaps are one-off ideas and which ones keep coming up across real usage.
175
-
176
- ### How you should use it
177
-
178
- You do **not** need special commands.
179
-
180
- Just ask naturally.
181
-
182
- If Rover cannot do what you asked, a good response from Rover is something like:
183
-
184
- - it explains the limitation clearly
185
- - it says the request was added to the wishlist
186
-
187
- If that does **not** happen, that is useful feedback for us too.
188
-
189
- ## Obsidian
190
-
191
- Obsidian is part of the pilot through the **git-synced content repo workflow**, not through MCP.
192
-
193
- That means:
194
-
195
- - use **Claude Desktop** as the main way to talk to Rover
196
- - use **Obsidian** if you want to browse, draft, and edit markdown files directly
197
- - Rover can pick up those file changes through the normal git-sync / directory-sync flow
198
-
199
- A simple mental model:
200
-
201
- - **Claude Desktop** = talk to Rover
202
- - **Obsidian** = edit the underlying notes
203
-
204
- ### Important: your content repo is private
205
-
206
- If you use the Obsidian/git workflow, you will be working in your own **private** GitHub repo.
207
-
208
- That means:
209
-
210
- - you do **not** need repo access just to use Rover through MCP
211
- - you **do** need GitHub access if you want to clone, edit, and push to your content repo
212
- - we will invite you only to **your own** content repo, not to the operator repo and not to other users' repos
213
-
214
- ### How you get access
215
-
216
- If you want the Obsidian/git workflow, we will:
217
-
218
- 1. create or confirm your private content repo
219
- 2. invite your GitHub account to that repo
220
- 3. ask you to accept the GitHub invite
221
- 4. send you the repo URL
222
-
223
- ### Easiest setup for most users
224
-
225
- The easiest path for most first-time users is:
226
-
227
- 1. install **GitHub Desktop**
228
- 2. accept the repo invite in GitHub
229
- 3. clone the private repo with GitHub Desktop
230
- 4. open the cloned folder as an Obsidian vault
231
- 5. optionally install the **Obsidian Git** plugin if you want in-app commit/push/pull support
232
- 6. edit your markdown notes
233
- 7. commit and push your changes
234
-
235
- ### Authentication options
236
-
237
- To work with a private repo, you need GitHub authentication.
238
-
239
- Usually the easiest order is:
240
-
241
- 1. **GitHub Desktop** or normal GitHub sign-in
242
- 2. **SSH key** if you already use git that way
243
- 3. a **fine-grained personal access token** only if another tool specifically requires it
244
-
245
- You do **not** need a personal access token just to use Rover through MCP.
246
-
247
- If we have already shared your content repo workflow with you, the normal setup is:
248
-
249
- 1. clone your Rover content repo locally
250
- 2. open that folder as an Obsidian vault
251
- 3. optionally install the **Obsidian Git** plugin if you want in-app commit/push/pull support
252
- 4. edit or organize your markdown notes there
253
- 5. commit and push your changes through normal git or the Obsidian Git plugin
254
- 6. let the normal git-sync flow carry those changes into Rover
255
-
256
- If we have **not** given you a direct content repo workflow yet, that is fine. You can ignore Obsidian for now and use Rover purely through MCP.
257
-
258
- ## Discord (optional)
259
-
260
- Discord is optional in this pilot.
261
-
262
- If it is enabled for you, think of it as a lightweight secondary interface for:
263
-
264
- - quick note capture
265
- - dropping in links to save
266
- - short questions when you do not want to open Claude Desktop
267
-
268
- Important:
269
-
270
- - **MCP remains the main interface**
271
- - Discord is **off by default**
272
- - if you want Discord, tell us explicitly
273
- - for this pilot, Discord-enabled users may need to supply their own bot token
274
- - if Discord is enabled, we will send the exact invite/setup steps separately
275
-
276
- If Discord is **not** enabled for you, that is completely normal.
277
-
278
- ## What to expect in the pilot
279
-
280
- This is a real working system, but it is still an early pilot.
281
-
282
- So you should expect:
283
-
284
- - some rough edges
285
- - a setup process that may still be a bit manual
286
- - a Rover that becomes more useful as you add more notes and links
287
- - occasional follow-up questions from us about your experience
288
- - improvements and changes during the pilot
289
-
290
- That is normal. The point of the pilot is to learn from real use.
291
-
292
- ## Privacy and boundaries
293
-
294
- For the pilot:
295
-
296
- - your Rover is deployed specifically for you
297
- - access to `/mcp` is protected by your Bearer token
298
- - you should avoid putting highly sensitive material into the pilot unless we have explicitly agreed that it is in scope
299
-
300
- If you are unsure whether something belongs in Rover, ask us first.
301
-
302
- ## Troubleshooting
303
-
304
- ### I opened the domain and it does not look like a normal site
305
-
306
- That is expected. In this pilot, **there is no website to browse**. Rover core is MCP-first.
307
-
308
- ### I got an authentication error
309
-
310
- Usually this means one of three things:
311
-
312
- - the Bearer token was missing
313
- - the Bearer token was pasted incorrectly
314
- - the client is using the wrong authentication type
315
-
316
- Double-check that you are using:
317
-
318
- - URL: `https://<handle>.rizom.ai/mcp`
319
- - auth type: **Bearer token**
320
- - token: exactly the token we sent you
321
-
322
- ### My MCP client says it cannot connect
323
-
324
- Some clients support local MCP servers better than remote HTTP MCP servers.
325
-
326
- If that happens, send us:
327
-
328
- - the name of the client
329
- - the version you are using
330
- - the exact error message
331
- - a screenshot if possible
332
-
333
- ## What feedback helps us most
334
-
335
- We especially want to hear:
336
-
337
- - what was confusing during setup
338
- - what felt useful immediately
339
- - what felt weak, awkward, or unclear
340
- - what you expected Rover to do but could not get it to do
341
- - whether you would keep using it after the pilot
342
-
343
- Short, honest feedback is perfect.
344
-
345
- ## Quick handoff template
346
-
347
- When we onboard you, the message will look roughly like this:
348
-
349
- ```text
350
- Rover URL: https://<handle>.rizom.ai/mcp
351
- Auth type: Bearer token
352
- Bearer token: <token>
353
- Discord enabled: yes/no
354
- ```
355
-
356
- If anything is unclear, reply with the exact error text or a screenshot and we will help.
217
+ A few plain sentences are perfect.
@@ -3,6 +3,9 @@
3
3
  "private": true,
4
4
  "type": "module",
5
5
  "packageManager": "bun@__BUN_VERSION__",
6
+ "dependencies": {
7
+ "age-encryption": "^0.3.0"
8
+ },
6
9
  "devDependencies": {
7
10
  "@rizom/ops": "__BRAINS_OPS_VERSION__"
8
11
  }
@@ -6,3 +6,6 @@ contentRepoPrefix: rover-
6
6
  domainSuffix: .rizom.ai
7
7
  preset: core
8
8
  aiApiKey: AI_API_KEY
9
+ gitSyncToken: GIT_SYNC_TOKEN
10
+ contentRepoAdminToken: CONTENT_REPO_ADMIN_TOKEN
11
+ agePublicKey: age1replace-with-your-public-key
@@ -3,4 +3,5 @@ anchorProfile:
3
3
  name: Alice Example
4
4
  description: Replace this with Alice's real public profile summary.
5
5
  discord:
6
- enabled: false
6
+ enabled: true
7
+ # anchorUserId: "123456789012345678"
@@ -1,6 +0,0 @@
1
- export interface UserSecretNames {
2
- gitSyncTokenSecretName: string;
3
- mcpAuthTokenSecretName: string;
4
- discordBotTokenSecretName: string;
5
- }
6
- export declare function deriveUserSecretNames(handle: string): UserSecretNames;
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- BRAIN_FILE="${BRAIN_YAML_PATH:-brain.yaml}"
5
- SSH_USER="$(ruby -e 'require "yaml"; config = YAML.load_file("deploy/kamal/deploy.yml") || {}; puts(config.dig("ssh", "user") || "root")')"
6
- IFS=',' read -ra HOSTS <<< "$KAMAL_HOSTS"
7
- for host in "${HOSTS[@]}"; do
8
- scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$BRAIN_FILE" "${SSH_USER}@${host}:/opt/brain.yaml"
9
- done
@@ -1,72 +0,0 @@
1
- # Internal Caddy — path-based routing to brain services.
2
- # kamal-proxy terminates TLS externally; this runs inside the container.
3
- :80 {
4
- @preview host preview.*
5
- handle @preview {
6
- reverse_proxy localhost:4321
7
-
8
- header {
9
- X-Frame-Options "SAMEORIGIN"
10
- X-Content-Type-Options "nosniff"
11
- Referrer-Policy "strict-origin-when-cross-origin"
12
- }
13
- }
14
-
15
- # Health endpoint
16
- handle /health {
17
- reverse_proxy localhost:3333
18
- }
19
-
20
- # MCP endpoint
21
- handle /mcp* {
22
- reverse_proxy localhost:3333
23
-
24
- header {
25
- X-Content-Type-Options "nosniff"
26
- Access-Control-Allow-Origin "*"
27
- Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS"
28
- Access-Control-Allow-Headers "Content-Type, Authorization, MCP-Session-Id"
29
- }
30
- }
31
-
32
- # A2A endpoints
33
- handle /.well-known/agent-card.json {
34
- reverse_proxy localhost:3334
35
- }
36
-
37
- handle /a2a {
38
- reverse_proxy localhost:3334
39
-
40
- header {
41
- X-Content-Type-Options "nosniff"
42
- Access-Control-Allow-Origin "*"
43
- Access-Control-Allow-Methods "GET, POST, OPTIONS"
44
- Access-Control-Allow-Headers "Content-Type, Authorization"
45
- }
46
- }
47
-
48
- # Plugin API routes
49
- handle /api/* {
50
- reverse_proxy localhost:3335
51
- }
52
-
53
- @root path /
54
- handle @root {
55
- redir /.well-known/agent-card.json 302
56
- }
57
-
58
- # Production site: prefer the webserver when present; otherwise fall back
59
- # to the A2A interface so core-only deployments never return a bare 502.
60
- handle {
61
- reverse_proxy localhost:8080 localhost:3334 {
62
- lb_policy first
63
- lb_retries 1
64
- }
65
-
66
- header {
67
- X-Frame-Options "SAMEORIGIN"
68
- X-Content-Type-Options "nosniff"
69
- Referrer-Policy "strict-origin-when-cross-origin"
70
- }
71
- }
72
- }