dictum-cli 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dictum contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,280 @@
1
+ # dictum
2
+
3
+ **Type or dictate a thought. Get a polished prompt in your clipboard.**
4
+
5
+ `dictum` is a prompt-polishing CLI with built-in voice input. Type a rough idea
6
+ (or speak it — the audio is transcribed first), an LLM rewrites it into a clean,
7
+ structured prompt, and the result lands in your clipboard or on stdout — ready
8
+ to paste into Claude, an editor, or a shell pipe.
9
+ It works over SSH (via OSC52), runs fully self-hosted, and is provider-agnostic.
10
+ Connected [over MCP](#dictum-inside-your-agent-mcp), it becomes a prompt overlay
11
+ for the coding agent you already use: your model, your context, Dictum's rules.
12
+
13
+ <!-- demo: replace with an asciinema cast or GIF -->
14
+ ```console
15
+ $ dictum
16
+ ● recording — press Enter to stop
17
+ ◌ transcribing ✦ polishing ✓ copied (2.1s)
18
+ # → clipboard: "Write a Python function that reads a JSON file of users and
19
+ # returns only the active ones. Handle missing-file and invalid-JSON errors."
20
+ ```
21
+ > _Demo placeholder — an asciinema recording goes here in the first third of the README._
22
+
23
+ ## Quick start
24
+
25
+ > **Pre-release note:** the first public release (GitHub + npm) is not published
26
+ > yet — until then, install from source below. The installer and npm commands
27
+ > go live with v0.1.
28
+
29
+ From source (works today; needs [Bun](https://bun.sh) ≥ 1.2):
30
+
31
+ ```sh
32
+ git clone https://github.com/KsandrSol/dictum && cd dictum
33
+ bun install --frozen-lockfile
34
+ bun run src/cli.ts doctor # check mic / STT / polisher / clipboard
35
+ bun run src/cli.ts # speak, then press Enter → polished prompt on your clipboard
36
+ ```
37
+
38
+ Once released — prebuilt binary or npm:
39
+
40
+ ```sh
41
+ curl -fsSL https://raw.githubusercontent.com/KsandrSol/dictum/main/install.sh | bash
42
+ # or, with Bun: npm i -g dictum-cli (then `dictum`), or one-off `bunx dictum-cli`
43
+ ```
44
+
45
+ ## Why
46
+
47
+ - **Talking is faster than typing a good prompt.** Speak the messy version; let
48
+ the model do the cleanup. You get a structured prompt, not a raw transcript.
49
+ - **Your agent's brains, Dictum's rules.** Inside Claude Code, Cursor & co.,
50
+ Dictum doesn't call its own model at all: it hands *your* agent a rewriting
51
+ brief, and the model you already pay for polishes the draft — with full
52
+ knowledge of your project. See [Dictum inside your agent](#dictum-inside-your-agent-mcp).
53
+ - **Provider-agnostic & self-hosted.** Local STT (GigaAM/Whisper) + your choice
54
+ of polisher (Claude CLI by subscription, Anthropic API, or any OpenAI-compatible
55
+ endpoint). No vendor lock-in, no required cloud account.
56
+ - **SSH- and pipe-friendly.** Over SSH it copies to your *local* clipboard via
57
+ OSC52; in a pipe it streams to stdout: `dictum --stdout | claude`.
58
+ - **Orthogonal & hackable.** record → transcribe → polish → emit, each stage a
59
+ swappable module behind one tiny contract.
60
+
61
+ ## Usage
62
+
63
+ ```sh
64
+ dictum # record → polish → choose → copy to clipboard
65
+ dictum --text "fix the auth bug" # polish typed text (no microphone)
66
+ echo "draft commit message" | dictum -m commit --stdout # piped stdin = text
67
+ dictum --input note.wav --stdout
68
+ dictum -m commit --auto --stdout | git commit -F -
69
+ dictum --raw --stdout # skip polishing; emit the raw transcript
70
+ dictum doctor # diagnose mic / STT / polisher / clipboard
71
+ ```
72
+
73
+ **Input — voice or text.** Speak (microphone), pass `--text "…"`, or pipe text
74
+ in (`echo … | dictum`). Text input skips recording and STT entirely.
75
+
76
+ **Choose, don't blindly replace.** On an interactive terminal Dictum shows the
77
+ polished result and lets you keep `[p]olished` (default), your `[o]riginal`, or
78
+ `[r]egenerate` a fresh one. In a pipe (`dictum | claude`) or with `--auto` it
79
+ emits the polished text automatically, so scripts and agent flows are unaffected.
80
+
81
+ | Flag | Meaning |
82
+ |------|---------|
83
+ | `-i, --input <file>` | Transcribe a WAV file instead of recording |
84
+ | `-t, --text <text>` | Polish the given text instead of recording (piped stdin works too) |
85
+ | `-m, --mode <name>` | Template: `agent-prompt` (default), `commit`, `note`, `spec`, `decompose` |
86
+ | `--raw` | Skip polishing; output the raw transcript |
87
+ | `--auto` | Skip the choice prompt; emit the polished text |
88
+ | `--stdout` | Print to stdout (for pipes) instead of the clipboard |
89
+ | `--format <text\|json>` | `json` emits a stable envelope: `{v, original, polished, template, score, rationale}` |
90
+ | `--help`, `--version` | The usual |
91
+
92
+ **Scores, not vibes.** A deterministic analyzer rates every draft 0–100 across
93
+ five dimensions (clarity, specificity, structure, actionability, context). The
94
+ interactive chooser shows the delta (`score 34 → 78 · structure +5`), and
95
+ `--format json` carries the full breakdown for scripts and integrations.
96
+
97
+ ## Dictum inside your agent (MCP)
98
+
99
+ The flagship way to use Dictum: as a **prompt overlay for the coding agent you
100
+ already use**. Connect the MCP server and Dictum stops calling its own model —
101
+ instead it hands *your* agent a rewriting brief (canon rules + a deterministic
102
+ pre-analysis of your draft), and **the model you picked in your session does the
103
+ polishing, with full knowledge of your project**. Vague references like "that
104
+ failing test" become real file paths. Zero extra LLM calls, zero API keys.
105
+
106
+ ```sh
107
+ dictum mcp # serve host-brain prompts + tools over stdio
108
+ ```
109
+
110
+ | Host | Host-brain channel | How you invoke it |
111
+ |------|--------------------|-------------------|
112
+ | Claude Code | MCP Prompts | `/mcp__dictum__polish <draft>` (also `__spec`, `__decompose`) |
113
+ | Cursor | MCP Prompts | type `/`, pick the dictum prompt |
114
+ | Windsurf | MCP Prompts | via Cascade |
115
+ | Claude Desktop | MCP Prompts | "+" menu → Add from dictum |
116
+ | Codex CLI | `polish_brief` tool | ask it to polish; it calls the tool and follows the brief |
117
+
118
+ Register the server. For Claude Code:
119
+
120
+ ```sh
121
+ claude mcp add dictum -- dictum mcp
122
+ ```
123
+
124
+ For Codex CLI, add to `~/.codex/config.toml`:
125
+
126
+ ```toml
127
+ [mcp_servers.dictum]
128
+ command = "dictum"
129
+ args = ["mcp"]
130
+ ```
131
+
132
+ For Cursor (`.cursor/mcp.json` project-level or `~/.cursor/mcp.json` global),
133
+ Windsurf, or Claude Desktop (`claude_desktop_config.json`) — the de-facto
134
+ standard JSON shape:
135
+
136
+ ```json
137
+ {
138
+ "mcpServers": {
139
+ "dictum": { "command": "dictum", "args": ["mcp"] }
140
+ }
141
+ }
142
+ ```
143
+
144
+ **Prompts** (host-brain — your model, your context; the flagship):
145
+
146
+ - **`polish(draft?)`** — draft → clear, structured prompt. The brief embeds the
147
+ deterministic 0–100 pre-analysis so the host fixes the *measured* weak spots.
148
+ - **`spec(draft?)`** — draft → compact task spec with requirements and
149
+ acceptance criteria.
150
+ - **`decompose(draft?)`** — draft → ordered, dependency-tracked subtasks.
151
+
152
+ Every brief ends the same way: the agent shows the result and a numbered
153
+ choice — reply **1** to act on it, **2** to keep your original, **3** to tweak.
154
+ Dictum proposes; you decide.
155
+
156
+ **Tools:**
157
+
158
+ - **`polish_brief(text, mode?)`** — the same host-brain brief as a tool result,
159
+ for hosts without MCP Prompts support (Codex CLI). Offline, no LLM call.
160
+ - **`polish_prompt(text, mode?)`** — server-side polish with Dictum's **own**
161
+ model (no session context; useful from scripts or context-less hosts).
162
+ `mode` is a template (`agent-prompt`, `commit`, `note`, `spec`, `decompose`,
163
+ or any custom one).
164
+ - **`analyze_prompt(text)`** — deterministic 0–100 score across five dimensions
165
+ plus weak spots, as JSON. Offline; lets an agent decide whether a draft needs
166
+ polishing at all.
167
+ - **`build_spec(text)`** — server-side spec via the `spec` template.
168
+
169
+ The server speaks plain MCP over stdio; the only client-specific behavior is
170
+ the brief's vendor prompting tips, picked from `clientInfo.name` at initialize
171
+ (Claude → Anthropic tips, Codex → OpenAI, anything else → generic; see the
172
+ `provider` override on `polish_brief`).
173
+ `tests/mcp_server.test.ts` and `tests/mcp_prompts.test.ts` verify the protocol
174
+ surface (prompts + tools) against the official `@modelcontextprotocol/sdk`
175
+ client, the same library the hosts above are built on. Server-side tools reuse
176
+ the CLI's polisher and templates (config in `~/.config/dictum/config.toml`).
177
+
178
+ ## /dictum in Claude Code (zero-install)
179
+
180
+ No MCP server connected? Dictum's slash command is a single markdown file that
181
+ does the same host-brain trick — Claude Code's own model polishes your draft
182
+ using the session context; no `dictum` binary required:
183
+
184
+ ```sh
185
+ # in this repo it works out of the box (.claude/commands/dictum.md);
186
+ # install globally for all projects:
187
+ mkdir -p ~/.claude/commands
188
+ cp .claude/commands/dictum.md ~/.claude/commands/dictum.md
189
+ ```
190
+
191
+ Then in any Claude Code session:
192
+
193
+ ```
194
+ /dictum сделай миграцию на новую схему юзеров, но чтобы старые токены не отвалились
195
+ ```
196
+
197
+ Claude shows the polished prompt, explains what changed, and acts only on the
198
+ version you choose. Mention that you want a full spec and it structures the
199
+ result with requirements and acceptance criteria.
200
+
201
+ ## Configuration
202
+
203
+ `~/.config/dictum/config.toml` (every field optional; env vars override):
204
+
205
+ ```toml
206
+ [recorder]
207
+ stopMode = "enter" # enter | vad | ptt
208
+ silenceTimeout = 2.0 # seconds of silence for VAD auto-stop
209
+ energyThreshold = 0.015 # VAD voicing threshold (normalized RMS)
210
+
211
+ [stt]
212
+ providers = ["local_http", "openai_compat"] # tried in order, with fallback
213
+ [stt.local_http]
214
+ baseUrl = "http://127.0.0.1:5500" # GigaAM-compatible server
215
+ [stt.openai_compat]
216
+ baseUrl = "https://api.openai.com"
217
+ model = "whisper-1"
218
+ language = "ru"
219
+
220
+ [polisher]
221
+ provider = "claude_cli" # claude_cli | anthropic | openai_compat
222
+ mode = "llm" # llm | rules (offline, no LLM) | layered (LLM only when score < threshold)
223
+ scoreThreshold = 80 # layered mode: skip the LLM when the draft scores >= this
224
+ template = "agent-prompt"
225
+
226
+ [sink]
227
+ target = "clipboard" # clipboard | stdout
228
+ ```
229
+
230
+ Custom templates: drop `~/.config/dictum/templates/<name>.md` (frontmatter
231
+ `description` / `language` + instruction body) to override or add modes.
232
+ The file stem `<name>` is the mode ID — a portable ASCII slug (letters,
233
+ digits, `_`, `.`, `-`; e.g. `ru-contract-review.md`); the description and
234
+ body can be in any language. Files with other names are ignored.
235
+
236
+ Useful env vars: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `DICTUM_POLISHER`,
237
+ `DICTUM_POLISHER_MODE`, `DICTUM_SCORE_THRESHOLD`, `DICTUM_SINK`,
238
+ `DICTUM_STOP_MODE`, `DICTUM_CONFIG`.
239
+
240
+ ## Requirements
241
+
242
+ - A polisher: the [Claude CLI](https://claude.com/claude-code) ≥ 2.1.169
243
+ (default, uses your subscription; dictum runs it with project customizations
244
+ disabled and all tools denied) **or** an `ANTHROPIC_API_KEY` /
245
+ OpenAI-compatible key.
246
+ - An STT backend: a local GigaAM/Whisper HTTP server, or an OpenAI-compatible key.
247
+ - For live recording: [`sox`](http://sox.sourceforge.net/) (`apt install sox` /
248
+ `brew install sox`). Not needed for `--input`.
249
+ - For `--input` with non-canonical WAV (not PCM16/16k/mono): `ffmpeg` to
250
+ transcode. Canonical WAV plays without it.
251
+ - Clipboard: native (`pbcopy`/`wl-copy`/`xclip`) or, over SSH with an
252
+ interactive terminal, OSC52 automatically (headless: use `--stdout`).
253
+
254
+ `dictum doctor` checks all of the above and tells you exactly what's missing.
255
+
256
+ ## Supported platforms (v0.1)
257
+
258
+ | Platform | Status |
259
+ |---|---|
260
+ | Linux glibc x64 (modern CPUs) | **Supported** — primary development and test platform |
261
+ | Linux arm64, macOS 13+ (x64/arm64) | **Implemented, unverified** — cross-compiled binaries; promoted after native smoke |
262
+ | WSL / SSH / headless | Text flows via `--stdout` everywhere; clipboard via OSC52 needs an interactive terminal over SSH |
263
+ | Windows (native) | **Experimental, unverified** — text mode and the MCP server should run under Bun; microphone and clipboard flows are not implemented |
264
+
265
+ ## Development
266
+
267
+ ```sh
268
+ bun install
269
+ bun test # unit + contract + e2e (mock servers; no mic needed)
270
+ bun run start --input tests/fixtures/sample-ru.wav --stdout
271
+ bun run build # standalone binary → dist/dictum
272
+ ```
273
+
274
+ TypeScript strict, linted with Biome. Architecture: each pluggable stage imports
275
+ only `src/core/types.ts`; assembly lives in `core/pipeline.ts` + `cli.ts` (an
276
+ import-orthogonality test enforces it).
277
+
278
+ ## License
279
+
280
+ MIT
package/bin/dictum.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bun
2
+ // npm entry point. Dictum is a Bun program (uses Bun.spawn / Bun.file / text
3
+ // imports), so it runs under Bun — installed globally (`npm i -g dictum-cli`)
4
+ // or one-off via `bunx dictum-cli`. Requires Bun ≥ 1.2 on PATH.
5
+ import { main } from "../src/cli.ts"
6
+
7
+ process.exit(await main(Bun.argv.slice(2)))
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "dictum-cli",
3
+ "version": "0.1.0",
4
+ "description": "Prompt-polishing CLI with an MCP host-brain overlay: type or dictate a rough thought, get a clear, structured prompt — in your clipboard or right inside your coding agent",
5
+ "type": "module",
6
+ "bin": {
7
+ "dictum": "bin/dictum.js"
8
+ },
9
+ "files": ["bin", "src", "README.md", "LICENSE"],
10
+ "scripts": {
11
+ "start": "bun run src/cli.ts",
12
+ "build": "bun build --compile --minify --outfile dist/dictum src/cli.ts",
13
+ "build:targets": "bash scripts/build-binaries.sh",
14
+ "test": "bun test",
15
+ "lint": "biome check .",
16
+ "lint:fix": "biome check --write .",
17
+ "format": "biome format --write ."
18
+ },
19
+ "keywords": ["voice", "stt", "prompt", "cli", "speech-to-text", "claude", "llm"],
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/KsandrSol/dictum.git"
24
+ },
25
+ "homepage": "https://github.com/KsandrSol/dictum#readme",
26
+ "bugs": "https://github.com/KsandrSol/dictum/issues",
27
+ "engines": {
28
+ "bun": ">=1.2.0"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.29.0",
32
+ "smol-toml": "^1.3.1",
33
+ "zod": "^4.4.3"
34
+ },
35
+ "devDependencies": {
36
+ "@biomejs/biome": "^1.9.4",
37
+ "@types/bun": "^1.1.14",
38
+ "typescript": "^5.7.2"
39
+ },
40
+ "trustedDependencies": ["@biomejs/biome"]
41
+ }