mercury-agent 0.4.28 → 0.5.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 +451 -451
- package/container/Dockerfile +127 -127
- package/container/Dockerfile.base +109 -109
- package/container/Dockerfile.power +17 -17
- package/container/agent-package.json +8 -8
- package/container/build.sh +54 -54
- package/docs/ARCHITECTURE.md +4 -0
- package/docs/ROADMAP.md +4 -5
- package/docs/{backlog/applicative-profiles.md → archive/applicative-profiles/2026-07-01-applicative-profiles.md} +29 -18
- package/docs/{backlog/caller-bound-capability-token.md → archive/applicative-profiles/2026-07-01-caller-bound-capability-token.md} +15 -11
- package/docs/archive/summarization/2026-07-02-recent-dev-summary.md +71 -0
- package/docs/auth/dashboard.md +28 -28
- package/docs/auth/overview.md +109 -109
- package/docs/auth/whatsapp.md +173 -173
- package/docs/authoring-profiles.md +174 -0
- package/docs/configuration.md +54 -54
- package/docs/container-lifecycle.md +349 -349
- package/docs/{bugs/bwrap-privileged-linux-docker.md → debug/major/2026-07-02-bwrap-privileged-linux-docker.md} +21 -1
- package/docs/{bugs/e2big-prompt-delivery-fix.md → debug/major/2026-07-02-e2big-prompt-delivery-fix.md} +27 -1
- package/docs/{bugs/registry-pull-no-local-fallback.md → debug/major/2026-07-02-registry-pull-no-local-fallback.md} +27 -1
- package/docs/debug/summarization/2026-07-02-common-bug-patterns.md +72 -0
- package/docs/deployment.md +199 -199
- package/docs/extensions.md +375 -375
- package/docs/graceful-shutdown.md +62 -62
- package/docs/kb-distillation.md +77 -77
- package/docs/media/overview.md +140 -140
- package/docs/media/whatsapp.md +171 -171
- package/docs/memory.md +137 -137
- package/docs/permissions.md +217 -217
- package/docs/pipeline.md +228 -228
- package/docs/prd-chat-memory.md +76 -76
- package/docs/prd-config-load.md +82 -82
- package/docs/rate-limiting.md +229 -229
- package/docs/scheduler.md +288 -288
- package/docs/setup-discord.md +100 -100
- package/docs/setup-slack.md +119 -119
- package/docs/setup-whatsapp.md +94 -94
- package/docs/subagents.md +166 -166
- package/docs/web-search.md +62 -62
- package/examples/extensions/README.md +12 -12
- package/examples/extensions/charts/index.ts +13 -13
- package/examples/extensions/charts/skill/SKILL.md +98 -98
- package/examples/extensions/gws/README.md +52 -52
- package/examples/extensions/gws/skill/SKILL.md +57 -57
- package/examples/extensions/gws/skill/references/calendar.md +101 -101
- package/examples/extensions/gws/skill/references/docs.md +65 -65
- package/examples/extensions/gws/skill/references/drive.md +79 -79
- package/examples/extensions/gws/skill/references/gmail.md +85 -85
- package/examples/extensions/gws/skill/references/sheets.md +60 -60
- package/examples/extensions/napkin/skill/SKILL.md +728 -728
- package/examples/extensions/pdf/skill/LICENSE.txt +30 -30
- package/examples/extensions/pdf/skill/SKILL.md +314 -314
- package/examples/extensions/pdf/skill/forms.md +294 -294
- package/examples/extensions/pdf/skill/reference.md +611 -611
- package/examples/extensions/pdf/skill/scripts/check_bounding_boxes.py +65 -65
- package/examples/extensions/pdf/skill/scripts/check_fillable_fields.py +11 -11
- package/examples/extensions/pdf/skill/scripts/convert_pdf_to_images.py +33 -33
- package/examples/extensions/pdf/skill/scripts/create_validation_image.py +37 -37
- package/examples/extensions/pdf/skill/scripts/extract_form_field_info.py +122 -122
- package/examples/extensions/pdf/skill/scripts/extract_form_structure.py +115 -115
- package/examples/extensions/pdf/skill/scripts/fill_fillable_fields.py +98 -98
- package/examples/extensions/pdf/skill/scripts/fill_pdf_form_with_annotations.py +107 -107
- package/examples/extensions/permission-guard/index.ts +65 -65
- package/examples/extensions/pinchtab/skill/SKILL.md +224 -224
- package/examples/extensions/pinchtab/skill/TRUST.md +69 -69
- package/examples/extensions/pinchtab/skill/references/api.md +297 -297
- package/examples/extensions/pinchtab/skill/references/env.md +45 -45
- package/examples/extensions/pinchtab/skill/references/profiles.md +107 -107
- package/examples/extensions/tradestation/host/refresh.ts +102 -102
- package/examples/extensions/tradestation/index.ts +153 -153
- package/examples/extensions/tradestation/skill/SKILL.md +67 -67
- package/examples/extensions/voice-synth/index.ts +94 -94
- package/examples/extensions/voice-synth/skill/SKILL.md +38 -38
- package/examples/extensions/voice-transcribe/requirements.txt +8 -8
- package/examples/extensions/voice-transcribe/scripts/transcribe.py +179 -179
- package/examples/extensions/voice-transcribe/skill/SKILL.md +53 -53
- package/examples/extensions/yahoo-mail/cli/package.json +13 -13
- package/examples/extensions/yahoo-mail/skill/SKILL.md +78 -78
- package/package.json +106 -106
- package/resources/agents/explore.md +50 -50
- package/resources/agents/worker.md +24 -24
- package/resources/connection-env-vars.json +25 -25
- package/resources/pi-extensions/subagent/agents.ts +126 -126
- package/resources/pi-extensions/subagent/index.ts +964 -964
- package/resources/profiles/coding/AGENTS.md +43 -43
- package/resources/profiles/coding/mercury-profile.yaml +15 -15
- package/resources/profiles/general/AGENTS.md +31 -31
- package/resources/profiles/general/mercury-profile.yaml +15 -15
- package/resources/profiles/research/AGENTS.md +40 -40
- package/resources/profiles/research/mercury-profile.yaml +15 -15
- package/resources/skills/config/SKILL.md +25 -25
- package/resources/skills/context/SKILL.md +33 -33
- package/resources/skills/conversation-recap/SKILL.md +19 -19
- package/resources/skills/mutes/SKILL.md +31 -31
- package/resources/skills/permissions/SKILL.md +19 -19
- package/resources/skills/preferences/SKILL.md +31 -31
- package/resources/skills/recall/SKILL.md +24 -24
- package/resources/skills/roles/SKILL.md +18 -18
- package/resources/skills/spaces/SKILL.md +18 -18
- package/resources/skills/tasks/SKILL.md +45 -45
- package/resources/templates/AGENTS.md +157 -157
- package/resources/templates/env.template +38 -38
- package/resources/templates/mercury.example.yaml +15 -0
- package/src/agent/container-runner.ts +23 -0
- package/src/cli/mercury.ts +38 -6
- package/src/cli/mrctl.ts +25 -0
- package/src/config-file.ts +3 -0
- package/src/config.ts +15 -0
- package/src/core/api.ts +23 -3
- package/src/core/caller-token.ts +101 -0
- package/src/core/permissions.ts +37 -5
- package/src/core/profiles.ts +110 -84
- package/src/core/routes/capability.ts +70 -0
- package/src/core/routes/index.ts +1 -0
- package/src/core/runtime.ts +14 -0
- package/src/dashboard/index.html +729 -729
- package/src/extensions/api.ts +21 -0
- package/src/extensions/loader.ts +15 -0
- package/src/extensions/types.ts +55 -0
- package/src/main.ts +19 -0
- package/docs/pending-updates/dm-auto-space.md +0 -15
- /package/docs/archive/{2026-07-01-dm-auto-space.md → applicative-profiles/2026-07-01-dm-auto-space.md} +0 -0
package/docs/auth/whatsapp.md
CHANGED
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
# WhatsApp Authentication
|
|
2
|
-
|
|
3
|
-
Mercury connects to WhatsApp using the [Baileys](https://github.com/WhiskeySockets/Baileys) library, which implements the WhatsApp Web protocol. This means you need to link your WhatsApp account just like you would link WhatsApp Web.
|
|
4
|
-
|
|
5
|
-
## Initial Setup
|
|
6
|
-
|
|
7
|
-
### QR Code Mode (Recommended)
|
|
8
|
-
|
|
9
|
-
The simplest way to authenticate:
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
mercury auth whatsapp
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
This will:
|
|
16
|
-
1. Display a QR code in your terminal
|
|
17
|
-
2. Wait for you to scan it with WhatsApp
|
|
18
|
-
3. Save credentials to `.mercury/whatsapp-auth/`
|
|
19
|
-
4. Exit when authentication is complete
|
|
20
|
-
|
|
21
|
-
**To scan:**
|
|
22
|
-
1. Open WhatsApp on your phone
|
|
23
|
-
2. Tap **Settings → Linked Devices → Link a Device**
|
|
24
|
-
3. Point your camera at the QR code
|
|
25
|
-
|
|
26
|
-
### Pairing Code Mode
|
|
27
|
-
|
|
28
|
-
If you can't scan QR codes (e.g., running on a remote server), use pairing code mode:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
mercury auth whatsapp --pairing-code --phone 14155551234
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Replace `14155551234` with your phone number (country code + number, no `+` or spaces).
|
|
35
|
-
|
|
36
|
-
This will:
|
|
37
|
-
1. Request a pairing code from WhatsApp
|
|
38
|
-
2. Display an 8-character code
|
|
39
|
-
3. Wait for you to enter it on your phone
|
|
40
|
-
|
|
41
|
-
**To pair:**
|
|
42
|
-
1. Open WhatsApp on your phone
|
|
43
|
-
2. Tap **Settings → Linked Devices → Link a Device**
|
|
44
|
-
3. Tap **"Link with phone number instead"**
|
|
45
|
-
4. Enter the code shown in your terminal
|
|
46
|
-
|
|
47
|
-
## Session Lifecycle
|
|
48
|
-
|
|
49
|
-
### Session Duration
|
|
50
|
-
|
|
51
|
-
WhatsApp linked device sessions typically last **~14-20 days** before requiring re-authentication. This is controlled by WhatsApp, not Mercury.
|
|
52
|
-
|
|
53
|
-
Signs your session has expired:
|
|
54
|
-
- WhatsApp stops receiving messages
|
|
55
|
-
- Logs show `connection closed` with `loggedOut` reason
|
|
56
|
-
- Status file shows `failed:logged_out`
|
|
57
|
-
|
|
58
|
-
### Re-authentication
|
|
59
|
-
|
|
60
|
-
If your session expires:
|
|
61
|
-
|
|
62
|
-
1. **Stop Mercury** (if running):
|
|
63
|
-
```bash
|
|
64
|
-
# Ctrl+C in the terminal running mercury, or
|
|
65
|
-
pkill -f "bun.*chat-sdk"
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
2. **Delete old credentials**:
|
|
69
|
-
```bash
|
|
70
|
-
rm -rf .mercury/whatsapp-auth/
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
3. **Re-authenticate**:
|
|
74
|
-
```bash
|
|
75
|
-
mercury auth whatsapp
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
4. **Restart Mercury**:
|
|
79
|
-
```bash
|
|
80
|
-
mercury run
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Status Files
|
|
84
|
-
|
|
85
|
-
The auth script writes status files for external monitoring (useful for headless deployments):
|
|
86
|
-
|
|
87
|
-
| File | Description |
|
|
88
|
-
|------|-------------|
|
|
89
|
-
| `.mercury/whatsapp-status.txt` | Current status (`authenticated`, `waiting_qr`, `pairing_code:XXXX`, `failed:reason`) |
|
|
90
|
-
| `.mercury/whatsapp-qr.txt` | Raw QR data for external rendering (deleted after successful auth) |
|
|
91
|
-
|
|
92
|
-
### Status Values
|
|
93
|
-
|
|
94
|
-
- `authenticated` — Successfully connected
|
|
95
|
-
- `already_authenticated` — Existing valid session found
|
|
96
|
-
- `waiting_qr` — Waiting for QR code scan
|
|
97
|
-
- `pairing_code:XXXXXXXX` — Waiting for pairing code entry
|
|
98
|
-
- `failed:logged_out` — Session was logged out by WhatsApp
|
|
99
|
-
- `failed:qr_timeout` — QR code expired before scan
|
|
100
|
-
- `failed:515` — Stream error (usually recovers automatically)
|
|
101
|
-
- `failed:unknown` — Other connection failure
|
|
102
|
-
|
|
103
|
-
## Auth Status API Endpoint
|
|
104
|
-
|
|
105
|
-
When Mercury is running, you can check auth status via the API:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
curl http://localhost:8787/auth/whatsapp
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
**Responses:**
|
|
112
|
-
|
|
113
|
-
```json
|
|
114
|
-
// Authenticated and connected
|
|
115
|
-
{ "status": "authenticated" }
|
|
116
|
-
|
|
117
|
-
// Waiting for QR scan (includes raw QR data)
|
|
118
|
-
{ "status": "waiting", "qr": "2@AbCdEf123..." }
|
|
119
|
-
|
|
120
|
-
// Disconnected or not yet connected
|
|
121
|
-
{ "status": "disconnected" }
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
This endpoint requires no authentication, making it suitable for headless monitoring dashboards.
|
|
125
|
-
|
|
126
|
-
## Troubleshooting
|
|
127
|
-
|
|
128
|
-
### "Already authenticated"
|
|
129
|
-
|
|
130
|
-
If you see this but WhatsApp isn't working:
|
|
131
|
-
```bash
|
|
132
|
-
rm -rf .mercury/whatsapp-auth/
|
|
133
|
-
mercury auth whatsapp
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### QR code times out too quickly
|
|
137
|
-
|
|
138
|
-
WhatsApp QR codes expire after ~20 seconds. If you're having trouble:
|
|
139
|
-
1. Have your phone ready before running the command
|
|
140
|
-
2. Use `--pairing-code` mode instead
|
|
141
|
-
|
|
142
|
-
### "Stream error (515)"
|
|
143
|
-
|
|
144
|
-
This is usually transient and the auth script will automatically reconnect. If it persists:
|
|
145
|
-
```bash
|
|
146
|
-
rm -rf .mercury/whatsapp-auth/
|
|
147
|
-
mercury auth whatsapp
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### WhatsApp shows "Linked Device" but Mercury doesn't receive messages
|
|
151
|
-
|
|
152
|
-
1. Check that `MERCURY_ENABLE_WHATSAPP=true` is set in `.env`
|
|
153
|
-
2. Check logs for connection errors
|
|
154
|
-
3. Try re-authenticating
|
|
155
|
-
|
|
156
|
-
### Messages from before startup appear
|
|
157
|
-
|
|
158
|
-
Mercury ignores messages that were sent before it connected to prevent processing old backlog. This is intentional.
|
|
159
|
-
|
|
160
|
-
## Environment Variables
|
|
161
|
-
|
|
162
|
-
| Variable | Default | Description |
|
|
163
|
-
|----------|---------|-------------|
|
|
164
|
-
| `MERCURY_ENABLE_WHATSAPP` | `false` | Enable WhatsApp adapter |
|
|
165
|
-
| `MERCURY_WHATSAPP_AUTH_DIR` | `.mercury/whatsapp-auth` | Directory for auth credentials |
|
|
166
|
-
| `MERCURY_DATA_DIR` | `.mercury` | Base data directory (auth dir is relative to this) |
|
|
167
|
-
|
|
168
|
-
## Security Notes
|
|
169
|
-
|
|
170
|
-
- Auth credentials in `.mercury/whatsapp-auth/` are sensitive — treat them like passwords
|
|
171
|
-
- Anyone with access to these files can impersonate your WhatsApp account
|
|
172
|
-
- The `/auth/whatsapp` endpoint is unauthenticated — only expose your API port to trusted networks
|
|
173
|
-
- Consider using a dedicated WhatsApp number for your bot
|
|
1
|
+
# WhatsApp Authentication
|
|
2
|
+
|
|
3
|
+
Mercury connects to WhatsApp using the [Baileys](https://github.com/WhiskeySockets/Baileys) library, which implements the WhatsApp Web protocol. This means you need to link your WhatsApp account just like you would link WhatsApp Web.
|
|
4
|
+
|
|
5
|
+
## Initial Setup
|
|
6
|
+
|
|
7
|
+
### QR Code Mode (Recommended)
|
|
8
|
+
|
|
9
|
+
The simplest way to authenticate:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
mercury auth whatsapp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This will:
|
|
16
|
+
1. Display a QR code in your terminal
|
|
17
|
+
2. Wait for you to scan it with WhatsApp
|
|
18
|
+
3. Save credentials to `.mercury/whatsapp-auth/`
|
|
19
|
+
4. Exit when authentication is complete
|
|
20
|
+
|
|
21
|
+
**To scan:**
|
|
22
|
+
1. Open WhatsApp on your phone
|
|
23
|
+
2. Tap **Settings → Linked Devices → Link a Device**
|
|
24
|
+
3. Point your camera at the QR code
|
|
25
|
+
|
|
26
|
+
### Pairing Code Mode
|
|
27
|
+
|
|
28
|
+
If you can't scan QR codes (e.g., running on a remote server), use pairing code mode:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
mercury auth whatsapp --pairing-code --phone 14155551234
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Replace `14155551234` with your phone number (country code + number, no `+` or spaces).
|
|
35
|
+
|
|
36
|
+
This will:
|
|
37
|
+
1. Request a pairing code from WhatsApp
|
|
38
|
+
2. Display an 8-character code
|
|
39
|
+
3. Wait for you to enter it on your phone
|
|
40
|
+
|
|
41
|
+
**To pair:**
|
|
42
|
+
1. Open WhatsApp on your phone
|
|
43
|
+
2. Tap **Settings → Linked Devices → Link a Device**
|
|
44
|
+
3. Tap **"Link with phone number instead"**
|
|
45
|
+
4. Enter the code shown in your terminal
|
|
46
|
+
|
|
47
|
+
## Session Lifecycle
|
|
48
|
+
|
|
49
|
+
### Session Duration
|
|
50
|
+
|
|
51
|
+
WhatsApp linked device sessions typically last **~14-20 days** before requiring re-authentication. This is controlled by WhatsApp, not Mercury.
|
|
52
|
+
|
|
53
|
+
Signs your session has expired:
|
|
54
|
+
- WhatsApp stops receiving messages
|
|
55
|
+
- Logs show `connection closed` with `loggedOut` reason
|
|
56
|
+
- Status file shows `failed:logged_out`
|
|
57
|
+
|
|
58
|
+
### Re-authentication
|
|
59
|
+
|
|
60
|
+
If your session expires:
|
|
61
|
+
|
|
62
|
+
1. **Stop Mercury** (if running):
|
|
63
|
+
```bash
|
|
64
|
+
# Ctrl+C in the terminal running mercury, or
|
|
65
|
+
pkill -f "bun.*chat-sdk"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
2. **Delete old credentials**:
|
|
69
|
+
```bash
|
|
70
|
+
rm -rf .mercury/whatsapp-auth/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
3. **Re-authenticate**:
|
|
74
|
+
```bash
|
|
75
|
+
mercury auth whatsapp
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
4. **Restart Mercury**:
|
|
79
|
+
```bash
|
|
80
|
+
mercury run
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Status Files
|
|
84
|
+
|
|
85
|
+
The auth script writes status files for external monitoring (useful for headless deployments):
|
|
86
|
+
|
|
87
|
+
| File | Description |
|
|
88
|
+
|------|-------------|
|
|
89
|
+
| `.mercury/whatsapp-status.txt` | Current status (`authenticated`, `waiting_qr`, `pairing_code:XXXX`, `failed:reason`) |
|
|
90
|
+
| `.mercury/whatsapp-qr.txt` | Raw QR data for external rendering (deleted after successful auth) |
|
|
91
|
+
|
|
92
|
+
### Status Values
|
|
93
|
+
|
|
94
|
+
- `authenticated` — Successfully connected
|
|
95
|
+
- `already_authenticated` — Existing valid session found
|
|
96
|
+
- `waiting_qr` — Waiting for QR code scan
|
|
97
|
+
- `pairing_code:XXXXXXXX` — Waiting for pairing code entry
|
|
98
|
+
- `failed:logged_out` — Session was logged out by WhatsApp
|
|
99
|
+
- `failed:qr_timeout` — QR code expired before scan
|
|
100
|
+
- `failed:515` — Stream error (usually recovers automatically)
|
|
101
|
+
- `failed:unknown` — Other connection failure
|
|
102
|
+
|
|
103
|
+
## Auth Status API Endpoint
|
|
104
|
+
|
|
105
|
+
When Mercury is running, you can check auth status via the API:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
curl http://localhost:8787/auth/whatsapp
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Responses:**
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
// Authenticated and connected
|
|
115
|
+
{ "status": "authenticated" }
|
|
116
|
+
|
|
117
|
+
// Waiting for QR scan (includes raw QR data)
|
|
118
|
+
{ "status": "waiting", "qr": "2@AbCdEf123..." }
|
|
119
|
+
|
|
120
|
+
// Disconnected or not yet connected
|
|
121
|
+
{ "status": "disconnected" }
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This endpoint requires no authentication, making it suitable for headless monitoring dashboards.
|
|
125
|
+
|
|
126
|
+
## Troubleshooting
|
|
127
|
+
|
|
128
|
+
### "Already authenticated"
|
|
129
|
+
|
|
130
|
+
If you see this but WhatsApp isn't working:
|
|
131
|
+
```bash
|
|
132
|
+
rm -rf .mercury/whatsapp-auth/
|
|
133
|
+
mercury auth whatsapp
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### QR code times out too quickly
|
|
137
|
+
|
|
138
|
+
WhatsApp QR codes expire after ~20 seconds. If you're having trouble:
|
|
139
|
+
1. Have your phone ready before running the command
|
|
140
|
+
2. Use `--pairing-code` mode instead
|
|
141
|
+
|
|
142
|
+
### "Stream error (515)"
|
|
143
|
+
|
|
144
|
+
This is usually transient and the auth script will automatically reconnect. If it persists:
|
|
145
|
+
```bash
|
|
146
|
+
rm -rf .mercury/whatsapp-auth/
|
|
147
|
+
mercury auth whatsapp
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### WhatsApp shows "Linked Device" but Mercury doesn't receive messages
|
|
151
|
+
|
|
152
|
+
1. Check that `MERCURY_ENABLE_WHATSAPP=true` is set in `.env`
|
|
153
|
+
2. Check logs for connection errors
|
|
154
|
+
3. Try re-authenticating
|
|
155
|
+
|
|
156
|
+
### Messages from before startup appear
|
|
157
|
+
|
|
158
|
+
Mercury ignores messages that were sent before it connected to prevent processing old backlog. This is intentional.
|
|
159
|
+
|
|
160
|
+
## Environment Variables
|
|
161
|
+
|
|
162
|
+
| Variable | Default | Description |
|
|
163
|
+
|----------|---------|-------------|
|
|
164
|
+
| `MERCURY_ENABLE_WHATSAPP` | `false` | Enable WhatsApp adapter |
|
|
165
|
+
| `MERCURY_WHATSAPP_AUTH_DIR` | `.mercury/whatsapp-auth` | Directory for auth credentials |
|
|
166
|
+
| `MERCURY_DATA_DIR` | `.mercury` | Base data directory (auth dir is relative to this) |
|
|
167
|
+
|
|
168
|
+
## Security Notes
|
|
169
|
+
|
|
170
|
+
- Auth credentials in `.mercury/whatsapp-auth/` are sensitive — treat them like passwords
|
|
171
|
+
- Anyone with access to these files can impersonate your WhatsApp account
|
|
172
|
+
- The `/auth/whatsapp` endpoint is unauthenticated — only expose your API port to trusted networks
|
|
173
|
+
- Consider using a dedicated WhatsApp number for your bot
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Authoring Applicative Profiles
|
|
2
|
+
|
|
3
|
+
The contract for building a **profile** — a package of deterministic business
|
|
4
|
+
logic that wraps raw capabilities (Calendar, email, …) and scopes what members
|
|
5
|
+
can do. Mercury (this repo) provides the schema, loader, permission scoping, and
|
|
6
|
+
the host-side capability broker; **profiles live in a separate repo** and depend
|
|
7
|
+
only on this contract.
|
|
8
|
+
|
|
9
|
+
> Layers: **Mercury** = platform (messaging, spaces, permissions, tokens,
|
|
10
|
+
> broker). **Capability extensions** = raw API access (e.g. `gws`), admin-only.
|
|
11
|
+
> **Profiles** = deterministic domain logic wrapping capabilities, member-facing.
|
|
12
|
+
|
|
13
|
+
## 1. Profile manifest — `mercury-profile.yaml`
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
name: barber-appointments # lowercase-kebab; required
|
|
17
|
+
description: Appointment booking for a barber shop
|
|
18
|
+
version: 0.1.0
|
|
19
|
+
|
|
20
|
+
agents_md: ./AGENTS.md # optional; copied to the global AGENTS.md
|
|
21
|
+
|
|
22
|
+
# Raw capability extensions this profile requires to be installed. Validated at
|
|
23
|
+
# apply time — activation fails loudly if any are missing.
|
|
24
|
+
capabilities:
|
|
25
|
+
- gws
|
|
26
|
+
|
|
27
|
+
# Extensions this profile ships (copied into .mercury/extensions).
|
|
28
|
+
extensions:
|
|
29
|
+
- name: barber
|
|
30
|
+
source: ./extensions/barber
|
|
31
|
+
|
|
32
|
+
# EXHAUSTIVE member permission set while active. When present it REPLACES the
|
|
33
|
+
# default member permissions — nothing is merged in — so raw capabilities stay
|
|
34
|
+
# admin-only unless listed here. Omit entirely to keep built-in defaults.
|
|
35
|
+
member_permissions:
|
|
36
|
+
- prompt
|
|
37
|
+
- prefs.get
|
|
38
|
+
- barber # the profile's own capability, NOT gws
|
|
39
|
+
|
|
40
|
+
# Optional env the profile needs (host-side credentials for capabilities).
|
|
41
|
+
env:
|
|
42
|
+
- key: MERCURY_BARBER_BUSINESS_HOURS
|
|
43
|
+
description: "Business hours"
|
|
44
|
+
default: "09:00-18:00"
|
|
45
|
+
|
|
46
|
+
# Project-wide agent persona, injected into every container's system prompt.
|
|
47
|
+
system_prompt: |
|
|
48
|
+
You are a barber shop assistant. Help each customer book, view, and cancel
|
|
49
|
+
ONLY their own appointments. Never reveal other customers' schedules.
|
|
50
|
+
|
|
51
|
+
defaults:
|
|
52
|
+
trigger_patterns: always
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Apply it with `mercury profile apply <name|path|git-url>`. That validates
|
|
56
|
+
capabilities, copies extensions/AGENTS.md, and persists activation to
|
|
57
|
+
`.mercury/active-profile.json`, which Mercury loads at startup.
|
|
58
|
+
|
|
59
|
+
## 2. The capability broker (where the business logic runs)
|
|
60
|
+
|
|
61
|
+
A profile's privileged work runs **on the host**, so credentials never enter the
|
|
62
|
+
customer-controlled agent container. The profile's extension registers a
|
|
63
|
+
handler; the agent invokes it through a thin CLI.
|
|
64
|
+
|
|
65
|
+
### Register a handler (in the extension's `index.ts`)
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import type { ExtensionSetupFn } from "mercury-agent"; // types from this repo
|
|
69
|
+
|
|
70
|
+
const setup: ExtensionSetupFn = (mercury) => {
|
|
71
|
+
// Make the capability gate-able. Members get it via member_permissions.
|
|
72
|
+
mercury.permission({ defaultRoles: [] });
|
|
73
|
+
|
|
74
|
+
// Host-side credentials for the wrapped capability (never sent to the container).
|
|
75
|
+
mercury.env({ from: "MERCURY_BARBER_GOOGLE_CREDENTIALS" });
|
|
76
|
+
|
|
77
|
+
mercury.capability("barber", async (req, ctx) => {
|
|
78
|
+
// req.callerId is the TOKEN-DERIVED, unspoofable caller — safe for ownership.
|
|
79
|
+
switch (req.action) {
|
|
80
|
+
case "availability":
|
|
81
|
+
return { data: await listOpenSlots(req.body, ctx) };
|
|
82
|
+
case "book":
|
|
83
|
+
return { data: await book(req.callerId, req.body, ctx) };
|
|
84
|
+
case "cancel":
|
|
85
|
+
return { data: await cancelOwn(req.callerId, req.body, ctx) };
|
|
86
|
+
case "my-appointments":
|
|
87
|
+
return { data: await listOwn(req.callerId, ctx) };
|
|
88
|
+
default:
|
|
89
|
+
return { status: 400, data: { error: `unknown action: ${req.action}` } };
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export default setup;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### The contract types (exported from this repo)
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
type CapabilityHandler = (
|
|
101
|
+
req: CapabilityRequest,
|
|
102
|
+
ctx: MercuryExtensionContext,
|
|
103
|
+
) => Promise<CapabilityResult>;
|
|
104
|
+
|
|
105
|
+
interface CapabilityRequest {
|
|
106
|
+
name: string; // capability name
|
|
107
|
+
action: string; // sub-action (book, cancel, …)
|
|
108
|
+
callerId: string; // token-derived, TRUSTWORTHY — use for ownership checks
|
|
109
|
+
spaceId: string;
|
|
110
|
+
body: unknown; // parsed JSON request body (or null)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface CapabilityResult {
|
|
114
|
+
status?: number; // default 200
|
|
115
|
+
data: unknown; // JSON-serializable response
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`ctx` (`MercuryExtensionContext`) gives you `db`, `config`, `log`, and
|
|
120
|
+
`hasCallerPermission(spaceId, callerId, permission)`. Store per-profile state via
|
|
121
|
+
`mercury.store` (namespaced KV) or your own tables through `ctx.db`.
|
|
122
|
+
|
|
123
|
+
### How the agent invokes it
|
|
124
|
+
|
|
125
|
+
Inside the container the agent runs:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
mrctl capability barber book '{"slot":"2026-07-02T15:00"}'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
→ `POST /api/capability/barber/book`. Document these commands for the agent in
|
|
132
|
+
the extension's `SKILL.md` or the profile's `AGENTS.md`.
|
|
133
|
+
|
|
134
|
+
## 3. Permission & security model (non-negotiable)
|
|
135
|
+
|
|
136
|
+
- **`member_permissions` is exhaustive.** List every permission a member may
|
|
137
|
+
hold, including the capability name (e.g. `barber`). Anything not listed —
|
|
138
|
+
including raw capabilities like `gws` — is unavailable to members.
|
|
139
|
+
- **Authorization = permission named after the capability.** The broker route
|
|
140
|
+
requires the caller to hold the `<name>` permission; the same grant gates both
|
|
141
|
+
the `mrctl capability <name> …` CLI and the route. Keep capability name ==
|
|
142
|
+
permission name == the entry in `member_permissions`.
|
|
143
|
+
- **Credentials stay on the host.** Put capability credentials in host env
|
|
144
|
+
(`mercury.env`) / `mercury.store` and use them only inside the handler. Never
|
|
145
|
+
expose a raw capability CLI (e.g. `gws`) to members — its secret would be
|
|
146
|
+
readable inside the container.
|
|
147
|
+
- **Enforce ownership with `req.callerId`.** It is token-derived and cannot be
|
|
148
|
+
spoofed by the container. Never trust an id passed in `req.body`.
|
|
149
|
+
- **`callerId === "system"`** for scheduled/system runs — handle it explicitly
|
|
150
|
+
(e.g. skip per-customer ownership).
|
|
151
|
+
|
|
152
|
+
## 4. Suggested profile repo layout
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
<profile-repo>/
|
|
156
|
+
barber/ # one folder per profile
|
|
157
|
+
mercury-profile.yaml
|
|
158
|
+
AGENTS.md
|
|
159
|
+
extensions/
|
|
160
|
+
barber/
|
|
161
|
+
index.ts # registers permission + capability
|
|
162
|
+
package.json
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Depend on this repo (`mercury-agent`) for the types
|
|
166
|
+
(`ExtensionSetupFn`, `CapabilityRequest`, `CapabilityResult`,
|
|
167
|
+
`MercuryExtensionContext`). See `src/extensions/types.ts` for the full surface.
|
|
168
|
+
|
|
169
|
+
## 5. Local test loop
|
|
170
|
+
|
|
171
|
+
1. `mercury profile apply ./barber`
|
|
172
|
+
2. `mercury service install` (builds the derived image with the extension CLI)
|
|
173
|
+
3. DM the bot as a non-admin number; confirm you can `book`/`cancel` only your
|
|
174
|
+
own appointments and cannot reach `gws`/Gmail.
|
package/docs/configuration.md
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
# Configuration
|
|
2
|
-
|
|
3
|
-
Mercury reads settings from **environment variables** (`MERCURY_*`) and, optionally, a project **`mercury.yaml`** file in the current working directory.
|
|
4
|
-
|
|
5
|
-
**Product / design spec:** [prd-config-load.md](prd-config-load.md) (config load: YAML + env precedence, security, non-goals).
|
|
6
|
-
|
|
7
|
-
## Precedence
|
|
8
|
-
|
|
9
|
-
1. If a `MERCURY_*` variable is **set** in the environment (the key exists, including empty string), its value wins.
|
|
10
|
-
2. Otherwise, if **`mercury.yaml`** (or **`mercury.yml`**) exists in `cwd`, values from that file apply.
|
|
11
|
-
3. Otherwise, built-in defaults from `config.ts` apply.
|
|
12
|
-
|
|
13
|
-
Set **`MERCURY_CONFIG_FILE`** to an explicit path to load a different file. Set it to **`""`** (empty) or **`none`** to **disable** loading any file (useful for tests or when you want env/defaults only).
|
|
14
|
-
|
|
15
|
-
Relative paths in `MERCURY_CONFIG_FILE` are resolved against `cwd`.
|
|
16
|
-
|
|
17
|
-
## Secrets (never use `mercury.yaml` for these)
|
|
18
|
-
|
|
19
|
-
These must be supplied via environment variables only; they are **not** read from YAML:
|
|
20
|
-
|
|
21
|
-
- `MERCURY_API_SECRET`
|
|
22
|
-
- `MERCURY_CHAT_API_KEY`
|
|
23
|
-
- `MERCURY_DISCORD_GATEWAY_SECRET`
|
|
24
|
-
|
|
25
|
-
Platform tokens, provider API keys, and extension keys (e.g. `MERCURY_TELEGRAM_BOT_TOKEN`, `MERCURY_BRAVE_API_KEY`) are also **env-only** today—they are not part of the YAML schema.
|
|
26
|
-
|
|
27
|
-
## YAML layout
|
|
28
|
-
|
|
29
|
-
See [`resources/templates/mercury.example.yaml`](../resources/templates/mercury.example.yaml) for a commented template. Supported sections include `server`, `model`, `ingress`, `runtime`, `trigger`, `context`, `conditional_context`, `compaction`, `agent`, `discord`, `telegram`, `media`, and `permissions`.
|
|
30
|
-
|
|
31
|
-
The `context:` block seeds default conversation-context behavior into the `main` space on first boot:
|
|
32
|
-
|
|
33
|
-
```yaml
|
|
34
|
-
context:
|
|
35
|
-
mode: context # clear | context (default: context)
|
|
36
|
-
window_size: 10 # 1-50 (default: 10). Sliding-window turns when mode=context.
|
|
37
|
-
reply_chain_depth: 10 # 1-50 (default: 10). Reply chain depth when mode=clear.
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Per-space overrides via `mrctl config set context.<key> <value>` always win over YAML defaults; YAML re-reads on restart do not overwrite an existing space row.
|
|
41
|
-
|
|
42
|
-
You may also set a top-level **`model_chain`** array as an alias for `model.chain`.
|
|
43
|
-
|
|
44
|
-
## Model chain
|
|
45
|
-
|
|
46
|
-
In YAML, use a list of `{ provider, model }` objects under `model.chain` (max 4 legs). The same rules apply as for `MERCURY_MODEL_CHAIN` JSON.
|
|
47
|
-
|
|
48
|
-
Optional **`model.capabilities`** may be a mapping; it is applied like `MERCURY_MODEL_CAPABILITIES` JSON.
|
|
49
|
-
|
|
50
|
-
### Removed: `provider: cursor`
|
|
51
|
-
|
|
52
|
-
The **Cursor Agent CLI** integration has been removed. All model legs use **pi** with standard providers (`anthropic`, `openai`, `google`, `mistral`, `groq`, `openrouter`, etc.).
|
|
53
|
-
|
|
54
|
-
If your chain still has `provider: cursor`, the agent run **fails fast** with an error that points here. Switch to the **native provider** for the model you want (for example `anthropic` for Claude, `openai` for GPT) and set the matching **`MERCURY_*_API_KEY`**.
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Mercury reads settings from **environment variables** (`MERCURY_*`) and, optionally, a project **`mercury.yaml`** file in the current working directory.
|
|
4
|
+
|
|
5
|
+
**Product / design spec:** [prd-config-load.md](prd-config-load.md) (config load: YAML + env precedence, security, non-goals).
|
|
6
|
+
|
|
7
|
+
## Precedence
|
|
8
|
+
|
|
9
|
+
1. If a `MERCURY_*` variable is **set** in the environment (the key exists, including empty string), its value wins.
|
|
10
|
+
2. Otherwise, if **`mercury.yaml`** (or **`mercury.yml`**) exists in `cwd`, values from that file apply.
|
|
11
|
+
3. Otherwise, built-in defaults from `config.ts` apply.
|
|
12
|
+
|
|
13
|
+
Set **`MERCURY_CONFIG_FILE`** to an explicit path to load a different file. Set it to **`""`** (empty) or **`none`** to **disable** loading any file (useful for tests or when you want env/defaults only).
|
|
14
|
+
|
|
15
|
+
Relative paths in `MERCURY_CONFIG_FILE` are resolved against `cwd`.
|
|
16
|
+
|
|
17
|
+
## Secrets (never use `mercury.yaml` for these)
|
|
18
|
+
|
|
19
|
+
These must be supplied via environment variables only; they are **not** read from YAML:
|
|
20
|
+
|
|
21
|
+
- `MERCURY_API_SECRET`
|
|
22
|
+
- `MERCURY_CHAT_API_KEY`
|
|
23
|
+
- `MERCURY_DISCORD_GATEWAY_SECRET`
|
|
24
|
+
|
|
25
|
+
Platform tokens, provider API keys, and extension keys (e.g. `MERCURY_TELEGRAM_BOT_TOKEN`, `MERCURY_BRAVE_API_KEY`) are also **env-only** today—they are not part of the YAML schema.
|
|
26
|
+
|
|
27
|
+
## YAML layout
|
|
28
|
+
|
|
29
|
+
See [`resources/templates/mercury.example.yaml`](../resources/templates/mercury.example.yaml) for a commented template. Supported sections include `server`, `model`, `ingress`, `runtime`, `trigger`, `context`, `conditional_context`, `compaction`, `agent`, `discord`, `telegram`, `media`, and `permissions`.
|
|
30
|
+
|
|
31
|
+
The `context:` block seeds default conversation-context behavior into the `main` space on first boot:
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
context:
|
|
35
|
+
mode: context # clear | context (default: context)
|
|
36
|
+
window_size: 10 # 1-50 (default: 10). Sliding-window turns when mode=context.
|
|
37
|
+
reply_chain_depth: 10 # 1-50 (default: 10). Reply chain depth when mode=clear.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Per-space overrides via `mrctl config set context.<key> <value>` always win over YAML defaults; YAML re-reads on restart do not overwrite an existing space row.
|
|
41
|
+
|
|
42
|
+
You may also set a top-level **`model_chain`** array as an alias for `model.chain`.
|
|
43
|
+
|
|
44
|
+
## Model chain
|
|
45
|
+
|
|
46
|
+
In YAML, use a list of `{ provider, model }` objects under `model.chain` (max 4 legs). The same rules apply as for `MERCURY_MODEL_CHAIN` JSON.
|
|
47
|
+
|
|
48
|
+
Optional **`model.capabilities`** may be a mapping; it is applied like `MERCURY_MODEL_CAPABILITIES` JSON.
|
|
49
|
+
|
|
50
|
+
### Removed: `provider: cursor`
|
|
51
|
+
|
|
52
|
+
The **Cursor Agent CLI** integration has been removed. All model legs use **pi** with standard providers (`anthropic`, `openai`, `google`, `mistral`, `groq`, `openrouter`, etc.).
|
|
53
|
+
|
|
54
|
+
If your chain still has `provider: cursor`, the agent run **fails fast** with an error that points here. Switch to the **native provider** for the model you want (for example `anthropic` for Claude, `openai` for GPT) and set the matching **`MERCURY_*_API_KEY`**.
|