M3 of my company's progress memory mechanism was DONE! ✅
The backend could now reconstruct the current state of my work on every conversation turn.
Straight from the database:
1- Current message: What I had just told it.
2- Recent turns: Our last 10 conversation turns.
3- Active items: My unfinished work (todo and in_progress).
All assembled into a single State structure, ready to be passed to the LLM alongside the system prompt.
The interesting part?
The LLM didn't have to remember everything. The backend did the remembering.
The LLM's job was to make judgements using the latest state.
Here's how I did it: 🧵
Since I already had the database and tables ready, I needed 2 functions:
1. List current items: Retrieved my unfinished work (todo or in_progress).
No need to fill the LLM's context with completed, cancelled, or dropped items.
2. List recent messages: Retrieved the last 10 conversation turns.
Next, I created a model called Interaction State that brought everything together:
current_message + recent_turns + current_items
But the LLM needed this context in a format it could actually read.
So I created a separate function to render the State into a string, ready to be included alongside the system prompt.
👇 Here's what the whole thing looked like.
Now I needed to connect it to the actual conversation workflow.
So I integrated the State builder into the backend workflow.
Every time a Telegram message arrived, the backend could:
Receive message → Store it → Build Interaction State.
All before invoking an LLM.
Which meant every conversation turn could have an up-to-date snapshot of my work and recent conversation.
But now came the hardest part.
I needed to develop a system prompt that could use all this context to make the judgements I'd designed the mechanism for.
And remember, I only had ONE LLM call to work with and with the smallest open model( Qwen3.5 9B.).
The second milestone (M2) of building my company's progress memory mechanism was complete! ✅
Here's what I had working:
1. Created the Telegram bot.
2. Implemented a webhook to receive Telegram updates.
3. Received and stored incoming messages in the database.
4. Generated and sent replies back to the originating chat.
Which meant M2's expected outcome was achieved:
A Telegram message reached the backend, got stored in the database, and a reply made it back to the same chat.
👇 The test that confirmed it worked!
Here's how I built it:
Replying to @MoTheAgent
Let's start with the milestones:
1- Foundation & MySQL: Set up the database to store users, messages and items (tasks), along with migrations for future changes.
2- Telegram Transport: Connect Telegram to the backend so messages could be received and replies sent back.
3- Interaction State: Assemble the current message, recent conversations and existing items(from the DB) to give the AI context.
4- LLM Contract: Make a single LLM invocation understand the user's intention and return a validated, structured decision.
5- Maintain Memory: execute Create/update tool calls(for maintaining the DB) and keep a history of changes based on the AI's decisions.
6- Retrieve Progress: Retrieve relevant records to answer questions like what's completed and what's still unresolved.
7- Complete Interaction: Make both workflows work end to end through Telegram.
8- Validate V1: Test speed, reliability, token usage and cost.
Basically, each milestone had a specific outcome and exit criteria before moving to the next one.
So the next step was to break each milestone down into actual development tasks.
Setting Up the Webhook
I needed 3 things:
1. FastAPI: To create an endpoint that received incoming messages from Telegram.
2. Uvicorn: To run the FastAPI application, configured through Docker Compose.
But Telegram needed a public HTTPS URL, and my backend was running locally.
3. ngrok: To expose my local server through a public HTTPS URL.
I then registered that URL with Telegram using its setWebhook API.
So the flow became:
Docker Compose started Uvicorn → Uvicorn served FastAPI → FastAPI exposed /telegram/webhook → ngrok made it publicly accessible → Telegram could send messages to it.
And just like that, Telegram could reach my backend.
Next, I needed to store those messages and send replies back to the same chat.
Receiving & Storing Telegram Messages
Now that Telegram could reach my backend, I needed to handle incoming messages.
So I implemented the /telegram/webhook endpoint to:
- Verify the request using Telegram's webhook secret.
- Extract the chat ID and message text.
- Identify the user and store the message in the database.
- Send a simple echo reply back to the same chat: you said: ...
- No AI involved yet. Just a simple way to test the entire message flow.
I also wrote Pytest tests to verify the webhook's behaviour, including secret validation, message handling, and the storage and reply calls.
And with that, M2 was complete! ✅
The actual Telegram demo was shown earlier in the thread.
For anyone interested in the implementation, here's the GitHub repo:
github.com/Xynarion/company-…
M1 of my company’s progress memory mechanism was complete. ✅
Here’s how I built it, from designing the database to running the final tests.
The entire journey, including the code, was documented in this thread. 👇
So I got to work, starting with the first milestone:
M1: Foundation & MySQL.
Expected outcome: A fully functional and tested database, ready for V1.
I started by defining the 5 tables I needed for V1:
1. Items: To store my work. Tasks, events, start dates, end dates, due dates, status, and other details.
2. Items History: To track how each item changes over time. When it was created, completed, carried over, cancelled, etc.
3. Messages: Basically, the back-and-forth conversation between me and the mechanism.
4 & 5. Users and User Channels: To store basic user information and connected channels (Telegram for now).
This way, when I eventually ship it publicly, each user will have their own items, messages, and progress history.
And here's the whole database schema, including how the 5 tables relate to each other, illustrated in an ERD (Entity-Relationship Diagram).
Now that I had the database structure figured out, it was time to turn this diagram into actual code.
So I got to work, starting with the first milestone:
M1: Foundation & MySQL.
Expected outcome: A fully functional and tested database, ready for V1.
I started by defining the 5 tables I needed for V1:
1. Items: To store my work. Tasks, events, start dates, end dates, due dates, status, and other details.
2. Items History: To track how each item changes over time. When it was created, completed, carried over, cancelled, etc.
3. Messages: Basically, the back-and-forth conversation between me and the mechanism.
4 & 5. Users and User Channels: To store basic user information and connected channels (Telegram for now).
This way, when I eventually ship it publicly, each user will have their own items, messages, and progress history.
And here's the whole database schema, including how the 5 tables relate to each other, illustrated in an ERD (Entity-Relationship Diagram).
Now that I had the database structure figured out, it was time to turn this diagram into actual code.
Replying to @MoTheAgent
Let's start with the milestones:
1- Foundation & MySQL: Set up the database to store users, messages and items (tasks), along with migrations for future changes.
2- Telegram Transport: Connect Telegram to the backend so messages could be received and replies sent back.
3- Interaction State: Assemble the current message, recent conversations and existing items(from the DB) to give the AI context.
4- LLM Contract: Make a single LLM invocation understand the user's intention and return a validated, structured decision.
5- Maintain Memory: execute Create/update tool calls(for maintaining the DB) and keep a history of changes based on the AI's decisions.
6- Retrieve Progress: Retrieve relevant records to answer questions like what's completed and what's still unresolved.
7- Complete Interaction: Make both workflows work end to end through Telegram.
8- Validate V1: Test speed, reliability, token usage and cost.
Basically, each milestone had a specific outcome and exit criteria before moving to the next one.
So the next step was to break each milestone down into actual development tasks.
Next, I needed 3 things:
1. Alembic: To manage database migrations. So whenever I changed the models in the future, I could update the database structure without rebuilding everything.
2. Pytest: To write automated tests and verify that the database operations actually behaved as expected.
3. Docker: To containerize the application and database, making it easier to run consistently across different environments.
Oh, and one last-minute change. 😂
I ended up switching from MySQL to PostgreSQL.
And with that, the foundation was ready.
But having everything set up was one thing. Actually getting it to work was another.
The migrations had to work, the tests had to pass, and the containers had to run successfully.
So I fired up the terminal and put the whole thing to the test.
Anddddd, everything passed! ✅
The database was up, migrations worked, and all the Pytest tests passed.
M1: Foundation & Database --> DONE. ✅
The first milestone of my company's progress memory mechanism was officially complete.
Still had a long way to go, but at least the foundation was in place.
And since I wanted to build this in public, I pushed the code to GitHub.
Here's the repo for anyone interested in following along:
github.com/Xynarion/company-…
Next up: M2.
So after designing the architecture, I started preparing a development plan.
A spreadsheet of milestones and tasks needed to produce Version 1 of my company's progress memory mechanism.
But why did I plan instead of jumping head-first into coding?
Because I wasn't just acting as a developer. I was also a CEO.
Time, effort and tokens mattered, especially when I was trying to build an MVP and a key company element at the same time but with as few resources as possible.
Without a clear plan, coding agents could have easily led me into building dozens of other cool features before I even shipped the MVP.
And why spreadsheet file?
To track my progress. What had I completed? What was still unresolved? And where had I left off?
Companies with teams use Jira, ClickUp, GitHub Projects, etc.
These tools all basically used as a progress memory for company's operations.
Product/project managers and developers are usually the ones responsible for maintaining that memory.
But paradoxically, the mechanism I was building was supposed to replace both the progress memory and the responsibility of manually maintaining it.
Anyway, here's what was inside my development plan spreadsheet:
Replying to @MoTheAgent
Here's the architecture I came up with.
First, the mechanism stores my message.
Then it builds the state it needs to understand what I'm talking about.
That includes our last 10 conversation turns and the company's existing items.
It combines that state with the system prompt and sends everything to the LLM.
But that's only the beginning.
What happens when the LLM decides something needs to change?
Let's start with the milestones:
1- Foundation & MySQL: Set up the database to store users, messages and items (tasks), along with migrations for future changes.
2- Telegram Transport: Connect Telegram to the backend so messages could be received and replies sent back.
3- Interaction State: Assemble the current message, recent conversations and existing items(from the DB) to give the AI context.
4- LLM Contract: Make a single LLM invocation understand the user's intention and return a validated, structured decision.
5- Maintain Memory: execute Create/update tool calls(for maintaining the DB) and keep a history of changes based on the AI's decisions.
6- Retrieve Progress: Retrieve relevant records to answer questions like what's completed and what's still unresolved.
7- Complete Interaction: Make both workflows work end to end through Telegram.
8- Validate V1: Test speed, reliability, token usage and cost.
Basically, each milestone had a specific outcome and exit criteria before moving to the next one.
So the next step was to break each milestone down into actual development tasks.
Now that I had the milestones, I needed to figure out exactly what had to be done to achieve each one.
So I broke them down into 34 tasks.
Each task had:
- What needed to be done.
- What other tasks it depended on.
- Its priority.
- Its current status.
- And most importantly, a definition of done.
That last part was important.
I didn't want to just write code and assume something was working.
I needed a way to know when a task was actually completed before moving to the next.
And since I was trying to build V1 with as little time and as few tokens as possible, I also needed to separate what was essential from what could wait.
Here's what the development plan looked like:
Few things I forgot to mention:
1. This was a conversational agent, which meant the whole workflow had to execute and generate a reply back to Telegram almost instantly.
2. As you could see, only one part of the workflow invoked an LLM. All the others were code.
3. However, that one model invocation had to make the following judgements:
For brain-dumping work changes:
- Determine if work had changed based on my text.
- Determine if the change was a new or existing item.
- Detect duplicates, conflicts and ambiguities.
- Decide whether to create, update or ask for clarification.
For recovering progress memory:
- Determine intention: orientation or reflection.
- Determine scope: the relevant time period.
- Determine shape: timeline, outcomes or patterns.
- Determine which records were relevant to show.
I knowwwwww. No way.
But that's exactly why I took on this challenge.
4. For the LLM, I chose Qwen3.5 9B.
But I was willing to go as small as Qwen3 0.6B.
🤪 What if I actually managed to pull this off?????
That much power at a fraction of the cost?
Replying to @MoTheAgent
Here's the architecture I came up with.
First, the mechanism stores my message.
Then it builds the state it needs to understand what I'm talking about.
That includes our last 10 conversation turns and the company's existing items.
It combines that state with the system prompt and sends everything to the LLM.
But that's only the beginning.
What happens when the LLM decides something needs to change?
After deciding that my company should persevere its own memory,
So I can move between different parts of my company without loosing momentum,
I started with the progress memory. The part that answers:
What’s completed ? Whats still unresolved ?
I depended on a todolist to answer them.
But the list kept getting out of date,
which meant inaccurate and time consuming to answer.
I couldn't keep being responsible for both doing the work and keeping the list up to date.
So I decided to build a mechanism that could take over that responsibility.
After 6 chapters of essays of figuring out how the mechanism should work, here is what I got:
Primary Responsibility
Keep the company's list (progress memory) up to date without depending on me to maintain it manually.
Core Capabilities
1. Notice when work changes
Reconstruct changes in the state of my work through my brain dumps.
2. Understand what those changes mean
Determine whether an existing item needs updating, a new item needs creating, or clarification is required.
3. Make sure the progress memory reflects those changes
Maintain the company's list in a persistent database.
4. Help me recover my sense of progress
Present the company's progress memory in a way that helps me form a clear mental image of where the work stands at a glance.
Since I already laid out all behavioural requirements and technical architecture constraints in my last chapter,
The only thing that was left before coding was:
Design front end architecture,
Design backend (mechanism) architecture,
Prepare development plan (building list).
Here is how the frontend architecture will work:
The mechanism needs to remember more than the message I'm sending right now.
It needs access to our recent conversations and the company's existing items.
And it needs to preserve incoming messages and the replies it sends.
So I'm using MySQL as the relational database.
The backend will use it to store messages, retrieve conversation history and existing items, and persist replies.
Here's how the database fits into the architecture.
But here's where this gets difficult.
I don't just want the mechanism to work.
I want it to be fast and cheap enough to use constantly throughout the day.
So I set myself some constraints.
1. One LLM invocation per interaction.
No matter how long the workflow is.
2. The smallest capable open-source LLM.
I don't want to depend on expensive models to make this work.
3. Ordinary code handles everything else.
The LLM should focus on understanding and making decisions. Everything that doesn't require its intelligence should be handled by code.
And it still needs to handle long brain dumps, understand context, determine what changed, and produce a valid plan.
Honestly, making all of this work under those constraints is going to be difficult.
But these are the constraints I set myself, and I need to find a way to make them work.
I've got the initial architecture.
Next, I'll share the development plan, repository and start building.










