@femtomc/mu-agent 26.2.98 → 26.2.100
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 +20 -0
- package/dist/operator.d.ts +3 -1
- package/dist/operator.d.ts.map +1 -1
- package/dist/operator.js +141 -6
- package/dist/session_factory.d.ts +1 -0
- package/dist/session_factory.d.ts.map +1 -1
- package/package.json +2 -2
- package/prompts/skills/crons/SKILL.md +204 -0
- package/prompts/skills/heartbeats/SKILL.md +172 -0
- package/prompts/skills/hierarchical-work-protocol/SKILL.md +233 -0
- package/prompts/skills/memory/SKILL.md +154 -0
- package/prompts/skills/mu/SKILL.md +144 -0
- package/prompts/skills/planning/SKILL.md +75 -14
- package/prompts/skills/setup-discord/SKILL.md +141 -0
- package/prompts/skills/setup-neovim/SKILL.md +141 -0
- package/prompts/skills/setup-slack/SKILL.md +159 -0
- package/prompts/skills/setup-telegram/SKILL.md +171 -0
- package/prompts/skills/subagents/SKILL.md +92 -165
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: planning
|
|
3
|
-
description:
|
|
3
|
+
description: "Builds and refines issue-DAG plans using the planning HUD and approval loops. Use when the user asks for planning, decomposition, sequencing, or plan review."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Planning
|
|
7
7
|
|
|
8
8
|
Use this skill when the user asks for planning, decomposition, or a staged execution roadmap.
|
|
9
9
|
|
|
10
|
+
## Contents
|
|
11
|
+
|
|
12
|
+
- [Planning HUD is required](#planning-hud-is-required)
|
|
13
|
+
- [Shared protocol dependency](#shared-protocol-dependency)
|
|
14
|
+
- [Core contract](#core-contract)
|
|
15
|
+
- [Suggested workflow](#suggested-workflow)
|
|
16
|
+
- [Effective HUD usage heuristics](#effective-hud-usage-heuristics)
|
|
17
|
+
- [Evaluation scenarios](#evaluation-scenarios)
|
|
18
|
+
- [Quality bar](#quality-bar)
|
|
19
|
+
|
|
10
20
|
## Planning HUD is required
|
|
11
21
|
|
|
12
22
|
For this skill, the planning HUD is the primary status/communication surface.
|
|
@@ -22,16 +32,30 @@ Default per-turn HUD loop:
|
|
|
22
32
|
2. Synchronize checklist items and `root_issue_id` with the issue DAG.
|
|
23
33
|
3. Emit `snapshot` (`compact` or `multiline`) and reflect it in your response.
|
|
24
34
|
|
|
35
|
+
## Shared protocol dependency
|
|
36
|
+
|
|
37
|
+
This skill plans DAGs for execution by `subagents`, so planning must follow the
|
|
38
|
+
shared protocol in **`hierarchical-work-protocol`**.
|
|
39
|
+
|
|
40
|
+
Before creating or reshaping DAG nodes, load that skill and use its canonical:
|
|
41
|
+
|
|
42
|
+
- protocol identity/tag (`hierarchical-work.protocol/v1`, `proto:hierarchical-work-v1`)
|
|
43
|
+
- node kinds and context tags
|
|
44
|
+
- invariants for executable vs non-executable nodes
|
|
45
|
+
- planning handoff contract
|
|
46
|
+
|
|
47
|
+
Do not invent alternate protocol names or tag schemas.
|
|
48
|
+
|
|
25
49
|
## Core contract
|
|
26
50
|
|
|
27
51
|
1. **Investigate first**
|
|
28
52
|
- Read relevant code/docs/state before proposing work.
|
|
29
53
|
- Avoid speculative plans when evidence is cheap to gather.
|
|
30
54
|
|
|
31
|
-
2. **Materialize the plan in mu issues**
|
|
32
|
-
- Create
|
|
33
|
-
- Encode dependencies so the DAG reflects execution order.
|
|
34
|
-
- Add clear titles, scope, acceptance criteria, and
|
|
55
|
+
2. **Materialize the plan in mu issues using the shared protocol**
|
|
56
|
+
- Create root and child issues that comply with `hierarchical-work.protocol/v1`.
|
|
57
|
+
- Encode dependencies so the DAG reflects execution order and synth fan-in.
|
|
58
|
+
- Add clear titles, scope, acceptance criteria, and protocol tags.
|
|
35
59
|
|
|
36
60
|
3. **Drive communication through the planning HUD**
|
|
37
61
|
- Treat HUD state as the canonical short status line for planning.
|
|
@@ -108,18 +132,39 @@ Also inspect repo files directly (read/bash) for implementation constraints.
|
|
|
108
132
|
### B) Draft DAG in mu-issue
|
|
109
133
|
|
|
110
134
|
```bash
|
|
111
|
-
# 1) Create root
|
|
112
|
-
mu issues create "<Goal>"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
135
|
+
# 1) Create protocol root container
|
|
136
|
+
root_json="$(mu issues create "<Goal>" \
|
|
137
|
+
--body "<scope + success criteria>" \
|
|
138
|
+
--tag node:root \
|
|
139
|
+
--tag kind:root \
|
|
140
|
+
--tag proto:hierarchical-work-v1 \
|
|
141
|
+
--json)"
|
|
142
|
+
root_id="$(echo "$root_json" | jq -r '.id')"
|
|
143
|
+
mu issues update "$root_id" --remove-tag node:agent
|
|
144
|
+
|
|
145
|
+
# 2) Create executable child work nodes
|
|
146
|
+
mu issues create "<Subtask A>" \
|
|
147
|
+
--parent "$root_id" \
|
|
148
|
+
--body "<acceptance criteria>" \
|
|
149
|
+
--tag kind:spawn \
|
|
150
|
+
--tag ctx:clean \
|
|
151
|
+
--tag proto:hierarchical-work-v1 \
|
|
152
|
+
--priority 2 --pretty
|
|
153
|
+
|
|
154
|
+
mu issues create "<Subtask B>" \
|
|
155
|
+
--parent "$root_id" \
|
|
156
|
+
--body "<acceptance criteria>" \
|
|
157
|
+
--tag kind:fork \
|
|
158
|
+
--tag ctx:inherit \
|
|
159
|
+
--tag proto:hierarchical-work-v1 \
|
|
160
|
+
--priority 2 --pretty
|
|
117
161
|
|
|
118
162
|
# 3) Add dependency edges where needed
|
|
119
163
|
mu issues dep <child-a-id> blocks <child-b-id>
|
|
120
164
|
|
|
121
|
-
# 4) Validate ready set
|
|
122
|
-
mu issues ready --root
|
|
165
|
+
# 4) Validate ready set + protocol scope
|
|
166
|
+
mu issues ready --root "$root_id" --tag proto:hierarchical-work-v1 --pretty
|
|
167
|
+
mu issues validate "$root_id"
|
|
123
168
|
```
|
|
124
169
|
|
|
125
170
|
### C) Plan presentation template
|
|
@@ -134,7 +179,8 @@ mu issues ready --root <root-id> --pretty
|
|
|
134
179
|
### D) Revision loop
|
|
135
180
|
|
|
136
181
|
- Apply feedback with `mu issues update` / `mu issues dep` / additional issues.
|
|
137
|
-
- Re-run `mu issues ready --root <root-id> --pretty`.
|
|
182
|
+
- Re-run `mu issues ready --root <root-id> --tag proto:hierarchical-work-v1 --pretty`.
|
|
183
|
+
- Validate protocol-root status via `mu issues validate <root-id>`.
|
|
138
184
|
- Present a concise diff of what changed and why.
|
|
139
185
|
- Update HUD each turn so phase/waiting/next/blocker/confidence match the latest state.
|
|
140
186
|
|
|
@@ -158,9 +204,24 @@ Required HUD updates during the loop:
|
|
|
158
204
|
- Adjust `confidence` as evidence quality changes (`low` when assumptions are unresolved).
|
|
159
205
|
- Customize checklist steps once scope is understood; check them off as milestones complete.
|
|
160
206
|
|
|
207
|
+
## Evaluation scenarios
|
|
208
|
+
|
|
209
|
+
1. **Initial decomposition request**
|
|
210
|
+
- Prompt: user asks for a staged roadmap.
|
|
211
|
+
- Expected: investigation pass runs first, root + child issues are created with `proto:hierarchical-work-v1`, HUD shows `phase=drafting` and `waiting_on_user=false` until first review checkpoint.
|
|
212
|
+
|
|
213
|
+
2. **Feedback-driven replan**
|
|
214
|
+
- Prompt: user requests scope change after first DAG draft.
|
|
215
|
+
- Expected: dependency/issue updates are applied, concise change diff is presented, HUD transitions through `reviewing`/`waiting_user` with updated `next_action`.
|
|
216
|
+
|
|
217
|
+
3. **Blocked-by-missing-input planning turn**
|
|
218
|
+
- Prompt: required architecture constraint is unknown.
|
|
219
|
+
- Expected: plan captures explicit assumption gap, HUD uses `phase=blocked` or `waiting_user` (as appropriate), and asks one concrete unblock question.
|
|
220
|
+
|
|
161
221
|
## Quality bar
|
|
162
222
|
|
|
163
223
|
- Every issue should be actionable and testable.
|
|
224
|
+
- DAG nodes must satisfy `hierarchical-work.protocol/v1` before execution handoff.
|
|
164
225
|
- Keep tasks small enough to complete in one focused pass.
|
|
165
226
|
- Explicitly call out uncertain assumptions for user confirmation.
|
|
166
227
|
- Prefer reversible plans and incremental checkpoints.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: setup-discord
|
|
3
|
+
description: "Sets up the Discord messaging adapter with agent-first config, reload, verification, and identity linking steps. Use when onboarding or repairing Discord channel integration."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# setup-discord
|
|
7
|
+
|
|
8
|
+
Use this skill when the user asks to set up Discord messaging for `mu`.
|
|
9
|
+
|
|
10
|
+
Goal: get Discord `/mu` ingress working with minimal user effort outside the terminal.
|
|
11
|
+
|
|
12
|
+
## Required user-provided inputs
|
|
13
|
+
|
|
14
|
+
- Public webhook base URL reachable by Discord (for example `https://mu.example.com`)
|
|
15
|
+
- Discord app **Signing Secret**
|
|
16
|
+
|
|
17
|
+
## Agent-first workflow
|
|
18
|
+
|
|
19
|
+
### 0) Verify local prerequisites (agent)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
command -v mu >/dev/null && echo "mu: ok"
|
|
23
|
+
command -v python3 >/dev/null && echo "python3: ok (required for config patching)"
|
|
24
|
+
command -v curl >/dev/null && echo "curl: ok (required for API checks)"
|
|
25
|
+
command -v jq >/dev/null && echo "jq: ok (required for filtered JSON checks)"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If any required command is missing, stop and ask the user to install it before proceeding.
|
|
29
|
+
|
|
30
|
+
### 1) Preflight local state
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
mu control status --pretty
|
|
34
|
+
mu store paths --pretty
|
|
35
|
+
mu control identities --all --pretty
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
If server reload/route checks fail because no server is running, ask the user to start `mu serve` in another terminal, then continue.
|
|
39
|
+
|
|
40
|
+
### 2) Minimal user actions in Discord Developer Portal
|
|
41
|
+
|
|
42
|
+
Ask the user to do only these actions:
|
|
43
|
+
|
|
44
|
+
1. Create/select a Discord application.
|
|
45
|
+
2. Set Interactions endpoint URL to:
|
|
46
|
+
- `https://<public-base>/webhooks/discord`
|
|
47
|
+
3. Create an application command named `mu` in the target guild/server.
|
|
48
|
+
4. Ensure the app is installed in the target guild.
|
|
49
|
+
5. Provide the app `signing_secret`.
|
|
50
|
+
|
|
51
|
+
### 3) Agent patches mu config
|
|
52
|
+
|
|
53
|
+
Use this canonical patch snippet (preserves unrelated keys):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
export MU_DISCORD_SIGNING_SECRET='<DISCORD_SIGNING_SECRET>'
|
|
57
|
+
config_path="$(mu control status --json | python3 -c 'import json,sys; print(json.load(sys.stdin)["config_path"])')"
|
|
58
|
+
|
|
59
|
+
python3 - "$config_path" <<'PY'
|
|
60
|
+
import json
|
|
61
|
+
import os
|
|
62
|
+
import sys
|
|
63
|
+
from pathlib import Path
|
|
64
|
+
|
|
65
|
+
path = Path(sys.argv[1])
|
|
66
|
+
if path.exists():
|
|
67
|
+
data = json.loads(path.read_text())
|
|
68
|
+
else:
|
|
69
|
+
data = {"version": 1, "control_plane": {}}
|
|
70
|
+
|
|
71
|
+
cp = data.setdefault("control_plane", {})
|
|
72
|
+
adapters = cp.setdefault("adapters", {})
|
|
73
|
+
discord = adapters.setdefault("discord", {})
|
|
74
|
+
discord["signing_secret"] = os.environ["MU_DISCORD_SIGNING_SECRET"]
|
|
75
|
+
|
|
76
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
77
|
+
path.write_text(json.dumps(data, indent=2) + "\n")
|
|
78
|
+
PY
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Replace placeholder values with secrets from the user, then `unset MU_DISCORD_SIGNING_SECRET` after patching.
|
|
82
|
+
|
|
83
|
+
### 4) Reload and verify channel capability
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
mu control reload
|
|
87
|
+
mu control status --json --pretty
|
|
88
|
+
curl -sS http://localhost:3000/api/control-plane/channels | jq '.channels[] | select(.channel=="discord")'
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Verify:
|
|
92
|
+
- `configured: true`
|
|
93
|
+
- `active: true` (when server is running)
|
|
94
|
+
- route `/webhooks/discord`
|
|
95
|
+
|
|
96
|
+
### 5) Identity linking with audit-assisted ID discovery
|
|
97
|
+
|
|
98
|
+
Preferred flow:
|
|
99
|
+
1. Ask user to run one Discord `/mu` command.
|
|
100
|
+
2. Extract `actor_id` + `channel_tenant_id` from adapter audit.
|
|
101
|
+
3. Link as operator.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
mu store tail cp_adapter_audit --limit 50 --json \
|
|
105
|
+
| jq -r '[.[] | select(.channel=="discord")] | last | "actor=\(.actor_id) tenant=\(.channel_tenant_id)"'
|
|
106
|
+
|
|
107
|
+
mu control link --channel discord --actor-id <actor-id> --tenant-id <tenant-id> --role operator
|
|
108
|
+
mu control identities --pretty
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
If audit data is missing, ask user for Discord user id + guild id directly.
|
|
112
|
+
|
|
113
|
+
### 6) Smoke checks
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
mu control status --pretty
|
|
117
|
+
mu store tail cp_adapter_audit --limit 20 --pretty
|
|
118
|
+
mu store tail cp_outbox --limit 20 --pretty
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Ask user to run `/mu status` and confirm ingress ACK behavior.
|
|
122
|
+
|
|
123
|
+
## Evaluation scenarios
|
|
124
|
+
|
|
125
|
+
1. **Happy path onboarding**
|
|
126
|
+
- Inputs: valid public base URL, `signing_secret`, running `mu serve`.
|
|
127
|
+
- Expected: Discord channel reports `configured=true` and `active=true`; `/mu status` gets an ACK/response flow.
|
|
128
|
+
|
|
129
|
+
2. **Invalid signing secret**
|
|
130
|
+
- Inputs: Discord app configured with one secret, `mu` config has another.
|
|
131
|
+
- Expected: inbound interactions are denied with deterministic audit reason; skill routes user to correct secret + reload + smoke.
|
|
132
|
+
|
|
133
|
+
3. **Audit-assisted link fallback**
|
|
134
|
+
- Inputs: command ingress works but no identity linked yet.
|
|
135
|
+
- Expected: skill derives `actor_id`/`channel_tenant_id` from audit, links operator identity, verifies with `mu control identities --pretty`.
|
|
136
|
+
|
|
137
|
+
## Notes and caveats
|
|
138
|
+
|
|
139
|
+
- Discord setup requires only `signing_secret` in current config contract.
|
|
140
|
+
- Keep troubleshooting reason-code oriented (signature/timestamp/payload errors from adapter audit).
|
|
141
|
+
- Keep user asks minimal: dashboard actions + one test command.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: setup-neovim
|
|
3
|
+
description: "Sets up the mu.nvim messaging channel with agent-first config, reload, verification, and identity linking steps. Use when onboarding or repairing Neovim channel integration."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# setup-neovim
|
|
7
|
+
|
|
8
|
+
Use this skill when the user asks to set up the Neovim messaging channel (`mu.nvim`).
|
|
9
|
+
|
|
10
|
+
Goal: get `:Mu ...` working against `mu` control-plane with minimal user-side editor actions.
|
|
11
|
+
|
|
12
|
+
## Required user-provided inputs
|
|
13
|
+
|
|
14
|
+
- Confirmation that `mu.nvim` is installed (or permission for the agent to provide install snippet)
|
|
15
|
+
- Neovim-side place to set shared secret (`shared_secret` option or `MU_NEOVIM_SHARED_SECRET` env)
|
|
16
|
+
|
|
17
|
+
## Agent-first workflow
|
|
18
|
+
|
|
19
|
+
### 0) Verify local prerequisites (agent)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
command -v mu >/dev/null && echo "mu: ok"
|
|
23
|
+
command -v python3 >/dev/null && echo "python3: ok (required for config patching)"
|
|
24
|
+
command -v curl >/dev/null && echo "curl: ok (required for API checks)"
|
|
25
|
+
command -v jq >/dev/null && echo "jq: ok (required for filtered JSON checks)"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If any required command is missing, stop and ask the user to install it before proceeding.
|
|
29
|
+
|
|
30
|
+
### 1) Preflight local state
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
mu control status --pretty
|
|
34
|
+
mu store paths --pretty
|
|
35
|
+
mu control identities --all --pretty
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
If no running server exists for reload/capability checks, ask user to run `mu serve` in another terminal.
|
|
39
|
+
|
|
40
|
+
### 2) Generate and set a shared secret (agent)
|
|
41
|
+
|
|
42
|
+
Generate a strong shared secret, then patch config with this canonical snippet
|
|
43
|
+
(preserves unrelated keys):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
export MU_NEOVIM_SHARED_SECRET='<NEOVIM_SHARED_SECRET>'
|
|
47
|
+
config_path="$(mu control status --json | python3 -c 'import json,sys; print(json.load(sys.stdin)["config_path"])')"
|
|
48
|
+
|
|
49
|
+
python3 - "$config_path" <<'PY'
|
|
50
|
+
import json
|
|
51
|
+
import os
|
|
52
|
+
import sys
|
|
53
|
+
from pathlib import Path
|
|
54
|
+
|
|
55
|
+
path = Path(sys.argv[1])
|
|
56
|
+
if path.exists():
|
|
57
|
+
data = json.loads(path.read_text())
|
|
58
|
+
else:
|
|
59
|
+
data = {"version": 1, "control_plane": {}}
|
|
60
|
+
|
|
61
|
+
cp = data.setdefault("control_plane", {})
|
|
62
|
+
adapters = cp.setdefault("adapters", {})
|
|
63
|
+
neovim = adapters.setdefault("neovim", {})
|
|
64
|
+
neovim["shared_secret"] = os.environ["MU_NEOVIM_SHARED_SECRET"]
|
|
65
|
+
|
|
66
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
path.write_text(json.dumps(data, indent=2) + "\n")
|
|
68
|
+
PY
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Replace `<NEOVIM_SHARED_SECRET>` with the generated secret, then `unset MU_NEOVIM_SHARED_SECRET`.
|
|
72
|
+
|
|
73
|
+
### 3) Reload and verify channel capability
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
mu control reload
|
|
77
|
+
mu control status --json --pretty
|
|
78
|
+
curl -sS http://localhost:3000/api/control-plane/channels | jq '.channels[] | select(.channel=="neovim")'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Verify:
|
|
82
|
+
- `configured: true`
|
|
83
|
+
- `active: true` (when server is running)
|
|
84
|
+
- route `/webhooks/neovim`
|
|
85
|
+
|
|
86
|
+
### 4) Provide minimal user editor steps
|
|
87
|
+
|
|
88
|
+
Ask user to do only these actions in Neovim:
|
|
89
|
+
|
|
90
|
+
1. Set the same shared secret in `mu.nvim` config (or env var `MU_NEOVIM_SHARED_SECRET`).
|
|
91
|
+
2. Ensure plugin points at the running server (default server discovery is fine if available).
|
|
92
|
+
3. Run:
|
|
93
|
+
- `:Mu channels`
|
|
94
|
+
- `:Mu link`
|
|
95
|
+
- `:Mu status`
|
|
96
|
+
|
|
97
|
+
` :Mu link` is the preferred identity binding path for Neovim.
|
|
98
|
+
|
|
99
|
+
### 5) Optional agent-side identity link fallback
|
|
100
|
+
|
|
101
|
+
If `:Mu link` is unavailable, derive actor/tenant from adapter audit after one Neovim request,
|
|
102
|
+
then link via control-plane API:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
mu store tail cp_adapter_audit --limit 50 --json \
|
|
106
|
+
| jq -r '[.[] | select(.channel=="neovim")] | last | "actor=\(.actor_id) tenant=\(.channel_tenant_id)"'
|
|
107
|
+
|
|
108
|
+
curl -sS -X POST http://localhost:3000/api/control-plane/identities/link \
|
|
109
|
+
-H 'content-type: application/json' \
|
|
110
|
+
-d '{"channel":"neovim","actor_id":"<actor-id>","tenant_id":"<tenant-id>","role":"operator"}'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 6) Smoke and forensics
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
mu control status --pretty
|
|
117
|
+
mu control identities --all --pretty
|
|
118
|
+
mu store tail cp_adapter_audit --limit 20 --pretty
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Confirm `:Mu status` returns a valid response in-editor.
|
|
122
|
+
|
|
123
|
+
## Evaluation scenarios
|
|
124
|
+
|
|
125
|
+
1. **Happy path with `:Mu link`**
|
|
126
|
+
- Inputs: matching shared secret in server + plugin, running `mu serve`.
|
|
127
|
+
- Expected: `:Mu channels` lists neovim as active; `:Mu link` succeeds; `:Mu status` returns valid response.
|
|
128
|
+
|
|
129
|
+
2. **Shared-secret mismatch**
|
|
130
|
+
- Inputs: plugin secret differs from `control_plane.adapters.neovim.shared_secret`.
|
|
131
|
+
- Expected: neovim requests are rejected with deterministic auth reason; skill rotates/re-syncs secret and revalidates.
|
|
132
|
+
|
|
133
|
+
3. **Manual identity-link fallback**
|
|
134
|
+
- Inputs: `:Mu link` unavailable in plugin version.
|
|
135
|
+
- Expected: skill extracts actor/tenant from adapter audit and links via control-plane API; identity appears in `mu control identities --all --pretty`.
|
|
136
|
+
|
|
137
|
+
## Safety and UX requirements
|
|
138
|
+
|
|
139
|
+
- Do not expose full shared secret in final user-facing summaries.
|
|
140
|
+
- Keep user asks limited to in-editor actions only.
|
|
141
|
+
- If failures occur, cite exact reason codes and next smallest recovery step.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: setup-slack
|
|
3
|
+
description: "Sets up the Slack messaging adapter with agent-first config, reload, verification, and identity linking steps. Use when onboarding or repairing Slack channel integration."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# setup-slack
|
|
7
|
+
|
|
8
|
+
Use this skill when the user asks to set up Slack messaging for `mu`.
|
|
9
|
+
|
|
10
|
+
Goal: get `/mu ...` working end-to-end in Slack, with the agent doing all local setup and asking the user only for Slack-console actions/secrets the agent cannot perform.
|
|
11
|
+
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
- [Required user-provided inputs](#required-user-provided-inputs)
|
|
15
|
+
- [Agent-first workflow](#agent-first-workflow)
|
|
16
|
+
- [Evaluation scenarios](#evaluation-scenarios)
|
|
17
|
+
- [Safety and UX requirements](#safety-and-ux-requirements)
|
|
18
|
+
|
|
19
|
+
## Required user-provided inputs
|
|
20
|
+
|
|
21
|
+
- Public webhook base URL reachable by Slack (for example `https://mu.example.com`)
|
|
22
|
+
- Slack app **Signing Secret**
|
|
23
|
+
- Slack app **Bot User OAuth Token** (`xoxb-...`) for outbound replies/media
|
|
24
|
+
|
|
25
|
+
## Agent-first workflow
|
|
26
|
+
|
|
27
|
+
### 0) Verify local prerequisites (agent)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
command -v mu >/dev/null && echo "mu: ok"
|
|
31
|
+
command -v python3 >/dev/null && echo "python3: ok (required for config patching)"
|
|
32
|
+
command -v curl >/dev/null && echo "curl: ok (required for API checks)"
|
|
33
|
+
command -v jq >/dev/null && echo "jq: ok (required for filtered JSON checks)"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If any required command is missing, stop and ask the user to install it before proceeding.
|
|
37
|
+
|
|
38
|
+
### 1) Preflight local state
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
mu control status --pretty
|
|
42
|
+
mu store paths --pretty
|
|
43
|
+
mu control identities --all --pretty
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If no running server is available when reload/route checks are attempted, ask the user to run `mu serve` in another terminal, then continue.
|
|
47
|
+
|
|
48
|
+
### 2) Drive user through Slack console steps (minimal ask)
|
|
49
|
+
|
|
50
|
+
Ask the user to do only these actions in Slack API UI:
|
|
51
|
+
|
|
52
|
+
1. Create/install a Slack app in target workspace.
|
|
53
|
+
2. Configure request URL for all inbound surfaces to:
|
|
54
|
+
- `https://<public-base>/webhooks/slack`
|
|
55
|
+
3. Enable at least:
|
|
56
|
+
- Slash command `/mu`
|
|
57
|
+
- Event Subscriptions (`app_mention`)
|
|
58
|
+
- Interactivity
|
|
59
|
+
4. Ensure bot scopes include:
|
|
60
|
+
- `app_mentions:read`
|
|
61
|
+
- `chat:write`
|
|
62
|
+
- `files:read`
|
|
63
|
+
- `files:write`
|
|
64
|
+
5. Return `signing_secret` and `bot_token` to the agent.
|
|
65
|
+
|
|
66
|
+
### 3) Agent patches mu config (do not ask user to edit JSON)
|
|
67
|
+
|
|
68
|
+
Use this canonical patch snippet (preserves unrelated keys):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
export MU_SLACK_SIGNING_SECRET='<SLACK_SIGNING_SECRET>'
|
|
72
|
+
export MU_SLACK_BOT_TOKEN='<SLACK_BOT_TOKEN>'
|
|
73
|
+
config_path="$(mu control status --json | python3 -c 'import json,sys; print(json.load(sys.stdin)["config_path"])')"
|
|
74
|
+
|
|
75
|
+
python3 - "$config_path" <<'PY'
|
|
76
|
+
import json
|
|
77
|
+
import os
|
|
78
|
+
import sys
|
|
79
|
+
from pathlib import Path
|
|
80
|
+
|
|
81
|
+
path = Path(sys.argv[1])
|
|
82
|
+
if path.exists():
|
|
83
|
+
data = json.loads(path.read_text())
|
|
84
|
+
else:
|
|
85
|
+
data = {"version": 1, "control_plane": {}}
|
|
86
|
+
|
|
87
|
+
cp = data.setdefault("control_plane", {})
|
|
88
|
+
adapters = cp.setdefault("adapters", {})
|
|
89
|
+
slack = adapters.setdefault("slack", {})
|
|
90
|
+
slack["signing_secret"] = os.environ["MU_SLACK_SIGNING_SECRET"]
|
|
91
|
+
slack["bot_token"] = os.environ["MU_SLACK_BOT_TOKEN"]
|
|
92
|
+
|
|
93
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
94
|
+
path.write_text(json.dumps(data, indent=2) + "\n")
|
|
95
|
+
PY
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Replace placeholder values with secrets from the user, then `unset MU_SLACK_SIGNING_SECRET MU_SLACK_BOT_TOKEN` after patching.
|
|
99
|
+
|
|
100
|
+
### 4) Reload and verify adapter status
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
mu control reload
|
|
104
|
+
mu control status --json --pretty
|
|
105
|
+
curl -sS http://localhost:3000/api/control-plane/channels | jq '.channels[] | select(.channel=="slack")'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Verify:
|
|
109
|
+
- `configured: true`
|
|
110
|
+
- `active: true` (when server is running)
|
|
111
|
+
- route `/webhooks/slack`
|
|
112
|
+
|
|
113
|
+
### 5) Identity link with least user effort
|
|
114
|
+
|
|
115
|
+
Preferred flow:
|
|
116
|
+
1. Ask user to send one Slack turn (for example `/mu status`).
|
|
117
|
+
2. Extract actor + tenant IDs from audit.
|
|
118
|
+
3. Link identity as operator.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
mu store tail cp_adapter_audit --limit 50 --json \
|
|
122
|
+
| jq -r '[.[] | select(.channel=="slack")] | last | "actor=\(.actor_id) tenant=\(.channel_tenant_id)"'
|
|
123
|
+
|
|
124
|
+
mu control link --channel slack --actor-id <actor-id> --tenant-id <tenant-id> --role operator
|
|
125
|
+
mu control identities --pretty
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
If audit rows are unavailable, ask user for Slack IDs (`U...` user id, `T...` workspace id).
|
|
129
|
+
|
|
130
|
+
### 6) Smoke test + forensic confirmation
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
mu control status --pretty
|
|
134
|
+
mu store tail cp_adapter_audit --limit 20 --pretty
|
|
135
|
+
mu store tail cp_outbox --limit 20 --pretty
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Ask user to run `/mu status` again and confirm response delivery.
|
|
139
|
+
|
|
140
|
+
## Evaluation scenarios
|
|
141
|
+
|
|
142
|
+
1. **Happy path onboarding**
|
|
143
|
+
- Inputs: valid public base URL, `signing_secret`, `bot_token`, running `mu serve`.
|
|
144
|
+
- Expected: `/api/control-plane/channels` reports Slack `configured=true` and `active=true`; Slack `/mu status` returns a response.
|
|
145
|
+
|
|
146
|
+
2. **Signature validation failure**
|
|
147
|
+
- Inputs: wrong `signing_secret` configured.
|
|
148
|
+
- Expected: inbound command is rejected; `cp_adapter_audit` shows deterministic signature/timestamp reason code; skill proposes secret rotation and reload as next step.
|
|
149
|
+
|
|
150
|
+
3. **Outbound token missing/invalid**
|
|
151
|
+
- Inputs: webhook ingress works but `bot_token` missing or invalid.
|
|
152
|
+
- Expected: ingress may ACK but delivery fails; `cp_outbox`/adapter audit expose concrete failure reason; skill guides user to update token and re-run smoke test.
|
|
153
|
+
|
|
154
|
+
## Safety and UX requirements
|
|
155
|
+
|
|
156
|
+
- Never expose secrets in chat logs unnecessarily; redact in summaries.
|
|
157
|
+
- Do not overwrite unrelated `config.json` fields.
|
|
158
|
+
- Keep the user ask short and sequential (one external-console step at a time).
|
|
159
|
+
- If setup fails, report concrete reason codes from audit/outbox and propose the next smallest recovery step.
|