voice-gate
Allows confirmed commands to be dispatched to an OpenAI-compatible assistant endpoint configured as a target.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@voice-gateWhat's the decision for 'remind me to buy milk'?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Voice Gate
A self-hosted Jev engine that turns completed speech or typed text into ordinary speech, a command, a retained thought, uncertainty, or no action.
Run one engine wherever you choose. Call it from a Mac menu bar, a phone Shortcut, a browser, or an agent through HTTP, the CLI, or MCP. Transcription belongs to the client; Voice Gate receives text. No machine address, provider credential, or assistant destination is built into the engine.
Start locally
Requires Python 3.11+ and uv.
git clone https://github.com/beejsbj/voice-gate.git
cd voice-gate
uv sync --frozen
uv run voice-gate init
set -a; . ./.env; set +a
uv run voice-gate serveOpen http://127.0.0.1:8000. The generated .env contains your client token; paste it into the login form. The browser clears the input and uses an HTTP-only session cookie. Default fixture mode uses explicitly synthetic judgments for the five samples and uncertainty for other text. Nothing is sent to a provider.
For real judgments, set VG_PROVIDER=openrouter and OPENROUTER_API_KEY, or VG_PROVIDER=typesafe and TYPESAFE_API_KEY. Restart the engine. VG_JEV_BASE_URL and VG_JEV_MODEL optionally select another compatible endpoint/model. Credentials remain server-side. The official TypeSafe Python SDK is used directly.
Related MCP server: rbac-rag-assistant
One request to integrate
A completed turn needs one authenticated request. Client connection settings are VOICE_GATE_URL and VOICE_GATE_TOKEN (or VOICE_GATE_TOKEN_FILE). These are separate from the engine's Jev provider settings.
export VOICE_GATE_URL=http://127.0.0.1:8000
# Set VOICE_GATE_TOKEN privately, or point VOICE_GATE_TOKEN_FILE at a protected file.
printf '%s' 'Save this thought: keep my running shoes beside the door.' |
uv run voice-gate turn -HTTP equivalent; tokens are sent in headers, never query strings:
POST /v1/turns
Authorization: Bearer <client-token>
Content-Type: application/json
{"text":"Save this thought: keep my running shoes beside the door.",
"request_id":"a-unique-client-generated-id"}The response contains session_id and a decision: exact text and timing, one of five labels, a deterministic policy reason, raw Jev probabilities, latency, an optional capture, and handoff status. Reusing the same request_id with the same payload returns the original completed decision within the session/idempotency lifetime; changed payloads return 409. No target runs from this call.
For streaming partials, create a session, submit versioned transcripts, and subscribe to SSE. Both paths use the same engine. /docs and /openapi.json describe the API. See API behavior and client integrations.
Clients and assistant targets
Surface | Included route |
Browser / phone browser | Responsive UI with typed input, explicit one-utterance microphone, replay, retained thoughts and confirmed handoffs |
Mac menu bar | SwiftBar plugin example; opens the web capture surface and shows retained count |
Phone Shortcuts | HTTP JSON recipe; use the phone's dictation action, then POST the result |
Hermes / Claude / Codex / compatible agent hosts | Official-SDK stdio MCP bridge and CLI; tools call your configured engine URL |
T3 | Configure the relevant underlying agent harness; no T3-specific plugin is claimed |
Your app | Versioned HTTP API, SSE snapshots, Python client and OpenAPI schema |
The microphone is off until clicked and stops after one utterance. Browser speech support varies; keyboard dictation or another transcription client can submit the same API payload. Physical Mac/phone microphone trials and native app packaging are not claimed by the automated tests.
VG_TARGETS configures destinations by name. Supported adapters:
health: fixed read-only GET, useful for a harmless integration check.webhook: POST the exact original command and a versioned envelope to your service.openai: POST the original command to an OpenAI-compatible assistant endpoint, such as a configured Hermes API.
Targets are selected from server configuration, never URLs generated from speech. A recognized command creates a proposal; an explicit confirmed: true dispatch or UI Send command invokes one target. Its assistant owns its execution permissions. Voice Gate is not a sandbox for the target's tools. All commands require confirmation, including those flagged sensitive. There is no automatic journal, task, reminder, email or shell execution.
See .env.example for target configuration. The MCP bridge exposes judgment/inspection tools, leaving handoff confirmation with the host or user. Do not configure a target to call Voice Gate back as its own command dispatcher.
Deploy your own
# .env is generated above; select your provider and tokens before deploying.
docker compose up --build -dThe provided Compose binds only 127.0.0.1:8000 and persists captures in a Docker volume. Put an authenticated HTTPS reverse proxy in front for device access. For a private engine, a private VPN/reverse proxy is a suitable boundary. Set VG_ORIGINS to any separately hosted browser origins you explicitly permit; wildcard credentialed CORS is not used.
For orchestrators, VG_CONFIG_FILE can name a mounted JSON secret containing environment-variable names mapped to strings. Existing environment values win. Example shape without credentials:
{"VG_PROVIDER":"openrouter","VG_TOKENS":"{\"personal\":\"<random-client-token>\"}","OPENROUTER_API_KEY":"<provider-key>","VG_TARGETS":"[]"}Run one process/worker per engine: sessions, epochs, browser logins and idempotency live in memory. Do not run multiple workers against one database and expect distributed session consistency. Use VG_DATABASE for retained captures; :memory: is the development default. Docker sets /data/captures.sqlite. Back up file-based SQLite using its online backup interface or while the service is stopped. Deployment notes cover rollback, credentials, retention and limits.
What informed it
Source research found Jev Voice, Jev Voice Browser, Capture, HA-Jev and JevRouter.
Voice Gate incorporates the useful patterns: shared typed/speech input, complete/addressed/cancelled/sensitive judgments, strict finality and stale-response rejection, explicit policy reasons, whole-request assistant adapters, literal capture provenance, and a thin MCP boundary. Research notes link inspected revisions and distinguish source evidence from unverified demo claims. No third-party source was copied. Multi-thought segmentation and richer recall/reminder routing remain future work.
Checks and practical limits
uv run pytest -q
node --check voice_gate/web/app.js
npm ci
CHROME_BIN=/path/to/chrome npm run test:browserTests cover session ownership/authentication, cancellation across delayed requests, revisions and finality, idempotency, exact capture persistence, concurrent dispatch, provider failures, configuration and client adapters. Browser checks include SSE, five-outcome replay, phone layout, and synthetic speech events. Browser evidence is written to ignored test-results/; it is not a physical microphone trial.
The experimental 0.70 policy floor is not a calibrated accuracy guarantee. Provider failure and ambiguous speech produce uncertainty. The server bounds request size, live concurrency, judgments/minute, session count, per-session turns, retained count, and target response size. It is a small single-owner/self-hosted service, not an Internet-scale multi-tenant platform.
Sessions and idempotency expire after an idle hour; completed decisions are visible for the most recent 64 turns. Captures persist until deleted when a database file is configured. Discard clears that session's retained captures, transcript/decision state and cached retry results; it cannot retract text already sent to a provider or unsend a confirmed target request. No raw audio is stored.
MIT licensed.
Available Tools
3 toolsget_sessionC
Return a session snapshot.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. 'Return a snapshot' implies a non-mutating read, but it does not disclose whether the snapshot is live, cached, point-in-time, or subject to authentication or rate-limit constraints. This adds minimal behavioral insight beyond the tool name.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence with no irrelevant content. However, the brevity is closer to under-specification than effective structure, since it omits usage and behavioral context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations and a one-line description, the definition is incomplete for an agent that must decide when to invoke this tool. The output schema covers return shape, but the description still lacks a clear use case, behavioral expectations, and any reference to sibling tools for selection.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description needed to compensate for the lone session_id parameter. 'Return a session snapshot' only hints that session_id identifies the session, but it does not explain the expected format, uniqueness, or how the parameter affects the returned snapshot.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Return') and a recognizable resource ('a session snapshot'), making it clear this is a read operation for a session. It does not explicitly differentiate from siblings like interpret_transcript, but the core purpose is still clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use get_session versus interpret_transcript or list_captures. The description provides no use-case context, exclusions, or alternative routing, leaving the agent to infer selection from the tool name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
interpret_transcriptB
Interpret one transcript and return the final Voice Gate decision.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| epoch | No | ||
| session_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the primary output but does not mention side effects, input constraints, idempotency, or what 'final' implies about the decision process. This is thin for a tool with zero annotation support.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single efficient sentence with no filler. The action and outcome are front-loaded, and every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although an output schema exists, the description omits context needed for correct invocation: the meaning of epoch and session_id, how they affect interpretation, and when this tool should be preferred over list_captures or get_session. The agent is left to infer these from parameter names alone.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the description only implicitly maps 'transcript' to the text parameter. It says nothing about the purpose of epoch or session_id, leaving the optional parameters unexplained beyond their schema types and defaults.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('interpret'), a specific resource ('one transcript'), and a concrete outcome ('final Voice Gate decision'). This is clearly distinct from the sibling tools list_captures and get_session, which are list/get operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied: call this when you have a transcript and need a Voice Gate decision. However, there is no explicit guidance on when NOT to use it, nor any comparison with the sibling tools list_captures and get_session.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_capturesA
List retained captures, optionally limited to one session.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden; 'List' conveys a non-mutating read operation and 'retained' scopes what is returned. It does not disclose pagination, ordering, retention semantics, or permission requirements, but for a simple read tool with an output schema this is a moderate gap rather than a fatal one.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One short sentence with the verb and resource front-loaded and no filler. Every word earns its place, making this an appropriately sized description for a simple tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given one optional parameter and an existing output schema, the description covers the essential call pattern: no arguments lists retained captures, and session_id scopes the list to one session. It doesn't unpack the meaning of 'retained' or differentiate from sibling tools, but the tool is simple enough that this is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for the undocumented session_id parameter. It does so by explaining that the optional parameter limits results to one session, which adds real meaning beyond the bare type/default in the schema. It doesn't specify ID formats or confirm the no-argument behavior, but the core semantic is present.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the verb 'List', the resource 'retained captures', and the optional session restriction in one clear sentence. It is distinguishable from siblings by resource type, but it does not explicitly contrast itself with get_session or interpret_transcript, so it stops short of the top score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool is for enumerating retained captures and that session_id narrows results to a single session, which is useful context. However, it gives no explicit guidance on when to choose list_captures over get_session or interpret_transcript, so usage direction remains largely implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
get_session - First observed
interpret_transcript - First observed
list_captures
TDQS
Scored across 3 tools
Each tool has a clearly distinct purpose: interpreting a transcript, listing captures, and fetching a session snapshot. There is no overlap or ambiguity between them.
All tool names follow a consistent verb_noun pattern (interpret_transcript, list_captures, get_session), making the intent predictable and uniform.
Three tools is a well-scoped size for a focused voice-gate server. Each tool serves a distinct function and none feel redundant or missing.
The set covers interpreting transcripts, reviewing captures, and viewing sessions, which covers the core read-only workflow. Minor gaps exist such as no delete/export or capture detail tool, but agents can likely complete their primary tasks.
Maintenance
Related MCP Connectors
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Hosted MCP for denial, prior auth, reimbursement, workflow validation, batch scoring, and feedback.
Hosted MCP memory and agent control plane for durable conversations, jobs, and operations.
Hybrid human + AI expertise for faster, trusted answers and decisions via MCP Server.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables to run structured QuReDec decision briefs from inside MCP-compatible clients, submitting questions and receiving evidence-backed recommendations with citations.24 PyPIMIT
- FlicenseNot gradedqualityBmaintenanceEnables MCP clients to ask plain-language questions and receive answers grounded only in documents the configured role is cleared to read, with the same access-controlled tools available across any client.-
- FlicenseNot gradedqualityCmaintenanceEnables AI clients to send prompts to a local Codex App Server via MCP, returning text responses and supporting persistent session reuse.-
- AlicenseNot gradedqualityCmaintenanceEnables Alexa+ agents and other MCP hosts to analyze dry exam/card pulse text from a mock trading desk, returning structured test results, signals, problems, needs, alarms, and recommendations over Streamable HTTP. It works with an offline rules engine and optional Nebius Token Factory enrichment.MIT