The clock is not mine, and that is the whole point
I built a bot so a day costs me one text message, and so that the time on it is not a time I chose.
I have started a journal four times. Every one of them died the same way. The writing was never the problem — opening the laptop was. By the time the editor was in front of me the day had gone cold and I was writing a report about myself instead of putting down what happened.
So the thing I built is not a journal. It is a way of not needing one. I send a message to a bot on my phone, and a dated markdown file is in the repository before I have put the phone down. That is the whole interaction. There is no app, no form, no login, and nothing to open.
The rule I built it around
Everything on this site is dated, and a date is the only thing here a stranger can actually check. Which means a date I typed is worth very little. If I can choose it, I can choose it wrong, and nobody reading can tell the difference.
So the bot does not take my word for when something was captured. It takes
Telegram’s. The captured field on every file comes off the messaging
service’s clock, and there is no way for me to set it — not from the message,
not from a file header, not by hand afterwards. If I want to lie about it I
have to go and edit the repository, and the commit history is sitting right
there saying when the file arrived.
I can date the subject. I cannot date the evidence. A day can say the work happened in 2021 — several of them do, and they are marked as reconstructed from photographs, with the source they came from. But nothing can move the moment it was written down.
What it actually does
One day is one file. Send a message and it starts src/content/days/ for
today. Send a second message the same day and it does not make a second file —
it appends a paragraph to the same one, behind a clock mark, so a day that
happened once is counted once. That sounds like a small thing and it is the
reason the counts on this site can be trusted at all.
Photographs go with it. A photo becomes a file under public/media/, embedded
in the day, and I do not have to say where to put it. A .md or .txt file
with type: note in its header becomes a note instead of a day, with the slug
taken from the title — and because the slug is stable, sending the same file
again revises the note rather than leaving me with two of them.
Anything else is refused in the chat and nothing is written. I sent it a .pdf
to check.
No database, and no server
It is a Cloudflare Worker. It receives the Telegram webhook, and it commits through GitHub’s contents API straight into this repository. There is nothing else: no database, no queue, no admin screen. Git is the log.
That was not a performance decision, it was a maintenance one. Anything I have to keep running is something that can quietly stop, and I would find out weeks later with a gap in the record. A Worker with no state either commits the file or tells me in the chat that it did not.
There are eight files in it and each one does one thing. Time is a fixed +05:30 with no timezone library and no daylight saving, because India has neither. Base64 encoding is done in chunks, which is not a detail I chose to find interesting — it is there because Devanagari came out broken the first time and I had to work out why before it would survive the trip into git.
There are 68 tests. I ran the whole thing end to end on 2026-08-22 before I
trusted it with anything: a message, a second message the same day, a photo, a
note file, a refused .pdf, a wrong secret, and a message from a chat that is
not mine.
It cannot publish
This is the part I would keep if I had to throw the rest away. Everything the bot writes lands as a draft, and a draft is invisible to the whole site. It becomes readable only if the message says so explicitly.
I need that gap. Without it every half-thought I typed on a bus would be a public claim the moment I sent it, and I would start editing myself before sending — which is the same failure as the laptop, arriving from the other direction. With the gate, a rough note can sit in the repository for a week being nothing in particular, and I decide later whether it was true.
What went wrong
On 2026-08-23 I renamed two directories on the site. editions became days
and essays became notes. The site built, the tests passed, and I did not
redeploy the bot.
So for a while the live bot was writing files into two directories that no longer existed, and adding a field the schema now rejects. Nothing was lost, because git keeps what it is given, but nothing arrived where I could see it either. It has now landed writing in a directory that does not exist twice, and both times I found it by sending a message and going to look rather than by noticing beforehand.
The lesson is not “remember to deploy”. It is that the bot and the site are two programs that share one set of path names, and nothing enforces the agreement between them. I have written the rule down — change a path, deploy, send one message and check — which is the weakest kind of fix, because it depends on me reading my own notes. A test that fails when the two disagree would be the real one. I have not written it.
Where it stands
The bot is live and I have not sent it anything worth publishing yet. The count beside it on this site is zero, and it says zero rather than nothing, because a tool that works and has not been used is a different state from a tool that does not work.
That is the next thing, and it is on me rather than on the code. Every day on this site so far was reconstructed years afterwards from photographs, and every one of them says so. Every day from here should be one I sent from where I was standing.

This is a seedling. It is rough and I have published it anyway, because a drafts folder is where writing goes to stop.