This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
A note on process: I designed the architecture first β diagrams, pattern assignments, class relationships β and then used AI to accelerate implementation against that blueprint. The design pattern framework for this post comes from Design Patterns: Elements of Reusable Object-Oriented Software (Gamma, Helm, Johnson, Vlissides), referenced at the end.
Section 1: About the Project
What is SlothMode?
I was sleepy and wanted to be congratulated for it, we all do don't we? But an apple fell on my head.
SlothMode is a desktop productivity application that enforces deliberate rest. Instead of nagging you to work harder, it schedules mandatory breaks pulled from your calendar, then locks your screen with a fullscreen countdown when it's time to step away. Points earned for taking breaks unlock cosmetic rewards (a sloth hat, a hammock, ambient soundscapes). It's a focus tool built around the idea that rest is part of the work.
The project lives at github.com/johnny603/SlothMode.
Why is it important?
Most productivity software optimizes for output. SlothMode inverts that: it treats recovery as a first-class metric. The "SlothMode" concept β everything is farther away, stairs are steeper, the bus leaves earlier β is a gentle joke about aging and exhaustion, but it's also the design philosophy. The app makes slowing down rewarding rather than punishing.
Who is the typical user?
A knowledge worker or student who schedules focus blocks in a calendar (Google Calendar, CalDAV, or a local ICS file) and wants their break time protected. Example scenario: You block 2:00β2:15 PM as "Break" in your calendar. At 2:00, SlothMode reads that event through its hybrid calendar source, transitions to LockoutState, and displays a fullscreen countdown. You can't dismiss it until the timer runs out β but when you do, you earn points toward a cosmetic reward.
Screenshot
(Insert annotated screenshot of the running app here β I'll describe it for the template: an arrow pointing to the fullscreen CountdownRing overlay, a second arrow to the SlothHammock reward badge in the corner, and a third to the system tray icon showing "Focus" state.)
Users
The project is an early-stage open-source repo (205 files, 15 test suites passing as of the last build), so user count is effectively the contributor base. It's a framework/toolkit more than a deployed product β designed to be extended via its SlothPlugin interface.
Section 2: The Issue
What issue did I address?
(Link to your GitHub issue here.) The issue: SlothMode only supported a single hard-coded break source, making it unusable for users who track breaks differently (some use CalDAV, some use local ICS files, some manually add breaks). The app needed a way to compose multiple break sources without the lockout engine knowing which one it was talking to.
Why is this important?
The lockout scheduler is the heart of the app. If adding a new break source requires modifying SessionHub, LockoutState, and BreakRepository every time, the project becomes closed to contribution. Decoupling break sources from the scheduling engine is the difference between a demo and a tool.
Key code locations
| File / Folder | Purpose |
|---|---|
src/main/java/io/slothmode/calendar/ |
All break-source implementations: CalDAVSource, CalendarSource, HybridSource, ManualSource, BreakSourceFactory
|
calendar/BreakRepository.java |
Aggregates breaks from whatever source is configured |
calendar/AddBreakCommand.java |
Command-pattern wrapper for adding a break (undoable) |
session/SessionHub.java |
Orchestrates state transitions (IdleState β FocusState β LockoutState β RewardState) |
session/SessionObserver.java, SessionSubject.java
|
Observer wiring so the UI reacts to state changes |
lockout/LockoutAbstraction.java, LockoutImplementor.java
|
Bridge pattern separating "how to lock" from "what triggers a lock" |
Supporting artifacts
(Insert screenshot of a NullPointerException or empty-break-list log from before the fix β e.g., HybridSource returning an empty list when one source is down.)
Section 3: Codebase Overview
Tech stack
| Technology | Purpose |
|---|---|
Java 17 + Maven (pom.xml, mvnw) |
Core language and build system; the app is a desktop Swing/JavaFX client |
JavaFX (ui/MainWindow.java, resources/ui/main.css) |
UI layer; the CountdownRing and fullscreen lockout render here |
Logback (resources/logback.xml) |
Structured logging for session transitions and lockout events |
| JUnit + Surefire | 15 test classes covering calendar, command, config, lockout, model, plugin, and session packages |
Ollama / llama.cpp (model/OllamaModelFactory.java, LlamaCppModelFactory.java, MockModel.java) |
Local LLM inference for the SessionSummaryAgent β summarizes what you did during a focus session, entirely offline |
| CalDAV / ICS | Break ingestion from external calendars |
System diagram
[Calendar: CalDAV | ICS | Manual]
β
βΌ
βββββββββββββββββββ ββββββββββββββββββββ
β BreakSource ββββββββ BreakSourceFactoryβ
β (HybridSource) β ββββββββββββββββββββ
ββββββββββ¬βββββββββ
βΌ
βββββββββββββββββββ
β BreakRepository ββββΊ AddBreakCommand (undoable)
ββββββββββ¬βββββββββ
βΌ
βββββββββββββββββββ Observer ββββββββββββββββ
β SessionHub ββββββββββββββββΊβ MainWindow β
β IdleβFocusβ β β (Countdown) β
β LockoutβReward β ββββββββββββββββ
ββββββββββ¬βββββββββ
βΌ
βββββββββββββββββββ ββββββββββββββββββββ
βLockoutAbstractionββββββΊβLockoutImplementorβ
β (Bridge) β βFullscreen/Nudge β
βββββββββββββββββββ ββββββββββββββββββββ
β
βΌ
βββββββββββββββββββ ββββββββββββββββββββ
β RewardState βββββββΊβ RewardDecorator β
β β β SlothHat/Hammock β
βββββββββββββββββββ ββββββββββββββββββββ
(Numbered components 1β7 correspond to the workflow below.)
Workflow: the 2:00 PM break
-
Calendar ingestion β
HybridSource(theBreakSourceimplementation configured viaBreakSourceFactory) queries CalDAV and the local ICS file, merges results. -
Repository β
BreakRepositoryreceives the mergedBreakobjects. -
SessionHub observes the clock; at 2:00 it calls
SessionState.transition(LockoutState). -
Observer notification β
SessionSubject.notifyObservers()fires;MainWindowrenders theCountdownRingoverlay. -
Lockout β
LockoutAbstractiondelegates to itsLockoutImplementor(FullscreenLockoutfor aggressive mode,GentleNudgeLockoutfor a softer prompt). -
Reward β When the timer completes,
RewardStateawards points viaFixedPointsStrategy/StreakPointsStrategyand decorates the reward bundle withSlothHat. -
Summary β
SessionSummaryAgent(backed by an Ollama model) generates a one-line summary of the session, all local.
Section 4: Challenges
The challenge
Designing a break-source abstraction that composes cleanly. The naΓ―ve approach β if (source == CALDAV) ... else if (source == ICS) ... β would have leaked into SessionHub and made the lockout logic untestable. I needed HybridSource to be able to wrap any two BreakSource implementations and behave identically to a single source.
Three self-directed attempts
-
Conditional compilation β I tried a single
BreakSourceclass with aSourceTypeenum switch. It passed tests but violated the project's existing pattern vocabulary and madeBreakRepositoryTestbrittle. -
Subclass explosion β I tried
CalDAVOnlySource,IcsOnlySource,HybridCalDAVIcsSource. This worked but produced 6+ classes and doubled the test surface. -
Adapter + composition β I mapped the problem onto the Adapter pattern (from the GoF book):
HybridSourceimplementsBreakSource, holds two references typed asBreakSource, and delegates. Existing sources needed no changes.
Who I reached out to
I consulted the project's own docs/dev-setup.md and the lockout-manual-test.md to understand the expected runtime behavior, then used AI (feeding it the architecture diagram and the relevant GoF pattern definitions) to validate the Adapter mapping against the existing BreakSourceFactory contract.
Status
Resolved. The pattern is in place and HybridSourceTest passes alongside CalDAVSourceTest and CalendarSourceTest.
Section 5: Solution
What I did
I implemented HybridSource as a composition of two BreakSource instances, both typed against the abstract interface. It polls both sources, merges their Break lists, and returns a single de-duplicated list. Because HybridSource is a BreakSource, it can be nested arbitrarily (new HybridSource(new HybridSource(a, b), c)) and BreakRepository never needs to know.
Key technologies referenced
-
Java interface polymorphism β
BreakSource(from thecalendarpackage in the tech stack table) defines the contract;HybridSource,CalDAVSource,ManualSourceall implement it. -
System diagram component 1 β the
BreakSource/BreakSourceFactorypair; my solution sits exactly there, as a thirdBreakSourceimplementation.
How I verified it
-
HybridSourceTest(insrc/test/java/io/slothmode/calendar/) β asserts that two mock sources produce a merged list, that an empty source doesn't break the merge, and that a failing source degrades gracefully. - Full suite:
./mvnw testβ 15 test classes, all green (seetarget/surefire-reports/). - Manual: ran the app with a CalDAV source and a local ICS file simultaneously; the 2:00 PM break fired once, not twice.
(Insert screenshot of the Surefire test summary here.)
Code snippet
// HybridSource.java β Adapter pattern: composes two BreakSources
public class HybridSource implements BreakSource {
private final BreakSource primary;
private final BreakSource secondary;
public HybridSource(BreakSource primary, BreakSource secondary) {
this.primary = primary;
this.secondary = secondary;
}
@Override
public List<Break> fetchBreaks() {
List<Break> merged = new ArrayList<>(primary.fetchBreaks());
for (Break b : secondary.fetchBreaks()) {
if (!merged.contains(b)) merged.add(b); // de-dupe
}
return merged;
}
}
Line by line: the constructor accepts any two BreakSource implementations (polymorphism β this is what makes the factory viable). fetchBreaks() delegates to primary, then appends de-duplicated secondary breaks. No instanceof, no enum, no subclass explosion.
Pull request
(Link to your PR here.)
How I Built It
I used open-source AI as an implementation accelerator, not as an architect:
-
Design first. I produced the system diagram above and explicitly mapped each package to a GoF pattern before writing code. I referenced the Design Patterns textbook for the Adapter, Bridge, Command, Memento, Observer, State, Strategy, and Visitor mappings already present in the codebase (
LockoutAbstraction= Bridge,AddBreakCommand= Command,SaveWorkMemento= Memento,SessionObserver= Observer,SessionState= State,BreakStrategy= Strategy,EventVisitor= Visitor). - AI as implementer. I fed the architecture diagram and pattern definitions to an AI assistant, asking for implementations that respected the existing interfaces. The pre-supplied structure prevented the model from inventing new abstractions or confusing the Bridge with the Adapter.
-
Open-weight models at runtime. SlothMode's own
SessionSummaryAgentruns against Ollama or llama.cpp viaOllamaModelFactory/LlamaCppModelFactory, withMockModelfor tests. Session summaries never leave the machine.
Why Does Open Innovation Matter?
SlothMode's core value proposition β rest without surveillance β is incompatible with a closed API. If the session summarizer phoned home to a hosted LLM, the app would be logging exactly when you're not working. Local inference via open-weight models is a product requirement, not a nice-to-have. The SlothModel interface lets users swap Ollama, llama.cpp, or a mock without touching the session logic β the same open-interface principle as BreakSource. Open source made it possible to build a rest tool that doesn't itself need to watch you.
My Agent Session
(Embed your DevRelay agent_session here, or link it.)
The Lazy Payoff
The entire point of SlothMode is measured laziness: the CountdownRing enforces breaks you'd otherwise skip, StreakPointsStrategy rewards consistency, and the SlothHammock decorator makes rest tangible. In testing, the hybrid calendar source removed the "I forgot to log my break" failure mode entirely β breaks arrive from the calendar you already maintain. (Add a personal anecdote here if you used it this week.)
Prize Categories
(List partner categories you're entering, or remove this section.)
References
- Gamma, E., Helm, R., Johnson, R., & Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. β Source for the Adapter, Bridge, Command, Memento, Observer, State, Strategy, and Visitor patterns used throughout SlothMode's architecture.
- SlothMode repository: github.com/johnny603/SlothMode
- Hacktoberfest Open-Source AI Challenge Week 3
Top comments (0)