mercury-agent 0.5.0 → 0.5.2
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 +452 -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/ROADMAP.md +3 -4
- 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 -174
- 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/runbooks/publish-checklist.md +9 -1
- 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 +99 -99
- package/src/agent/container-entry.ts +1 -1
- package/src/agent/container-runner.ts +1345 -1346
- package/src/cli/mercury.ts +39 -7
- package/src/cli/mrctl.ts +636 -636
- package/src/config-file.ts +540 -540
- package/src/config.ts +339 -339
- package/src/core/api.ts +125 -125
- package/src/core/caller-token.ts +101 -101
- package/src/core/permissions.ts +228 -228
- package/src/core/profiles.ts +271 -271
- package/src/core/routes/capability.ts +70 -70
- package/src/core/routes/index.ts +15 -15
- package/src/core/runtime.ts +1530 -1530
- package/src/dashboard/index.html +729 -729
- package/src/extensions/api.ts +273 -273
- package/src/extensions/loader.ts +286 -286
- package/src/extensions/types.ts +517 -517
- package/src/main.ts +605 -605
- package/docs/pending-updates/applicative-profiles.md +0 -15
- package/docs/pending-updates/caller-bound-capability-token.md +0 -15
- package/docs/pending-updates/dm-auto-space.md +0 -15
- /package/docs/archive/{2026-07-01-applicative-profiles.md → applicative-profiles/2026-07-01-applicative-profiles.md} +0 -0
- /package/docs/archive/{2026-07-01-caller-bound-capability-token.md → applicative-profiles/2026-07-01-caller-bound-capability-token.md} +0 -0
- /package/docs/archive/{2026-07-01-dm-auto-space.md → applicative-profiles/2026-07-01-dm-auto-space.md} +0 -0
package/docs/permissions.md
CHANGED
|
@@ -1,217 +1,217 @@
|
|
|
1
|
-
# Permissions
|
|
2
|
-
|
|
3
|
-
Mercury uses role-based access control (RBAC) per space. Each user has a role, and each role has a set of permissions.
|
|
4
|
-
|
|
5
|
-
## How It Works
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
Message arrives
|
|
9
|
-
│
|
|
10
|
-
├─► Resolve caller's role
|
|
11
|
-
│ • System caller? → role = "system"
|
|
12
|
-
│ • Seeded admin? → grant admin, store in DB
|
|
13
|
-
│ • Existing role in DB? → use it
|
|
14
|
-
│ • Otherwise → "member"
|
|
15
|
-
│
|
|
16
|
-
├─► Load role's permissions
|
|
17
|
-
│ • Check space_config for override
|
|
18
|
-
│ • Fall back to built-in defaults
|
|
19
|
-
│
|
|
20
|
-
└─► Check permission for action
|
|
21
|
-
• Has permission → proceed
|
|
22
|
-
• Denied → return error
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Roles
|
|
26
|
-
|
|
27
|
-
| Role | Default Permissions | Description |
|
|
28
|
-
|------|---------------------|-------------|
|
|
29
|
-
| `system` | All | Internal system caller (scheduler, etc.) — not assignable |
|
|
30
|
-
| `admin` | All | Full control over the space |
|
|
31
|
-
| `member` | `prompt`, `prefs.get` | Can chat and read space preferences (default for new users) |
|
|
32
|
-
|
|
33
|
-
Custom roles can be created by assigning permissions to any role name.
|
|
34
|
-
|
|
35
|
-
## Permissions
|
|
36
|
-
|
|
37
|
-
| Permission | Description |
|
|
38
|
-
|------------|-------------|
|
|
39
|
-
| `prompt` | Send messages to the assistant |
|
|
40
|
-
| `stop` | Abort running agent and clear queue |
|
|
41
|
-
| `compact` | Reset session boundary (fresh context) |
|
|
42
|
-
| `tasks.list` | View scheduled tasks |
|
|
43
|
-
| `tasks.create` | Create new scheduled tasks |
|
|
44
|
-
| `tasks.pause` | Pause scheduled tasks |
|
|
45
|
-
| `tasks.resume` | Resume paused tasks |
|
|
46
|
-
| `tasks.delete` | Delete scheduled tasks |
|
|
47
|
-
| `config.get` | Read space configuration |
|
|
48
|
-
| `config.set` | Modify space configuration |
|
|
49
|
-
| `prefs.get` | Read space preferences (`mrctl prefs list/get`) |
|
|
50
|
-
| `prefs.set` | Create, update, or delete space preferences (`mrctl prefs set/delete`) |
|
|
51
|
-
| `roles.list` | View roles in the space |
|
|
52
|
-
| `roles.grant` | Assign roles to users |
|
|
53
|
-
| `roles.revoke` | Remove roles from users |
|
|
54
|
-
| `permissions.get` | View role permissions |
|
|
55
|
-
| `permissions.set` | Modify role permissions |
|
|
56
|
-
| `spaces.list` | View all spaces |
|
|
57
|
-
| `spaces.rename` | Rename a space and link/unlink conversations |
|
|
58
|
-
| `spaces.delete` | Delete current space and all related DB data |
|
|
59
|
-
|
|
60
|
-
## Mutes
|
|
61
|
-
|
|
62
|
-
Muted users’ messages are dropped for the space until the mute expires or is cleared. The agent can mute via `mrctl mute` (with API confirmation). **Operators** with dashboard access (`MERCURY_API_SECRET`) can list active mutes, unmute, or add a timed mute from **Spaces → (space) → Muted users**.
|
|
63
|
-
|
|
64
|
-
## Managing Roles
|
|
65
|
-
|
|
66
|
-
The agent uses `mrctl` to manage roles:
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
# List all roles in the current space
|
|
70
|
-
mrctl roles list
|
|
71
|
-
|
|
72
|
-
# Grant admin role to a user
|
|
73
|
-
mrctl roles grant 1234567890@s.whatsapp.net --role admin
|
|
74
|
-
|
|
75
|
-
# Grant a custom role
|
|
76
|
-
mrctl roles grant 1234567890@s.whatsapp.net --role moderator
|
|
77
|
-
|
|
78
|
-
# Revoke role (user becomes member)
|
|
79
|
-
mrctl roles revoke 1234567890@s.whatsapp.net
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## Managing Permissions
|
|
83
|
-
|
|
84
|
-
Permissions are per-role, per-space:
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
# Show permissions for all roles
|
|
88
|
-
mrctl permissions show
|
|
89
|
-
|
|
90
|
-
# Show permissions for a specific role
|
|
91
|
-
mrctl permissions show --role member
|
|
92
|
-
|
|
93
|
-
# Give members ability to stop the agent
|
|
94
|
-
mrctl permissions set member prompt,stop
|
|
95
|
-
|
|
96
|
-
# Create a moderator role with task management
|
|
97
|
-
mrctl permissions set moderator prompt,stop,tasks.list,tasks.pause,tasks.resume
|
|
98
|
-
|
|
99
|
-
# Give a role full task control
|
|
100
|
-
mrctl permissions set taskmaster prompt,tasks.list,tasks.create,tasks.pause,tasks.resume,tasks.delete
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Managing Spaces
|
|
104
|
-
|
|
105
|
-
Spaces can be listed and managed via `mrctl`:
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
# List all spaces with their names
|
|
109
|
-
mrctl spaces list
|
|
110
|
-
|
|
111
|
-
# Get current space's display name
|
|
112
|
-
mrctl spaces name
|
|
113
|
-
|
|
114
|
-
# Set current space's display name
|
|
115
|
-
mrctl spaces name "Startup Buddies"
|
|
116
|
-
|
|
117
|
-
# Delete current space (tasks, messages, roles, config)
|
|
118
|
-
mrctl spaces delete
|
|
119
|
-
|
|
120
|
-
# List discovered conversations
|
|
121
|
-
mrctl conversations list
|
|
122
|
-
|
|
123
|
-
# Show only conversations that are not yet linked
|
|
124
|
-
mrctl conversations list --unlinked
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Space names are stored in the database and shown in logs/dashboard for easier identification. Conversations remain platform-native and are linked into spaces. Conversation listing uses `spaces.list`; linking and unlinking use `spaces.rename`.
|
|
128
|
-
|
|
129
|
-
## Seeding Admins
|
|
130
|
-
|
|
131
|
-
Pre-configure admin users via environment variable. They're granted admin on first interaction with each space:
|
|
132
|
-
|
|
133
|
-
```bash
|
|
134
|
-
MERCURY_ADMINS=1234567890@s.whatsapp.net,0987654321@s.whatsapp.net
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
This is useful for bootstrapping — the first admin can then grant roles to others.
|
|
138
|
-
|
|
139
|
-
## Storage
|
|
140
|
-
|
|
141
|
-
Roles and permissions are stored in SQLite:
|
|
142
|
-
|
|
143
|
-
| Table | Purpose |
|
|
144
|
-
|-------|---------|
|
|
145
|
-
| `space_roles` | Maps `(space_id, platform_user_id)` → `role` |
|
|
146
|
-
| `space_config` | Stores `role.<name>.permissions` overrides |
|
|
147
|
-
|
|
148
|
-
Built-in defaults (`admin` = all, `member` = `prompt` + `prefs.get`) are not stored — they're applied when no override exists.
|
|
149
|
-
|
|
150
|
-
## System Caller
|
|
151
|
-
|
|
152
|
-
The `system` role is special:
|
|
153
|
-
|
|
154
|
-
- Always has all permissions
|
|
155
|
-
- Cannot be modified or assigned
|
|
156
|
-
- Used for internal callers: scheduled tasks, system triggers
|
|
157
|
-
|
|
158
|
-
```typescript
|
|
159
|
-
if (isSystemCaller(callerId)) return "system";
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
## Extension Permissions
|
|
163
|
-
|
|
164
|
-
Extensions register additional permissions at runtime via the extension API:
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
mercury.permission({ defaultRoles: ["admin", "member"] });
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
This registers a permission named after the extension (e.g., `napkin`). The behavior:
|
|
171
|
-
|
|
172
|
-
- **Admin** always gets all permissions (built-in + extension)
|
|
173
|
-
- **Extension `defaultRoles`** are respected — if `["member"]` is specified, members get that permission by default
|
|
174
|
-
- **Per-space overrides** still take precedence over defaults
|
|
175
|
-
- **Built-in permission names** cannot be overridden by extensions
|
|
176
|
-
|
|
177
|
-
Extension CLIs are called directly by the agent in bash. Permission enforcement is handled by a pi extension that blocks denied CLIs at the bash tool level, based on the caller's role and the `MERCURY_DENIED_CLIS` environment variable set by Mercury's runtime.
|
|
178
|
-
|
|
179
|
-
Extensions that declare env vars via `mercury.env()` also have those vars gated by permission — they are only injected into containers when the caller has the extension's permission. This prevents credential leakage (e.g., a blocked `gh` CLI's `GH_TOKEN` being used via `curl`).
|
|
180
|
-
|
|
181
|
-
### API
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
registerPermission(name, { defaultRoles }) // Register (called by extension loader)
|
|
185
|
-
getAllPermissions() // Built-in + extension permissions
|
|
186
|
-
isValidPermission(name) // Check if name is valid
|
|
187
|
-
resetPermissions() // Clear registered (test isolation)
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## Scope
|
|
191
|
-
|
|
192
|
-
Permissions are **per-space**:
|
|
193
|
-
|
|
194
|
-
- A user can be `admin` in one space and `member` in another
|
|
195
|
-
- Custom role permissions are space-specific
|
|
196
|
-
- No global roles (except seeded admins, which apply on first interaction per space)
|
|
197
|
-
|
|
198
|
-
## API
|
|
199
|
-
|
|
200
|
-
### `resolveRole(db, spaceId, platformUserId, seededAdmins)`
|
|
201
|
-
|
|
202
|
-
Determines a caller's role:
|
|
203
|
-
1. System caller → `"system"`
|
|
204
|
-
2. Seed admins if needed
|
|
205
|
-
3. Upsert member record
|
|
206
|
-
4. Return stored role or `"member"`
|
|
207
|
-
|
|
208
|
-
### `getRolePermissions(db, spaceId, role)`
|
|
209
|
-
|
|
210
|
-
Returns the permission set for a role:
|
|
211
|
-
1. System role → all permissions
|
|
212
|
-
2. Check `space_config` for `role.<name>.permissions`
|
|
213
|
-
3. Fall back to built-in defaults
|
|
214
|
-
|
|
215
|
-
### `hasPermission(db, spaceId, role, permission)`
|
|
216
|
-
|
|
217
|
-
Returns `true` if the role has the specified permission.
|
|
1
|
+
# Permissions
|
|
2
|
+
|
|
3
|
+
Mercury uses role-based access control (RBAC) per space. Each user has a role, and each role has a set of permissions.
|
|
4
|
+
|
|
5
|
+
## How It Works
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Message arrives
|
|
9
|
+
│
|
|
10
|
+
├─► Resolve caller's role
|
|
11
|
+
│ • System caller? → role = "system"
|
|
12
|
+
│ • Seeded admin? → grant admin, store in DB
|
|
13
|
+
│ • Existing role in DB? → use it
|
|
14
|
+
│ • Otherwise → "member"
|
|
15
|
+
│
|
|
16
|
+
├─► Load role's permissions
|
|
17
|
+
│ • Check space_config for override
|
|
18
|
+
│ • Fall back to built-in defaults
|
|
19
|
+
│
|
|
20
|
+
└─► Check permission for action
|
|
21
|
+
• Has permission → proceed
|
|
22
|
+
• Denied → return error
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Roles
|
|
26
|
+
|
|
27
|
+
| Role | Default Permissions | Description |
|
|
28
|
+
|------|---------------------|-------------|
|
|
29
|
+
| `system` | All | Internal system caller (scheduler, etc.) — not assignable |
|
|
30
|
+
| `admin` | All | Full control over the space |
|
|
31
|
+
| `member` | `prompt`, `prefs.get` | Can chat and read space preferences (default for new users) |
|
|
32
|
+
|
|
33
|
+
Custom roles can be created by assigning permissions to any role name.
|
|
34
|
+
|
|
35
|
+
## Permissions
|
|
36
|
+
|
|
37
|
+
| Permission | Description |
|
|
38
|
+
|------------|-------------|
|
|
39
|
+
| `prompt` | Send messages to the assistant |
|
|
40
|
+
| `stop` | Abort running agent and clear queue |
|
|
41
|
+
| `compact` | Reset session boundary (fresh context) |
|
|
42
|
+
| `tasks.list` | View scheduled tasks |
|
|
43
|
+
| `tasks.create` | Create new scheduled tasks |
|
|
44
|
+
| `tasks.pause` | Pause scheduled tasks |
|
|
45
|
+
| `tasks.resume` | Resume paused tasks |
|
|
46
|
+
| `tasks.delete` | Delete scheduled tasks |
|
|
47
|
+
| `config.get` | Read space configuration |
|
|
48
|
+
| `config.set` | Modify space configuration |
|
|
49
|
+
| `prefs.get` | Read space preferences (`mrctl prefs list/get`) |
|
|
50
|
+
| `prefs.set` | Create, update, or delete space preferences (`mrctl prefs set/delete`) |
|
|
51
|
+
| `roles.list` | View roles in the space |
|
|
52
|
+
| `roles.grant` | Assign roles to users |
|
|
53
|
+
| `roles.revoke` | Remove roles from users |
|
|
54
|
+
| `permissions.get` | View role permissions |
|
|
55
|
+
| `permissions.set` | Modify role permissions |
|
|
56
|
+
| `spaces.list` | View all spaces |
|
|
57
|
+
| `spaces.rename` | Rename a space and link/unlink conversations |
|
|
58
|
+
| `spaces.delete` | Delete current space and all related DB data |
|
|
59
|
+
|
|
60
|
+
## Mutes
|
|
61
|
+
|
|
62
|
+
Muted users’ messages are dropped for the space until the mute expires or is cleared. The agent can mute via `mrctl mute` (with API confirmation). **Operators** with dashboard access (`MERCURY_API_SECRET`) can list active mutes, unmute, or add a timed mute from **Spaces → (space) → Muted users**.
|
|
63
|
+
|
|
64
|
+
## Managing Roles
|
|
65
|
+
|
|
66
|
+
The agent uses `mrctl` to manage roles:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# List all roles in the current space
|
|
70
|
+
mrctl roles list
|
|
71
|
+
|
|
72
|
+
# Grant admin role to a user
|
|
73
|
+
mrctl roles grant 1234567890@s.whatsapp.net --role admin
|
|
74
|
+
|
|
75
|
+
# Grant a custom role
|
|
76
|
+
mrctl roles grant 1234567890@s.whatsapp.net --role moderator
|
|
77
|
+
|
|
78
|
+
# Revoke role (user becomes member)
|
|
79
|
+
mrctl roles revoke 1234567890@s.whatsapp.net
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Managing Permissions
|
|
83
|
+
|
|
84
|
+
Permissions are per-role, per-space:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Show permissions for all roles
|
|
88
|
+
mrctl permissions show
|
|
89
|
+
|
|
90
|
+
# Show permissions for a specific role
|
|
91
|
+
mrctl permissions show --role member
|
|
92
|
+
|
|
93
|
+
# Give members ability to stop the agent
|
|
94
|
+
mrctl permissions set member prompt,stop
|
|
95
|
+
|
|
96
|
+
# Create a moderator role with task management
|
|
97
|
+
mrctl permissions set moderator prompt,stop,tasks.list,tasks.pause,tasks.resume
|
|
98
|
+
|
|
99
|
+
# Give a role full task control
|
|
100
|
+
mrctl permissions set taskmaster prompt,tasks.list,tasks.create,tasks.pause,tasks.resume,tasks.delete
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Managing Spaces
|
|
104
|
+
|
|
105
|
+
Spaces can be listed and managed via `mrctl`:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# List all spaces with their names
|
|
109
|
+
mrctl spaces list
|
|
110
|
+
|
|
111
|
+
# Get current space's display name
|
|
112
|
+
mrctl spaces name
|
|
113
|
+
|
|
114
|
+
# Set current space's display name
|
|
115
|
+
mrctl spaces name "Startup Buddies"
|
|
116
|
+
|
|
117
|
+
# Delete current space (tasks, messages, roles, config)
|
|
118
|
+
mrctl spaces delete
|
|
119
|
+
|
|
120
|
+
# List discovered conversations
|
|
121
|
+
mrctl conversations list
|
|
122
|
+
|
|
123
|
+
# Show only conversations that are not yet linked
|
|
124
|
+
mrctl conversations list --unlinked
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Space names are stored in the database and shown in logs/dashboard for easier identification. Conversations remain platform-native and are linked into spaces. Conversation listing uses `spaces.list`; linking and unlinking use `spaces.rename`.
|
|
128
|
+
|
|
129
|
+
## Seeding Admins
|
|
130
|
+
|
|
131
|
+
Pre-configure admin users via environment variable. They're granted admin on first interaction with each space:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
MERCURY_ADMINS=1234567890@s.whatsapp.net,0987654321@s.whatsapp.net
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This is useful for bootstrapping — the first admin can then grant roles to others.
|
|
138
|
+
|
|
139
|
+
## Storage
|
|
140
|
+
|
|
141
|
+
Roles and permissions are stored in SQLite:
|
|
142
|
+
|
|
143
|
+
| Table | Purpose |
|
|
144
|
+
|-------|---------|
|
|
145
|
+
| `space_roles` | Maps `(space_id, platform_user_id)` → `role` |
|
|
146
|
+
| `space_config` | Stores `role.<name>.permissions` overrides |
|
|
147
|
+
|
|
148
|
+
Built-in defaults (`admin` = all, `member` = `prompt` + `prefs.get`) are not stored — they're applied when no override exists.
|
|
149
|
+
|
|
150
|
+
## System Caller
|
|
151
|
+
|
|
152
|
+
The `system` role is special:
|
|
153
|
+
|
|
154
|
+
- Always has all permissions
|
|
155
|
+
- Cannot be modified or assigned
|
|
156
|
+
- Used for internal callers: scheduled tasks, system triggers
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
if (isSystemCaller(callerId)) return "system";
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Extension Permissions
|
|
163
|
+
|
|
164
|
+
Extensions register additional permissions at runtime via the extension API:
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
mercury.permission({ defaultRoles: ["admin", "member"] });
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
This registers a permission named after the extension (e.g., `napkin`). The behavior:
|
|
171
|
+
|
|
172
|
+
- **Admin** always gets all permissions (built-in + extension)
|
|
173
|
+
- **Extension `defaultRoles`** are respected — if `["member"]` is specified, members get that permission by default
|
|
174
|
+
- **Per-space overrides** still take precedence over defaults
|
|
175
|
+
- **Built-in permission names** cannot be overridden by extensions
|
|
176
|
+
|
|
177
|
+
Extension CLIs are called directly by the agent in bash. Permission enforcement is handled by a pi extension that blocks denied CLIs at the bash tool level, based on the caller's role and the `MERCURY_DENIED_CLIS` environment variable set by Mercury's runtime.
|
|
178
|
+
|
|
179
|
+
Extensions that declare env vars via `mercury.env()` also have those vars gated by permission — they are only injected into containers when the caller has the extension's permission. This prevents credential leakage (e.g., a blocked `gh` CLI's `GH_TOKEN` being used via `curl`).
|
|
180
|
+
|
|
181
|
+
### API
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
registerPermission(name, { defaultRoles }) // Register (called by extension loader)
|
|
185
|
+
getAllPermissions() // Built-in + extension permissions
|
|
186
|
+
isValidPermission(name) // Check if name is valid
|
|
187
|
+
resetPermissions() // Clear registered (test isolation)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Scope
|
|
191
|
+
|
|
192
|
+
Permissions are **per-space**:
|
|
193
|
+
|
|
194
|
+
- A user can be `admin` in one space and `member` in another
|
|
195
|
+
- Custom role permissions are space-specific
|
|
196
|
+
- No global roles (except seeded admins, which apply on first interaction per space)
|
|
197
|
+
|
|
198
|
+
## API
|
|
199
|
+
|
|
200
|
+
### `resolveRole(db, spaceId, platformUserId, seededAdmins)`
|
|
201
|
+
|
|
202
|
+
Determines a caller's role:
|
|
203
|
+
1. System caller → `"system"`
|
|
204
|
+
2. Seed admins if needed
|
|
205
|
+
3. Upsert member record
|
|
206
|
+
4. Return stored role or `"member"`
|
|
207
|
+
|
|
208
|
+
### `getRolePermissions(db, spaceId, role)`
|
|
209
|
+
|
|
210
|
+
Returns the permission set for a role:
|
|
211
|
+
1. System role → all permissions
|
|
212
|
+
2. Check `space_config` for `role.<name>.permissions`
|
|
213
|
+
3. Fall back to built-in defaults
|
|
214
|
+
|
|
215
|
+
### `hasPermission(db, spaceId, role, permission)`
|
|
216
|
+
|
|
217
|
+
Returns `true` if the role has the specified permission.
|