Product

A gateway, not an agent framework.

DreenMind owns the turn, the state, and the authority boundary. Models propose; tools act only after the gateway records the attempt. This page describes the gateway without rounding up its status.

ImplementedTested locallyLive behavior unverifiedOne operatorApache-2.0

What DreenMind is

DreenMind is a local-first agent gateway written in Go. It runs on your machine, exposes a loopback HTTP API, and gives the operator a CLI plus an optional Telegram channel. The gateway, not the model, owns conversation state, tool execution, approvals, and the record of what happened.

The design target is one operator on one machine. There is no hosted control plane, no team tenancy, and no assumption that the model provider is trustworthy. The provider is an edge adapter. The state stays local.

Runtime

Single Go binary

Go 1.26.x; CGO disabled for release builds.

State

SQLite with WAL and FTS5

Sessions, messages, tool calls, approvals, usage.

Access

Loopback HTTP + bearer

CLI first; optional Telegram private chats.

Provider

OpenAI-compatible

Chat completions with tool calling.

Tools

Workspace and web fetch

Default-deny; exact host allowlists.

License

Apache-2.0

Permissive license.

One turn, in order

The turn loop is deliberately boring. The order is the safety property: state is written before an external effect, and the result is appended as untrusted data.

  1. The CLI or Telegram adapter submits a message to the gateway.
  2. The gateway persists the user message and creates or loads the session.
  3. The provider is called with a bounded history and the available tool schemas.
  4. The assistant message and any tool-call rows are persisted before execution.
  5. The tool is checked against policy: name, path, host, size, and approval state.
  6. If approval is required, the call waits up to 60 seconds for a CLI or API decision.
  7. The tool runs with a timeout and a bounded output size.
  8. The result is recorded as an untrusted tool message and fed back to the provider.
  9. The loop ends with a final assistant message, a failure, or an explicit stop.
  10. On restart, an interrupted tool call is closed with a synthetic error rather than replayed.

The receipt is not telemetry

The record is local and operator-owned. It exists so the next turn, the next process, and the operator can tell what happened. It is not sent to a hosted dashboard.

What the gateway owns

The database is the source of truth. The model context is a projection, not the record. The gateway writes before it acts and keeps enough detail to explain a failure without guessing.

RecordWhy it exists
SessionOne conversation boundary, channel identity, and timestamps.
MessageUser, assistant, tool, and system-visible turns with ordering.
Tool callName, arguments, policy decision, approval, result, error, timing.
ApprovalScoped request, expiry, single-use decision, and actor.
UsageProvider token counts and model metadata when available.
Message searchFTS5 index with a rebuild path through doctor --repair.

SQLite runs in WAL mode. Startup performs a quick integrity check. Corruption is treated as an operational failure, not a reason to silently reset state.

Security invariants

  • Loopback only. The gateway binds to loopback. Remote access is the operator’s tunnel or reverse-proxy problem, not a built-in public listener.
  • Secrets stay out of config. The vault uses Argon2id and AES-GCM. Secrets are referenced as secret:// and redacted from logs and errors.
  • Tools are deny-by-default. Workspace read/list are on; write and move are opt-in. Paths are confined with os.Root, with UTF-8, size, and symlink checks.
  • Web fetch is exact-host. The allowlist is explicit. DNS is revalidated, private and link-local addresses are blocked, and redirects are not a way around the list.
  • Approval is a capability. Requests are scoped, single-use, and expire after 15 minutes. The gateway exposes decisions through the CLI and HTTP API, not Telegram buttons.
  • Tool output is untrusted. A fetched page or file cannot promote itself into instructions. The gateway records it as tool data.
  • Sandbox is fail-closed. The Docker contract exists; execution is disabled when Docker is unavailable. There is no shell or execution tool.

Status, without rounding up

ClaimLabelWhat the label means
Core loopTestedAgent, gateway, state, and app tests pass locally.
Provider adapterImplemented UnverifiedWorks against a fake HTTP server; no live provider call.
Telegram adapterImplemented UnverifiedPrivate-chat logic and fake API tests; no live bot.
ApprovalsTestedSingle-use, expiry, and timeout behavior tested.
Docker sandboxPartialContract and fail-closed behavior tested; no escape suite.
UpdatesPartialChecksummed draft artifacts; no signing or SBOM.

“Verified” is reserved for a claim tested in the environment it names. The current tree does not claim verified live provider or Telegram behavior.

Known limits

  • Source-first distribution; no hosted control plane.
  • No live verification against a real model provider or the Telegram Bot API.
  • No streaming responses, embeddings, image, or audio support.
  • No semantic memory; message search is FTS5 only.
  • No teams, shared tenancy, group Telegram chats, or multi-user approvals.
  • No shell or execution tool, and no sandbox escape test suite.
  • No signed updates, SBOM, or automatic updater.
  • No rate limiting, per-tenant budgets, or compaction policy.
  • Windows builds are supported, but untrusted execution remains disabled.

Non-goals

DreenMind is not trying to be a marketplace, a multi-agent orchestrator, or a hosted control plane. It is not a general workflow engine. It does not promise that a model is correct, safe, or cheap. It promises that the gateway records what it allowed and what it refused.

Those refusals are part of the product. A smaller surface is easier to test, explain, and recover.