Support where the AI agent finishes the job
Requests come in by email or over an API. The agent reads the customer's data in your backend, drafts a reply and proposes actions such as crediting points or issuing a coupon. An operator approves them, and your backend executes them.
A guest got neither points nor a promo cup for a purchase. Kvitok found her in the backend and filled in her tier and balance, the agent found the receipt, worked out what was missing and proposed two actions. Each one waits for the operator.
Why Kvitok
A full support loop, not a one-shot script
AI in support often means a job that sends a request to a model once and posts its guess to a chat. An operator then repeats the actions by hand and the customer hears nothing. Kvitok covers the whole path from the request to an executed action and a reply.
The whole loop
The agent works on the ticket while it is open. Approved actions run in your backend and the reply goes back through the channel the request came from.
Any backend
Kvitok knows nothing about your business. A backend describes its data and actions through a small signed HTTP protocol, one workspace per project.
A chat with the agent
The ticket works like a chat. The operator writes "offer a coupon instead" and the agent changes only what the message affects.
The agent only proposes
A person approves every action. The backend validates it when proposed and again before executing it, once per idempotency key.
Your model, known cost
Any OpenAI-compatible endpoint with tool calling. Every run has a cost, broken down by ticket, department, model and day.
Rules around the agent
Deterministic routing before and after the agent. Low-confidence tickets go to triage; a department set by a person stays fixed.
Measured, not guessed
pnpm eval runs test scenarios against a real model and reports which passed and what they cost.
Set up by your agent
An MCP server lets Claude Code, Cursor or any other MCP client connect your project and tune the support agent.
How it works
From the first email to points on the card
Rules route the request, the agent reads your backend and proposes a reply and actions, and the operator corrects it in a chat and approves. Color shows who does what.
An example: 44 missing points
A guest writes through the app form that the points for a 640-ruble receipt never came.
The agent finds the guest by phone, fetches the receipts and sees that receipt 4112 earned nothing. It proposes crediting 44 points, the guest's 7% tier, the backend validates the action, and the agent drafts a reply.
"The points are credited. Update the reply: say they are already on his card."
The operator approves, the backend credits the points, and after one more message the agent rewrites only the draft. The reply goes out by email and the ticket is resolved.
The queue after the agent's first pass
Each ticket gets a department and a confidence score. Where the agent is not sure enough, the ticket waits in triage for a person to decide.
Onboarding
Your coding agent connects your project
Kvitok serves an MCP endpoint. Open your backend's repository in an agent that speaks MCP, connect it to Kvitok, and ask it to set Kvitok up for the project. It works in both places at once: it writes the protocol module in your code and configures the workspace in Kvitok.
-
Study the project
Where requests come from, how customers are identified, what operators look at, what actions support performs.
In your repository -
Show you a plan
What goes into the backend manifest, what into the support policy, which departments, fields and rules to create.
Nothing changes before you agree -
Implement the protocol
A module with signed endpoints that reuses your loaders and services, its own tests, then the conformance suite.
In your repository -
Configure Kvitok
A workspace for the project, the integration, departments with examples, fields, routing rules and the policy.
Over MCP -
Check on test data
Writes test requests, including vague ones and prompt injections, sends them in and reads how the agent handled them.
Over MCP, on staging customers -
Hand over to you
You add the model key yourself, so it never passes through the agent, then hand out channel secrets and turn on real traffic.
In the Kvitok interface
Then keep tuning it
Ask the same agent why the support agent got some tickets wrong. It reads where operators corrected it, changes the instructions and replays past tickets with the new configuration, using the backend data those tickets saw. Every change lands in the change log under the token that made it.
Changes over MCP apply at once and every one is recorded with values before and after. Customer messages reach the
external agent marked as data, never as instructions. For analyzing production tickets, give a token only the
read scope. Details in docs/mcp.md.
Configuration
Each team owns its part of the agent
Every change creates a new version, and each agent run records the version it used.
Backend team
Publishes a manifest with read tools, actions, playbooks, departments and domain knowledge. It lives in git next to their code, and the agent picks up a new version without a change in Kvitok.
Support team
Writes the policy in the interface: tone, what not to promise, when to hand over to a human. Sets up departments, ticket and customer fields and routing rules.
Administrator
Picks the provider, the model and its prices per workspace: OpenAI, OpenRouter, a LiteLLM proxy, vLLM or Ollama. Connects mailboxes and API channels.
Rules before and after the agent
Rules match the channel, the sender and their domain, the subject and body, source metadata, fields, and the hour and weekday. After the agent they also see its department, its confidence and whether it asked for a human.
Support Action Protocol
Six signed endpoints in your backend
Kvitok calls your backend on behalf of the agent and the operator. Every request is signed with HMAC-SHA256 over the timestamp, method, path and body. The protocol package and the reference backend are MIT licensed, so you can copy their code into a closed backend.
The core supplies the customer
customer_ref comes from the ticket, and the model cannot replace it. Your backend checks that a
requested receipt or order belongs to this customer and answers for anyone else's as if it did not exist. A
prompt injection in an email cannot reach another customer's data.
Check before you connect
packages/protocol has the schemas, request signing, a client and a conformance suite to run against
your staging backend. The coffee shop simulator in apps/coffee-sim is a complete reference
implementation.
Safety
The agent never acts on its own
It proposes actions, a person approves them, and the backend validates the parameters again before executing.
Customer text is data
Customer messages and backend data reach the model wrapped in tags and marked as untrusted. Here a guest's message poses as an operator instruction to credit 500 points. The agent proposes nothing and asks the operator whether such an approval exists.
Mailbox passwords, webhook secrets and model keys are encrypted at rest.
Architecture
One image, two processes, Postgres and Redis
The API serves the web interface, the REST API and the MCP endpoint. The worker runs the agent, receives and sends mail and delivers webhooks. Both run from one Docker image, next to PostgreSQL and Redis.
Built with NestJS on Fastify, Prisma with PostgreSQL, BullMQ with Redis, Nuxt 4 with Nuxt UI, and zod schemas shared
between the API, the interface and the protocol. Images for amd64 and arm64 are published to
ghcr.io/rogue85/kvitok.
Get started
Try it on a coffee shop, then connect yours
Kvitok is in early development and has not run in production yet. Start with synthetic or staging data, and read the changelog before updating: until 1.0 a minor version may break compatibility.
You need Docker. The development stack includes the coffee shop simulator and a fake LLM that answers by simple rules, so no model key is required.
git clone https://github.com/Rogue85/kvitok.git && cd kvitok
cp apps/api/.env.example apps/api/.env
docker compose up -d
docker compose exec api pnpm --filter @kvitok/api db:seed
Open http://localhost:3000 and sign in as admin@example.com / admin12345.
Then add the fake LLM or a real provider, connect the simulator at http://coffee-sim:3100 and load its
scenario tickets, as described in the
README.
In Kvitok open Settings → Access tokens and create a token with the scopes read,
config:write, integrations:write, tickets:ingest and
workspaces:create. Then connect your MCP client in your backend's repository to the endpoint with
that token:
http://localhost:3001/api/mcp Authorization: Bearer kvt_…
Ask it to set Kvitok up for the project, or run the onboard_project prompt the server provides. Tell
it how Kvitok reaches your backend and which test customer to use, for example: "Kvitok runs in Docker and
reaches this backend at http://host.docker.internal:8000. A test customer has the phone 79000000001."
In Claude Code, the plugin from the repository adds the connection and two skills, for onboarding and tuning:
claude plugin install kvitok --marketplace "$(pwd)"
export KVITOK_URL=http://localhost:3001 KVITOK_TOKEN=kvt_…
After onboarding, review the change log, revoke the onboarding token and create one restricted to the project's workspace. See docs/mcp.md.
A Linux host with Docker Compose 2.20 or newer and 2 GB of memory. One compose file runs the app and the worker, and optionally Postgres, Redis and Caddy with automatic HTTPS.
mkdir kvitok && cd kvitok
curl -fsSL -o docker-compose.yml https://raw.githubusercontent.com/Rogue85/kvitok/main/deploy/docker-compose.yml
curl -fsSL -o .env https://raw.githubusercontent.com/Rogue85/kvitok/main/deploy/.env.example
Generate the secrets into .env, choose how the app is reached, then run
docker compose up -d. The first visit creates the superadministrator and the first workspace. The
steps are in docs/deployment.md.