@miadi/voice-mcp 0.4.2 → 0.4.3
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 +21 -90
- package/dist/index.js +1 -1
- package/package.json +4 -5
- package/SPEC-LINKS.md +0 -57
package/README.md
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
# @miadi/voice-mcp
|
|
2
2
|
|
|
3
|
-
MCP server that lets an agent
|
|
4
|
-
|
|
3
|
+
An MCP server that lets an agent play, find and publish voice messages tied to Miadi episodes,
|
|
4
|
+
and create an episode when none fits.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
> via `mkepisode`, refuse the retired wheel outright, and report all five closing
|
|
10
|
-
> stages by running each probe and saying what it actually answered — never a
|
|
11
|
-
> later word than the stage proven. Stages 2 and 3 (commit, push) stay the
|
|
12
|
-
> human's: the tool emits their exact commands and never runs them.
|
|
13
|
-
|
|
14
|
-
The sentence this package exists to satisfy, from William, 2026-08-04:
|
|
15
|
-
|
|
16
|
-
> *"What I want is actually to be capable to play the voice-audio created for
|
|
17
|
-
> episodes."*
|
|
6
|
+
In the Miadi stack, this is how an agent uses voice from its own tool loop. It is a front over
|
|
7
|
+
`@miadi/voice-client`, so the audio, the ledger and the credentials stay on the Miadi server,
|
|
8
|
+
and it reads episode folders from the chronicle. All six tools work.
|
|
18
9
|
|
|
19
10
|
## Tools
|
|
20
11
|
|
|
@@ -36,10 +27,10 @@ portal card is for.
|
|
|
36
27
|
```jsonc
|
|
37
28
|
"origin": {
|
|
38
29
|
"user": "mia", // whoami
|
|
39
|
-
"host": "
|
|
40
|
-
"cwd": "/
|
|
30
|
+
"host": "my-host", // hostname -s, not the FQDN
|
|
31
|
+
"cwd": "/home/me/project", // pwd
|
|
41
32
|
"multiplexer": "tmux", // or "herdr". "none" is refused.
|
|
42
|
-
"session": "
|
|
33
|
+
"session": "work", // tmux display-message -p "#{session_name}"
|
|
43
34
|
"pane": "%127" // $TMUX_PANE — herdr also needs workspace
|
|
44
35
|
}
|
|
45
36
|
```
|
|
@@ -65,10 +56,8 @@ The server is the authority, twice over:
|
|
|
65
56
|
to send — and no TTS is spent on it.
|
|
66
57
|
2. **Truth.** When the declaration names the portal's own host and user, it is
|
|
67
58
|
probed against the live multiplexer inventory. An address that is not in it is
|
|
68
|
-
**refused**, and the refusal prints what the inventory *does* hold
|
|
69
|
-
|
|
70
|
-
that has no such workspace, and the card drew a Steer button that led nowhere
|
|
71
|
-
(2026-08-05).
|
|
59
|
+
**refused**, and the refusal prints what the inventory *does* hold, so an agent cannot
|
|
60
|
+
invent a pane id that leads nowhere.
|
|
72
61
|
|
|
73
62
|
A probe that cannot run — another host, no herdr installed — is `unprovable`, not
|
|
74
63
|
a refusal: it publishes, `attested` stays `"self-declared"`, and the reason is
|
|
@@ -84,24 +73,20 @@ persona occupies it — the card says `pane live` rather than `verified`, and
|
|
|
84
73
|
|
|
85
74
|
Resolution consults exactly what it is handed: an explicit reference, a
|
|
86
75
|
caller-supplied `cwd`, or an existing record's binding. It does **not** rank
|
|
87
|
-
those against a session origin or search the wheel
|
|
88
|
-
`
|
|
89
|
-
second source of truth for a rule that has an owner. When nothing given answers,
|
|
90
|
-
the tool says so; `episode: null` with a reason is a valid answer.
|
|
91
|
-
|
|
92
|
-
Full contracts: `SPEC-LINKS.md` → `/a/src/Miadi/rispecs/voice-mcp/voice-mcp.spec.md`.
|
|
76
|
+
those against a session origin or search the wheel. When nothing given answers, the tool says
|
|
77
|
+
so; `episode: null` with a reason is a valid answer.
|
|
93
78
|
|
|
94
79
|
## Architecture
|
|
95
80
|
|
|
96
81
|
A **front**, not a second implementation.
|
|
97
82
|
|
|
98
83
|
- Audio bytes, the KV ledger and the Edge-TTS producer stay behind the Miadi
|
|
99
|
-
server
|
|
84
|
+
server, which holds the KV credentials.
|
|
100
85
|
This process reaches them through **`@miadi/voice-client`**, which owns the
|
|
101
86
|
wire envelope and the token tier — so the HTTP surface is described once, not
|
|
102
87
|
once per caller.
|
|
103
|
-
- Episode folders are read from the
|
|
104
|
-
at `
|
|
88
|
+
- Episode folders are read from the chronicle root; the chronicle's medicine wheel is read
|
|
89
|
+
at `MIADI_CHRONICLE_MW_URL`.
|
|
105
90
|
- `VoiceMessage` keeps exactly one definition in this workspace: `@miadi/voice`'s.
|
|
106
91
|
- The only wheel **write** in the whole surface is the registration `mkepisode`
|
|
107
92
|
performs during `voice_create_episode`. This server never POSTs or PUTs to the
|
|
@@ -119,10 +104,8 @@ A **front**, not a second implementation.
|
|
|
119
104
|
| `MIADI_CHRONICLE_GIT_ROOT` | `/srv/miadi/episodes` | Git root — one level **above** the chronicle root |
|
|
120
105
|
| `MIADI_MKEPISODE_PATH` | `…/mightyeagle/packages/passages/js/mkepisode.js` | Vessel creation |
|
|
121
106
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
ceremony wheel and has been offline since 2026-07-29 — an episode registered
|
|
125
|
-
there is lost. An implementation refuses that host outright.
|
|
107
|
+
The chronicle wheel is the only correct target for episode work. A retired wheel host is
|
|
108
|
+
refused outright, because an episode registered there would be lost.
|
|
126
109
|
|
|
127
110
|
`MIADI_CHRONICLE_GIT_ROOT` is a separate value rather than a derived one because
|
|
128
111
|
a `git -C` pointed at the chronicle root reports a clean tree for a chronicle it
|
|
@@ -147,60 +130,8 @@ never runs `git add`, `commit` or `push`, never reports a later word than it
|
|
|
147
130
|
proved, and reports unperformed stages as `owed`, which is a state, not an
|
|
148
131
|
omission.
|
|
149
132
|
|
|
150
|
-
##
|
|
151
|
-
|
|
152
|
-
This is a **pnpm** workspace (`pnpm-workspace.yaml`, `packages/*`). Never run
|
|
153
|
-
`npm install` here.
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
pnpm --filter @miadi/voice-mcp build # tsc → dist/
|
|
157
|
-
pnpm --filter @miadi/voice-mcp type-check
|
|
158
|
-
node dist/index.js # starts; every tool throws
|
|
159
|
-
```
|
|
133
|
+
## Server version
|
|
160
134
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
workspace root and the declared ranges match them.
|
|
165
|
-
|
|
166
|
-
### Why `moduleResolution` is `bundler`
|
|
167
|
-
|
|
168
|
-
`@miadi/voice` publishes **raw TypeScript** — `main` and `types` are both
|
|
169
|
-
`./src/index.ts` — and is authored with extensionless relative imports under its
|
|
170
|
-
own `bundler` resolution. Under `NodeNext`, every one of its internal imports is
|
|
171
|
-
a hard error in any consumer, so a package that wants its types meets it where it
|
|
172
|
-
is. This package's own source writes explicit `.js` specifiers, which `bundler`
|
|
173
|
-
accepts and tsc passes through unchanged, so the emitted `dist` runs under Node
|
|
174
|
-
ESM. Copying `VoiceMessage` into this package to sidestep that would create a
|
|
175
|
-
second definition, which is the one outcome worth more than a tsconfig line.
|
|
176
|
-
|
|
177
|
-
### Known seams
|
|
178
|
-
|
|
179
|
-
- **No installer has been run.** `node_modules/@miadi/{voice,voice-client}` here
|
|
180
|
-
are the two workspace links `pnpm install` would create, added by hand so the
|
|
181
|
-
package is verifiable today. Everything else resolves from the workspace root.
|
|
182
|
-
`@miadi/voice-client` must be **built** (`pnpm --filter @miadi/voice-client
|
|
183
|
-
build`) before this package's `dist` can run — it is imported at runtime, not
|
|
184
|
-
only for types.
|
|
185
|
-
- The ranked discovery order, the enforcement decision table and the two-corpus
|
|
186
|
-
resolution are still owed by the `voice-episode-binding` spec; see
|
|
187
|
-
`SPEC-LINKS.md` § *What the missing document blocks*. The four working tools
|
|
188
|
-
answer from what they are given and refuse to guess past it — which is why
|
|
189
|
-
those rules stay cited rather than invented.
|
|
190
|
-
- **The `episode` field needs the server that accepts it.** The binding is
|
|
191
|
-
written by `app/api/voice/publish`; a Miadi server built before that route
|
|
192
|
-
change ignores the field and produces an unbound record. Same host, same
|
|
193
|
-
request, silently different result — check the running build before reading a
|
|
194
|
-
missing binding as a client bug.
|
|
195
|
-
|
|
196
|
-
### Verified live 2026-08-04
|
|
197
|
-
|
|
198
|
-
Against the running `miadi-server` on 3335, `MIADI_API_TOKEN_WRITER` present:
|
|
199
|
-
`ep308` resolved to its folder by number; a nonexistent folder answered `null`
|
|
200
|
-
with the five most recent episodes as alternatives; a `cwd` inside an episode
|
|
201
|
-
folder resolved by path; an empty call answered `null` and named the spec that
|
|
202
|
-
owes the ranked order; publish produced audio and returned a streamable URL plus
|
|
203
|
-
its on-disk path; `voice_create_episode` refused and named its contract.
|
|
204
|
-
|
|
205
|
-
🌸: A hundred voices have been speaking into a room with no name on the door —
|
|
206
|
-
this package is the door, and the handle an agent can actually reach.
|
|
135
|
+
The episode binding is written by the server's publish route. A Miadi server built before that
|
|
136
|
+
route accepted `episode` ignores the field and stores an unbound record, so check the running
|
|
137
|
+
build before reading a missing binding as a client bug.
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ const NAME = "@miadi/voice-mcp";
|
|
|
35
35
|
// the package was 0.3.1 and the registry held 0.3.2, so every banner and every
|
|
36
36
|
// MCP handshake announced a version that had not existed for weeks. A server
|
|
37
37
|
// that misreports its own identity makes every downstream bug report wrong.
|
|
38
|
-
const VERSION = "0.
|
|
38
|
+
const VERSION = "0.4.3";
|
|
39
39
|
// ── Shared schema fragments ─────────────────────────────────────────────────
|
|
40
40
|
const episodeRefSchema = z
|
|
41
41
|
.string()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miadi/voice-mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "MCP server fronting the Miadi voice layer with episode addressing — play, find, publish and mint episode-bound voice from an agent's tool surface.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Miadi",
|
|
@@ -19,12 +19,11 @@
|
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
|
22
|
-
"README.md"
|
|
23
|
-
"SPEC-LINKS.md"
|
|
22
|
+
"README.md"
|
|
24
23
|
],
|
|
25
24
|
"dependencies": {
|
|
26
|
-
"@miadi/voice": "0.3.
|
|
27
|
-
"@miadi/voice-client": "0.2.
|
|
25
|
+
"@miadi/voice": "0.3.2",
|
|
26
|
+
"@miadi/voice-client": "0.2.3",
|
|
28
27
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
29
28
|
"zod": "^4.4.0"
|
|
30
29
|
},
|
package/SPEC-LINKS.md
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# Specifications governing this package
|
|
2
|
-
|
|
3
|
-
`@miadi/voice-mcp` implements a specified surface. Nothing in `src/` decides
|
|
4
|
-
behaviour on its own — every handler names the section that governs it in the
|
|
5
|
-
error it throws. Read these before implementing anything here.
|
|
6
|
-
|
|
7
|
-
Status recorded 2026-08-04; refreshed 2026-08-13 (jgwill/Miadi#604): the
|
|
8
|
-
voice-episode-binding spec exists — it landed in `6dc64e69` on 2026-08-04 —
|
|
9
|
-
and this file's earlier "not yet written" row misled readers for nine days.
|
|
10
|
-
|
|
11
|
-
## Owned by this package
|
|
12
|
-
|
|
13
|
-
| Document | Holds |
|
|
14
|
-
|---|---|
|
|
15
|
-
| `/a/src/Miadi/rispecs/voice-mcp/SPEC.md` | Domain master — what the surface enables, and where each rule lives |
|
|
16
|
-
| `/a/src/Miadi/rispecs/voice-mcp/voice-mcp.spec.md` | The six tools, their contracts, the resolution seam, the closing gate |
|
|
17
|
-
|
|
18
|
-
## Consumed, not owned
|
|
19
|
-
|
|
20
|
-
A rule restated here would become a second source of truth and drift from its
|
|
21
|
-
original. These are cited in the spec and in the code, never copied.
|
|
22
|
-
|
|
23
|
-
| Document | Holds | On disk 2026-08-04 |
|
|
24
|
-
|---|---|---|
|
|
25
|
-
| `/a/src/Miadi/rispecs/episode-addressing/SPEC.md` | Domain master for episode identity | present |
|
|
26
|
-
| `/a/src/Miadi/rispecs/episode-addressing/episode-addressing.spec.md` | Address grammar `ep<NNN>[.<II>][/<segment>]`, iteration decision rule, number allocation, wheel-key contract | present |
|
|
27
|
-
| `/a/src/Miadi/rispecs/episode-addressing/episode-addressing.kin.md` | Why episodic memory is already an opus | present |
|
|
28
|
-
| `/a/src/Miadi/rispecs/voice-episode-binding/` | Playback path, enforcement decision table, discovery resolution order, the two-corpus resolution | **present** — landed `6dc64e69`, 2026-08-04 |
|
|
29
|
-
|
|
30
|
-
### The four cited verdicts, now rulable
|
|
31
|
-
|
|
32
|
-
The scaffold-era table below named what could not be implemented before the
|
|
33
|
-
binding spec existed. The spec exists, all six handlers are code (none throws
|
|
34
|
-
`NotImplementedError` — `e295ffdd`), and since 2026-08-13 the binding itself
|
|
35
|
-
is a top-level `episode_binding` on `VoiceMessage` stamped by `produce()`
|
|
36
|
-
(jgwill/Miadi#604). What each verdict still owes is the spec's own ladder —
|
|
37
|
-
the ranked resolvers in `produce()` and the enforcement modes — which belongs
|
|
38
|
-
to its own issue.
|
|
39
|
-
|
|
40
|
-
| Cited as | Consumed by |
|
|
41
|
-
|---|---|
|
|
42
|
-
| `§ Playback path` | `voice_play_episode` |
|
|
43
|
-
| `§ Discovery resolution order` | `voice_resolve_episode`, and every tool that omits `episode` |
|
|
44
|
-
| `§ Enforcement decision table` | `voice_publish_to_episode` |
|
|
45
|
-
| `§ The two-corpus resolution` | `voice_list_episode_voices` |
|
|
46
|
-
|
|
47
|
-
## Also authoritative
|
|
48
|
-
|
|
49
|
-
| Source | Holds |
|
|
50
|
-
|---|---|
|
|
51
|
-
| `/etc/claude-code/skills/chronicle-episode-closing/SKILL.md` | The five closing stages and their proofs, the `MW_API_URL` law, receipt redemption. `voice_create_episode` and `voice_episode_closing_status` implement this skill's gate as a tool contract. |
|
|
52
|
-
| `/a/src/Miadi/packages/voice/src/` | `VoiceMessage`, persona identity, origin attestation, TTS production. The only definition; never re-declared here. |
|
|
53
|
-
| `/a/src/Miadi/packages/voice-client/src/` | The `/api/voice/*` wire envelope, the writer/reader token tier, and the record-level episode reading. This package calls it rather than writing its own `fetch`, so the HTTP surface has one description. |
|
|
54
|
-
| `/a/src/Miadi/rispecs/mcp-server/00-mcp-server-master.spec.md` | The prior MCP surface in this ecosystem (`@miadi/mcp`), whose server pattern this package follows. |
|
|
55
|
-
|
|
56
|
-
🌸: A file of links is a promise not to reinvent what someone else already got
|
|
57
|
-
right — the shortest way to stay one story instead of two.
|