cd /news/ai-agents/sloth-mode-an-agent-that-does-your-d… · home › topics › ai-agents › article
[ARTICLE · art-154755] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Sloth Mode: an agent that does your dread while you do nothing

Developer Harish Kotra built Sloth Mode, an open-source local app that uses the Gemma 3 4B open-weight model to triage a user's avoided to-do list into three bins (do now, delegate to the model, or drop) and then drafts the delegated items itself. In a recorded run, 14 tasks were reduced to 2 for the user that day, 7 drafted, and 3 dropped, with the app estimating 3h 31m of work eliminated in 117 seconds of machine time. The project enforces its rules in code rather than in the prompt, parsing a line-per-item table format that degrades gracefully instead of crashing on malformed output.

read7 min views3 publishedOct 21, 2026

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady

I keep a note on my phone called "the pile". Fourteen things in it. The invoice I owe Priya a reply on. The dentist I have not booked in two years. The gym membership I keep paying for. Some of it has been in there since March.

On Sunday night I pasted all fourteen lines into a thing I built over the weekend, and pressed one button. Two minutes later it told me two of them needed me today. It had already drafted seven. It told me to throw three away, with a reason for each. Two more it moved to "later this week" without asking me to feel bad about it.

That is the whole product. Sloth Mode takes the pile you are avoiding and gives you back a much smaller pile.

A local open-weight model (Gemma 3 4B, on your machine, no internet) sorts every line into three bins:

Then it does the second bin. Not advice about the work. The work. The email is written. The cancellation is written. You skim, you send, you close the tab.

Who it is for: anyone with a note called "the pile". Freelancers, one person businesses, people who are good at their job and quietly three weeks behind on admin.

The video is one real run, 2 minutes 45 seconds, nothing sped up. 14 things in. 2 left for me today, 2 moved to later, 7 drafted, 3 dropped. 3h 31m of estimated work gone, in 117 seconds of machine time.

Nothing in that clip is a fixture. The drafts are the model's output, streamed at nine tokens a second, which is also why the clip is that long.

The sloth itself is hand drawn SVG, animated in plain CSS: it drops onto the vine when the page loads, swings, blinks, shuffles its grip hand over hand while it drafts, bobs along the track when it advances, and dozes off with drifting z's when you leave it waiting. No GIF assets, no animation library, about four kilobytes of keyframes, and all of it stops dead under prefers-reduced-motion.

If you want to see the result without installing anything: the app ships a recorded session behind one button. It renders the real card from that run, labelled as recorded, with the arithmetic open for inspection. I would rather show a captured run than a bright green demo that is secretly a fake.

github.com/harishkotra/sloth-mode

Vite, React, TypeScript. A ~200 line Node server that serves the app and proxies chat completions to any OpenAI-compatible endpoint. No agent framework, no orchestration layer, no vector database, no account. One dependency that matters: a model.

npm install
ollama pull gemma3:4b
npm run build && npm start   # http://localhost:8787
npm test                     # 22 tests: arithmetic, parser, policy, draft cleaner
npm run smoke                # the real triage prompt and one real draft
npm run eval                 # the reliability audit

Three decisions did most of the work.

Small models write bad JSON and good tables. So the triage prompt asks for exactly one line per item, in order:

<number>|<DO or SLOTH or GONE>|<minutes>|<reason>

1|DO|30|electricity needs paying, avoid late fees
2|SLOTH|10|routine reply, no judgement needed
3|GONE|0|nobody has asked about this in a month

The parser maps by index, so one malformed line degrades to a default instead of a crash. Gemma 3 4B returns a clean table for a fourteen line pile almost every time. It returns clean JSON about half the time.

Asking a model to "keep it to two things" is not a policy, it is a wish. So the app enforces the rules afterwards:

That second rule exists because a small model is quick to protect you from yourself. It will happily drop "cancel the gym membership" and call it efficient. Dropping things you still care about is not efficiency, it is avoidance with a nicer interface.

The generation is real. The delivery is throttled to nine tokens per second by default, adjustable from 2 to 60.

I expected this to be decorative. It turned out to be the most useful part of the interface:

Every agent demo I have built asks you to sit and watch it work. This one makes watching boring on purpose, and that is what makes it usable.

The risk with a small model is not that it cannot write a cancellation email. It is that it sorts the same pile differently every time you run it. So the repo has an audit script, and the number is real:

npm run eval     # 5 runs of the real triage prompt over the same 14 item pile

Gemma 3 4B, five runs, one pile:

4 do / 7 sloth / 3 gone in all five runs So the sorting is stable and the minutes wobble by twenty. That is exactly the shape I expected, and it is why the product quotes the review cost as a fixed subtraction while the estimates get called estimates.

The drafting is less trustworthy than the triage, so there are three defences, and only one of them is a prompt:

NEEDS: path lets it refuse when the task needs a document it does not have. That third rule earned its place during testing. In the model answer I captured as a test fixture, Gemma dumped five items, including "cancel the gym membership" and "reply to the guy who keeps pitching me crypto". The code pulled both back to the sloth.

Both the parser and the policy are tested against that real captured answer (src/lib/__fixtures__/triage-raw.txt), not a hand written mock, because a mock would only prove that my parser agrees with my imagination.

The headline number is attention reclaimed, and it is deliberately not flattering:

attention reclaimed = Σ(estimated human minutes of delivered drafts) − 2 minutes of review per item

One real session, run exactly as shipped:

| Items in | 14 | | Left for me today | 2 | | Moved to later this week | 2 | | Drafted by the sloth | 7 | | Dropped with a reason | 3 | | Estimated human minutes drafted | 225 | | Review cost subtracted | 14 | | Attention reclaimed | 3h 31m | | Machine time at nine tokens a second | 117 seconds |

Run the same pile again and the estimate moves by twenty minutes, because the minutes come from a model. The subtraction does not move. Neither does the fact that the seven drafts are real text you can send with a number filled in.

The card has a Show the arithmetic panel that lists every counted draft, every subtraction, and everything excluded, so the number can be checked by hand instead of trusted.

Three things, and none of them are "it was cheaper".

The pile is the most personal text you write all week. Mine has my landlord, my dentist, an invoice, a recruiter I am quietly talking to, and the name of a gym I am embarrassed to still be paying for. Sending that to an API means trusting somebody's retention policy. Running a 4B model on my own machine means there is no server to opt out of. The app can honestly say nothing left the machine, because there was nowhere for it to go. That is a structural guarantee, not a promise in a settings page.

The work is boring, so the model can be small. Triage and short drafting are exactly what a 4B model does well. A frontier model would write a slightly better cancellation email and cost a hundred times more to do it. When the job is "write the thing I have been avoiding for three weeks", good enough shipped at 11pm beats perfect next Tuesday. Small models also mean it runs on the laptop you already own, offline, on a train.

Cost is fixed at zero, so the app can stay free. The whole product is one prompt with an opinion about how much work a person should do in a day. It should not need an account, a subscription, or a rate limit. Set it up once and it works forever, including when the internet does not.

The open part is not only the weights. The prompt, the guardrails and the arithmetic are all in the repo, so you can disagree with my definition of reclaiming attention and change it. That is the part a closed product cannot give you.

localStorage because that is the right amount of infrastructure for this product.

── more in #ai-agents 4 stories · sorted by recency
── more on @harish kotra 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/sloth-mode-an-agent-…] indexed:0 read:7min 2026-10-21 · —