@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 CHANGED
@@ -1,20 +1,11 @@
1
1
  # @miadi/voice-mcp
2
2
 
3
- MCP server that lets an agent **play, find, publish and mint episode-bound
4
- voice** — the tool surface over the Miadi voice layer and the Chronicle.
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
- > **State: all six tools work (0.4.0).** Publish, play, list and resolve run
7
- > against the live server. `voice_create_episode` and
8
- > `voice_episode_closing_status` stopped being promises on 2026-08-12: they mint
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": "gaia", // hostname -s, not the FQDN
40
- "cwd": "/a/src/Miadi-18", // pwd
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": "stcbot", // tmux display-message -p "#{session_name}"
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. This
69
- exists because a required field taught an agent to invent `wH:p2` in a session
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 — that order is owed by the
88
- `voice-episode-binding` spec, and inventing one here would make this package a
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 (systemd `miadi-server`, port 3335), which holds the KV credentials.
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 Chronicle root; the medicine wheel is read
104
- at `http://127.0.0.1:8040`.
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
- **Two wheels exist.** `http://127.0.0.1:8040` is the Chronicle wheel and the only
123
- correct target for episode work. `https://mw.tail3b11eb.ts.net` is Gaia's
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
- ## Development
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
- Verified 2026-08-04, no installer run: `tsc --noEmit` exits 0, and emit produces
162
- ESM with explicit `.js` specifiers that `node dist/index.js` resolves.
163
- `@modelcontextprotocol/sdk` 1.30.0 and `zod` 4.4.3 are already present at the
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.3.3";
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.2",
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.1",
27
- "@miadi/voice-client": "0.2.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.