You said 10. It took 19: a freelancer notebook for unpaid hours A developer built Quoted, an open-source tool that helps freelancers avoid underquoting by logging promised versus actual hours on past jobs. The tool uses Gemma to extract six structured facts from a client's request and TabPFN to predict a low, middle, and high hour estimate from the freelancer's own notebook, then multiplies the middle estimate by the freelancer's hourly rate to produce a quote. The developer reports testing it on a physiotherapist's request and a sample job that returned 19 hours and ₹28,500. This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle https://dev.to/challenges/hacktoberfest-week2-2026-10-12 Sometimes a freelancer says yes because the job sounds small. They promise ten hours. The work takes nineteen hours. They get paid for ten, and the other nine hours are free. That hurts in the first year, and it still hurts in the tenth. This happened to me on a small website. I charged eight thousand rupees. The work took nineteen hours, and I did not ask for the extra money. Then the same people came back for more work, and I almost promised ten hours again. I made Quoted because I wanted a notebook for that moment. Quoted is not a chatbot that invents a price. It is a place to write the hours you promised and the hours the job really took. The next time someone asks for a quote, those old hours are sitting there, so the cheap number has somewhere to get caught. Would a freelancer pay 499 rupees a month for that, so they never give the next week away for free? Maybe, if they had already given a week away. I sat with my own live site and I said no, not this month. The story of that sit-down is at the end of this post. I did not invent a friend who said yes. You start by writing jobs you have already finished: what the client asked for, how many hours you promised, how many hours it really took, and what you were paid, if you still remember. If you do not remember the money, you can leave that part blank. You do not need a file. Three jobs from memory are enough. If you already have a list in Excel, a photo of paper, a PDF, or a Word document, you can drop that in too. Then a new client sends a new ask. You paste what they wrote, and you press What should I promise this time? A model called Gemma reads that ask. Gemma is allowed to write only six facts: what kind of work it is, how many pages it has, how many extra tools it needs, how many rounds of changes they may want, how soon they want it, and whether you already know this person. Gemma is not allowed to pick the hours. Gemma is not allowed to pick the rupees. If a number shows up in the sentence that did not come from your notebook, that sentence is thrown away. A model called TabPFN then looks at your finished jobs of the same kind. TabPFN is built for small tables, about the size of one freelancer’s year. It answers with three numbers: a low guess, a middle guess, and a high guess for how long the new job will take. Quoted takes the middle number, multiplies it by what you actually earn in an hour, and rounds the money to the nearest five hundred rupees. That is the number you can send. If you do not yet have three finished jobs of that same kind, Quoted still does not mix a shop into a website. It follows the closest job of the same kind. I learned why that matters in the first-user story below. The notebook starts empty, whether you are new or you have been doing this for ten years. There is an example notebook behind a small door, and it is marked as someone else’s jobs, not yours. You do not need an account. Live site: https://quoted-32zd.onrender.com https://quoted-32zd.onrender.com Code: https://github.com/shivansh-marjara/Quoted https://github.com/shivansh-marjara/Quoted If you have about a minute, you can try it on someone else’s notebook, so TabPFN has a full list of old jobs to look at: The pad should show 19 hours and ₹28,500. It also keeps 3 extra hours, and it says not to promise less than 19. That click uses TabPFN on the live site. If TabPFN is missing, Quoted still looks at similar finished jobs and it says that it did. That dentist click is the easy path. The first time I sat with Quoted, I did not use the dentist example. I used three of my own jobs and a message from a physiotherapist in Pune. That story is under My First User. There is also a sample called Physio website by Friday if you want to paste the same kind of ask. Gemma reads the new ask and writes those six facts. It never writes the money. My laptop has only 4 GB of memory, which is not enough to hold Gemma, so Gemma runs at Google AI Studio. The weights are still open, which means I can swap that reader later. Gemma does not run on my laptop. TabPFN looks at hours that already happened, using model 3.5. It only steps in when there are enough finished jobs of the same kind. If there are not enough, Quoted looks at the closest job of that kind instead, so a clinic website does not inherit a shop’s hours. If there is no TabPFN key, the pad still fills. After the hours are chosen, Quoted checks the sentence. Every digit has to come from those hours, the extra hours, the hourly rate, or the fee. The sentence can be tried twice. If it still has a strange number, the pad shows the raw numbers instead. I also tested the “look at jobs like this” idea on a public table of old software projects, with 46 projects in the test. Guessing the average was, on average, 3115 hours away from the truth. A straight line was 2014 hours away. Looking at similar old jobs was 1972 hours away. TabPFN-3.5 was 1618 hours away, which was the closest, and it landed within 25 percent of the truth more often than the others. On one later group of projects, the straight line did better 1096 hours away versus 988 . That result is in eval/REPORT.md. I left the loss in the table. The site lives on Render in one box, so the notebook you see and the brain behind it go out together. If you open /api/health, you can see that TabPFN and Gemma are both on. The screen looks like paper because this is a notebook, not a dashboard. A year of clients should not have to be pasted into a locked chat just to get a guess. Those rows are names, hours, and what people paid. I did not keep the whole year off the internet, and I want to say that clearly. The finished jobs stay in the browser. The new ask still goes to Gemma so it can name the kind of job, and Gemma is only allowed to return six facts, never a price. A closed quote tool would guess the fee from the vibe of the message, then charge every time you ask, until you are renting your own memory. TabPFN is open for a table this small. It can fit on a freelancer’s jobs and give a low, middle, and high guess, without asking someone to upload their whole year as a prompt. Gemma is open too, so the reader is not glued to one company. The money check only works because the hours come out as a short list of numbers. A chatbot has no such list. It only sounds sure. I built it this way because a sentence should not invent ₹58,500 when the last small clinic website took 16 hours. I built this in Cursor. I do not have a DevRelay replay to embed. The work is in the commits here: github.com/shivansh-marjara/Quoted/commits/main //github.com/shivansh-marjara/Quoted/commits/main I asked freelancer friends to sit with Quoted. They were busy, and inventing them would have been a lie, so the first sit-down was me. I wrote three finished jobs, pasted one new ask, and answered three questions. For a clinic website, I had promised 10 hours and it took 16, so I gave away 6 hours. For a sari shop, I had promised 36 hours and it took 48, so I gave away 12 hours. For a coaching dashboard, I had promised 28 hours and it took 40, so I gave away 12 hours. The notebook added those up and showed 30 hours unpaid. That number was true, and for a second I felt understood. Then I pasted a new message: a physiotherapist in Pune wanted a small website by Friday, with five pages, WhatsApp, two rounds of changes, and it was the first time working with them. Quoted said not to promise less than 39 hours, and to send ₹58,500, and that it might take anywhere from 15 to 51 hours. My last small website had taken 16 hours. Thirty-nine hours is not a small website. That hurt in a different way. I had come for help, and the help was too big. Gemma had read “small website” as wiring between systems, because the message mentioned WhatsApp. The hours then mixed in the sari shop and the coaching dashboard. A clinic quote inherited a shop’s week. I changed two things after that sit-down. First, a website with a WhatsApp button is still a website. Second, the hours have to come from the same kind of finished job. One clinic and one shop is not a table of clinics, so the shop’s 48 hours should stay out of a website quote. I used the same three jobs and the same physio message again. This time the pad said 16 hours, like the clinic. It said the work might take between 14 and 21 hours, and it told me to keep 5 extra hours for myself. The shop’s 48 hours stayed out of it. Here are the three questions, answered out loud. 1.Would you pay Rs 499 a month? No, not this month. The unpaid hours already tell the truth. I would pay after I have sent two real quotes this way and they did not blow up. 2.What did it get wrong? The first time, a small website became wiring. It told me 39 hours and ₹58,500, when sixteen hours was the truth. The first load also sat on a blank red bar while I waited, and a freelancer waiting on a quote already feels that wait. 3.What do you want it to tell you next? Which old jobs it used. I wanted it to say, in plain words, that this new ask is like the clinic, not like the shop. That is what the second sit-down does now. The feeling of seeing those unpaid hours is worth paying for. The first session was not. The second one was closer. If you have ever promised ten hours and it took nineteen, I would like to hear it in the comments. Would you have paid 499 rupees a month so the next week stayed paid? What would you want Quoted to tell you next?