Labsco
bnomei logo

Vent

from bnomei

Have your agents file their own bug reports

๐Ÿ”ฅ๐Ÿ”ฅโœ“ VerifiedFreeQuick setup

vent-mcp

Crates.io Downloads

Allow your agent to complain before the same paper cut becomes tomorrow's bug.

vent-mcp is a small STDIO MCP server that gives agents a non-destructive place to send actionable feedback while they work. Agents can report blocked work, repeated failures, missing capabilities, confusing workflows, or operational friction without interrupting the task flow.

The crate is named vent-mcp; the installed binary is named vent. The Rust library surface supports that binary and is not a stable embedding API.

The idea pairs well with Benjamin Verbeek's talk, The agent that files its own bug reports and the official Lovable blog post.

CLI

With no arguments, vent starts the STDIO MCP server:

vent

Use the same binary from a shell when the cli feature is enabled:

vent list
vent "The queue changed mid-run."
vent --channel automation "The failing check output was hard to correlate."
vent --mcp

Successful CLI delivery prints the event id and channel:

vented aZ8pQ2xK to feedback

Message text is trimmed before delivery. Empty messages and unknown channels are rejected before any sink receives an event.

MCP tools

vent-mcp exposes a small tool surface:

ToolPurpose
ventSend actionable feedback to the configured default channel or to a named channel.
list_channelsList configured channel names and descriptions when multiple channels are available.

When the config contains only the default channel, list_channels is hidden and the vent input schema only contains message. When multiple channels exist, list_channels is exposed and vent accepts an optional channel.

Example multi-channel vent input:

{
  "message": "The failing check output was hard to correlate with the changed file.",
  "channel": "automation"
}

The vent response is an acknowledgement:

{
  "ok": true,
  "eventId": "aZ8pQ2xK",
  "channel": "automation"
}

If delivery fails, ok is false and error contains the first sink failure. The eventId is a short trace id, not a deduplication key. Agents should not send repeated vents for the same issue unless they have new root-cause evidence.

Channels, sinks, and providers

vent-mcp keeps routing deliberately simple:

  • A channel is the route the agent can choose, or omit to use default_channel.
  • A sink is a concrete destination, such as local JSONL logging or a webhook.
  • A provider is a webhook payload shape.

Sink names and channel names do not have to match. For example, an automation channel can write to the default log and post to Discord:

default_channel = "feedback"

[[channels]]
name = "feedback"
description = "General feedback."
sinks = ["log"]

[[channels]]
name = "automation"
description = "Build, test, CI/CD, deployment, scheduler, or pipeline failures that blocked progress."
sinks = ["log", "discord-automation"]

[[sinks]]
type = "jsonl"
name = "log"

[[sinks]]
type = "webhook"
name = "discord-automation"
provider = "discord"
url = "https://discord.com/api/webhooks/..."
timeout_ms = 10000

With this config, channel = "automation" vents are written to vents.jsonl and posted to Discord. Other channels go only to the sinks they list.

Webhook providers

Webhook sinks POST JSON. With no provider, or with provider = "raw", the raw vent event is sent unchanged.

Built-in provider maps include:

ProviderShape
zapier, make, n8n, pipedream, workatoRaw canonical event fields.
iftttmessage, channel, and project mapped to value1, value2, and value3.
slack, mattermostText plus attachment-style project field.
discordcontent plus an embed field for project.
microsoft_teams, google_chat, webexText-only message field.

Custom provider maps live in the same TOML config file. The left side is a canonical event field and the value is a dotted JSON output path. Numeric path segments create arrays. If field_label_key is set, paths ending in .value also get a generated label such as Project.

[providers.discord]
field_label_key = "name"
message = "content"
project = "embeds.0.fields.0.value"

[[sinks]]
type = "webhook"
name = "discord-automation"
provider = "discord"
url = "https://discord.com/api/webhooks/..."
timeout_ms = 10000

Webhook headers read values from environment variables:

[[sinks]]
type = "webhook"
name = "private-endpoint"
url = "https://example.test/vent"

[[sinks.headers]]
name = "Authorization"
env = "VENT_WEBHOOK_AUTH"

If a webhook returns a non-2xx response, the error preview is shortened and known URL or header secrets are redacted before the caller sees it.

Development

Run the test suite:

cargo test

Build a release binary:

cargo build --release

Source anchors:

  • src/main.rs: binary mode selection, config loading, CLI output, and MCP server startup.
  • src/config.rs: config path resolution, defaults, validation, and built-in provider maps.
  • src/server.rs: MCP tool definitions and dynamic tool-surface shaping.
  • src/delivery.rs: message trimming, channel selection, event construction, and acknowledgement output.
  • src/sinks.rs: JSONL writing, webhook delivery, env-backed headers, timeout handling, and error redaction.
  • src/provider.rs: provider path validation and webhook JSON rendering.
  • tests/cli.rs: process-level CLI behavior and config bootstrapping coverage.