Patrick Diaz

Vision · Part 01

Telegram adapter and signed sender

A thin adapter between my phone and Vision. It lets through only my own messages from my private chat, signs every one of them, and agent core trusts nothing that isn't signed.

As of 2026-11-12

You are hereVision · map

What it does

Telegram was the first way to talk to Vision and is still the one on my phone. The adapter between the two is deliberately thin: it passes my messages to agent core and the answers back, with no model, no database and no records of its own.

It is also where Vision learns who is talking to it. Every message the adapter passes on is signed, and agent core accepts nothing else. This page names those layers and why each exists; the details stay private.

PHONE MY PRIVATE CHAT TELEGRAM ADAPTER ONE USER · ONE CHAT SIGNS EVERY MESSAGE signed AGENT CORE VERIFIES, REFUSES THE REST BEFORE A RUN everyone else, stale DROPPED NO RUN, NO MODEL accepted RUN WITH ITS ORIGIN RECORD MY PRIVATE CHAT TELEGRAM ADAPTER ONE USER · ONE CHAT SIGNS EVERY MESSAGE DROPPED OTHERS, STALE signed AGENT CORE VERIFIES, REFUSES THE REST BEFORE A RUN RUN WITH ITS ORIGIN RECORD
Fig. 1.1 Only my own messages from my private chat get through, each one signed by the adapter. Agent core verifies before any run starts, and every accepted run keeps a record of where it came from.

Why this way

Decision 01

A thin adapter

The adapter has no model access, no database and no run records. It passes my messages to agent core and sends the answers back; agent core does everything else and records every message. Replacing Telegram later means replacing only this one small service.

Decision 02

One user, one chat, everything else dropped

A message counts only if it comes from me, in my private chat with the bot. Anything else gets no reply and no call to agent core, and leaves a single log line without sender, chat or text. Only text is accepted for now; voice notes, photos and files get a short “text only” reply and never reach agent core.

Decision 03

Safe behaviour after an outage

Messages from one chat are handled one at a time, so the conversation stays in order, while commands skip the queue, so a stop isn’t stuck behind a slow start. A message older than 15 minutes isn’t run at all, commands included; I get a note that it arrived while the bot was offline and should be sent again. A backlog of paid messages never runs unseen after an outage.

Decision 05

Every message signed, unsigned ones refused

The adapter signs every message it passes on, commands included, with a key that only it holds. Agent core checks the signature against what it knows itself, not against what the request claims, and only a verified message from me in my private chat counts as me. Anything that isn’t a fresh, verified message from me is refused before a run starts or any model is called. The trusted keys are part of the reviewed configuration, so a change of trust shows up in review, and several can be trusted at once so a new key can overlap the old one. Every accepted run gets an origin record that agent core can only add to and read.

Rejected: treating unsigned requests as an untrusted sender in a separate conversation

That was my own first idea. An untrusted sender that still reached the strong model would get my knowledge, file and homelab tools. No legitimate caller sends unsigned requests, so they are simply refused.

How it's tested

A probe after the switch

After signing went live, an unsigned request got a refusal and a refused-run record without its text. My phone tests passed: a message, the status line with its count of origin records, and stop and resume.

The origin audit

The status command checks that every chat run of the last 7 days has a valid origin record, and an audit every 10 minutes logs a warning for any run that doesn’t. Refused requests are recorded too, without their text.

What I learned

Case 01

The sender was just a claim

What happened

To test a new skill, the coding agent sent three messages straight into agent core from inside the system. I had asked for the test, but the messages didn’t come from my phone, and the run records looked exactly like mine. Agent core believed whichever sender a request named.

What I changed

First a hard rule, enforced by the guardrail: the coding agent never sends chat messages, and every test that depends on who I am is sent by me from my phone. Then the signed sender: the adapter signs every message, and agent core refuses anything unsigned before a run starts.

Result

Only a verified message from me counts as me, and every chat run carries a record of where it came from.