A minimalist, SMS-only habit-building agent designed to help users form lasting habits with one calm daily check-in and no notification overload.
This is not a motivation app.
It is a low-noise habit status and reflection system.
The Habit Builder SMS Platform operates entirely via text message.
Users:
- Sign up with a phone number
- Define multiple habits and their expected frequency
- Receive one daily SMS digest
- Reply once per day to log progress
- Request detailed stats only when they want them
The platform prioritizes long-term habit formation, autonomy, and attention respect.
- Single daily touchpoint
- User-controlled engagement
- No gamification or pressure
- Neutral, supportive tone
- Designed for months-long use
- Track multiple habits simultaneously
- Each habit has a frequency:
- Daily
- Multiple times per day
- X times per week
- No hard habit limit (UI naturally encourages 3–5)
Sent at a user-selected time (default 9:00 AM).
Includes:
- All active habits
- Current status (streaks, weekly progress)
- A single prompt to log updates
Example:
Daily Check-in:
Morning run (Daily): 4-day streak Read 10 pages (Daily): missed yesterday Gym (3x/week): 1 of 3 this week
Reply: Y N Y Text STATUS anytime for details.
No other reminders are sent that day.
- Users reply once with short answers (e.g.
Y N Y) - Parser accepts flexible responses (
yes/y/yep,no/n/nope) - Weekly habits aggregate daily replies into weekly totals
- Missed replies are logged silently (no nagging)
- Number-based logging still supported for backward compatibility
Users can text STATUS at any time.
Response includes:
- Completion rates
- Current and best streaks
- Weekly goal progress
- Simple text-based reports
Stats are never pushed automatically—only returned on request.
Supported commands:
ADD [name]– create a new habitREMOVE [name]– remove a habitTIME HH:MM– change digest timeLIST- see all habitsPAUSE/RESUME– pause/resume check-insSTOP– unsubscribe
- No mobile app
- No AI coaching or therapy language
- No social features
- No points, badges, or leaderboards
- No real-time or multiple daily notifications
- No qualitative scoring ("how well" you did)
-
Consistency beats intensity
One reliable daily cue is more effective than many interruptions. -
Autonomy drives habit formation
Users pull insight when they want it; the system never demands attention. -
Low stimulation supports long-term success
Avoids dopamine fatigue, shame cycles, and notification burnout.
The system should feel like it's working for the user—not managing them.
- Node.js 20.x or higher
- A Firebase account (free tier available)
- A Twilio account with SMS capabilities
- A phone number from Twilio
- Firebase CLI:
npm install -g firebase-tools
- Clone the repository:
git clone https://github.com/outrightmental/daily-grain.git
cd daily-grain- Install Firebase CLI (if not already installed):
npm install -g firebase-tools- Login to Firebase:
firebase login- Create a new Firebase project:
firebase projects:create daily-grain-your-name- Select your project:
firebase use daily-grain-your-name- Install dependencies:
cd functions
npm install
cd ..- Configure Twilio credentials:
firebase functions:config:set \
twilio.account_sid="your_account_sid" \
twilio.auth_token="your_auth_token" \
twilio.phone_number="+1234567890"Or set them as Firebase secrets (recommended):
firebase functions:secrets:set TWILIO_ACCOUNT_SID
firebase functions:secrets:set TWILIO_AUTH_TOKEN
firebase functions:secrets:set TWILIO_PHONE_NUMBER- Deploy to Firebase:
firebase deployAfter deploying to Firebase, configure your Twilio webhook:
- Log in to your Twilio Console
- Go to Phone Numbers → Active Numbers → Select your number
- Under "Messaging", set the webhook URL to:
https://YOUR_REGION-YOUR_PROJECT.cloudfunctions.net/webhook/sms - Method:
POST - Save your changes
For local development with Firebase emulators:
# Start the Firebase emulators
cd functions
npm run serveThis will start the Functions and Firestore emulators. The webhook will be available at:
http://localhost:5001/YOUR_PROJECT/us-central1/webhook/sms
The application is deployed as Firebase Cloud Functions with Firestore as the database. All infrastructure is managed by Firebase.
The project includes automated deployment workflows using GitHub Actions:
Production Deployment (main branch):
- Automatically deploys to Firebase on every push to
main - Workflow:
.github/workflows/firebase-deploy.yml - Deploys all Firebase services (Functions, Hosting, Firestore rules)
Preview Deployments (Pull Requests):
- Automatically creates a preview environment for each PR
- Preview URLs are posted as PR comments
- Previews expire after 7 days
- Workflow:
.github/workflows/firebase-preview.yml - Preview channels are automatically cleaned up when PRs are closed
Required Setup:
- Generate a Firebase CI token:
firebase login:ci
- Add the token as a GitHub repository secret named
FIREBASE_TOKEN:- Go to your repository Settings → Secrets and variables → Actions
- Click "New repository secret"
- Name:
FIREBASE_TOKEN - Value: Paste the token from step 1
Manual Deployment:
# Deploy everything
firebase deploy
# Deploy specific components
firebase deploy --only functions
firebase deploy --only hosting
firebase deploy --only firestoreSee DEPLOYMENT.md for detailed Firebase deployment instructions and CI-CD-SETUP.md for complete CI/CD setup guide.
| Command | Description | Example |
|---|---|---|
ADD [name] |
Create a new habit | ADD Morning run |
REMOVE [name] |
Remove a habit | REMOVE Morning run |
LIST |
See all your habits | LIST |
STATUS |
View detailed stats | STATUS |
TIME HH:MM |
Set check-in time | TIME 08:30 |
PAUSE |
Pause daily check-ins | PAUSE |
RESUME |
Resume daily check-ins | RESUME |
STOP |
Unsubscribe | STOP |
Y N Y |
Log habits (Yes/No) | Y N Y |
Firebase Cloud Architecture:
daily-grain/
├── functions/ # Firebase Cloud Functions
│ ├── src/
│ │ ├── models/ # Firestore data models
│ │ │ ├── firestore.js # Firebase Admin initialization
│ │ │ ├── User.js # User model (Firestore)
│ │ │ ├── Habit.js # Habit model (Firestore)
│ │ │ ├── HabitLog.js # Habit logging and stats
│ │ │ └── UserState.js # Conversation state management
│ │ └── services/ # Business logic
│ │ ├── HabitService.js # Habit management
│ │ ├── DigestService.js # Daily digest generation
│ │ ├── MessageService.js # SMS message handling
│ │ └── TwilioService.js # Twilio API wrapper
│ ├── index.js # Cloud Functions entry point
│ └── package.json # Functions dependencies
├── public/ # Firebase Hosting files
│ └── index.html # Landing page
├── src/ # Legacy code (kept for reference)
├── firebase.json # Firebase project configuration
├── firestore.rules # Firestore security rules
├── firestore.indexes.json # Firestore indexes
└── .firebaserc # Firebase project aliases
Cloud Functions:
webhook- HTTP function for Twilio SMS webhooksendDailyDigests- Scheduled function (runs daily at 9 AM)
Firestore Collections:
users- User profiles and preferenceshabits- User habits with frequency settingshabitLogs- Daily habit completion logsuserStates- Conversation state for multi-step flows
phoneNumber(string): Unique phone numbertimezone(string): User timezone (default: "America/New_York")digestTime(string): Daily check-in time (default: "09:00")isPaused(boolean): Pause statuscreatedAt(timestamp): Registration timestamp
userId(string): Reference to user document IDname(string): Habit namefrequencyType(string): "daily" | "multiple_per_day" | "x_per_week"targetCount(number): Number of times (for multiple_per_day and x_per_week)createdAt(timestamp): Creation timestamp
habitId(string): Reference to habit document IDlogDate(string): Date of log (YYYY-MM-DD format)completedCount(number): Number of completionsloggedAt(timestamp): Timestamp of logging
state(string): Current conversation statestateData(object): JSON data for multi-step flowsupdatedAt(timestamp): Last update timestamp
Firebase configuration is managed through:
- Functions Config: Use
firebase functions:config:setfor configuration - Environment Secrets: Use
firebase functions:secrets:setfor sensitive data (recommended) - firebase.json: Project-level Firebase settings
Required Secrets:
TWILIO_ACCOUNT_SID: Twilio account SIDTWILIO_AUTH_TOKEN: Twilio auth tokenTWILIO_PHONE_NUMBER: Your Twilio phone number
Set secrets:
firebase functions:secrets:set TWILIO_ACCOUNT_SID
firebase functions:secrets:set TWILIO_AUTH_TOKEN
firebase functions:secrets:set TWILIO_PHONE_NUMBERDaily digests are sent using Firebase Cloud Scheduler. The scheduled function sendDailyDigests runs every day at 9 AM Eastern Time by default.
To customize the schedule, edit functions/index.js:
exports.sendDailyDigests = onSchedule({
schedule: 'every day 08:00', // Change time here
timeZone: 'America/New_York',
memory: '256MiB',
}, async (event) => {
// ...
});Outright Mental Inc
This campaign sends one-time authentication codes and daily habit tracking check-ins to end users who sign up for Daily Grain, an SMS-based habit building platform. Users receive one daily digest message at their preferred time (default 9 AM) listing their habits and progress, and can reply to log their habit completions. Users can also text commands at any time to manage habits, view statistics, or adjust settings.
Daily Check-in:
Morning run (Daily): 4-day streak Read 10 pages (Daily): missed yesterday Gym (3x/week): 1 of 3 this week
Reply: Y N Y Text STATUS anytime for details.
Your one-time passcode is 782456.
Added daily habit: "Morning run" Reply LIST to see all habits.
STATUS Report:
Morning run (Daily)
- Current streak: 4 days
- Best streak: 12 days
- 7-day rate: 85%
- 30-day rate: 78%
Read 10 pages (Daily)
- Current streak: 0 days
- Best streak: 6 days
- 7-day rate: 71%
- 30-day rate: 65%
Text HELP for commands.
Logged: Morning run, Gym Text STATUS anytime for details.
End users opt-in by visiting dailygrain.example.com and entering their phone number to create an account, or by texting any command to our service number. Upon first message, users receive an automatic welcome confirming opt-in. Users can text STOP at any time to unsubscribe. Additionally, end users create an account after texting their first message, which constitutes explicit opt-in to receive daily habit check-ins and respond to their commands. Each daily digest includes instructions on how to text STOP to opt-out.
START, HELP, ADD, LIST, STATUS
Opt-in Message (20-320 characters)
Welcome to Daily Grain! You're now opted-in. You'll receive one daily check-in at 9:00 AM. Reply with your habit progress anytime. For help, reply HELP. To opt-out, reply STOP.
Daily Grain follows these principles:
- Minimalist: No apps, no complex interfaces, just SMS
- User-Controlled: Users decide when to check in (except one daily digest)
- No Gamification: No badges, points, or artificial rewards
- Privacy-First: Minimal data collection, stored locally
- Long-Term Focus: Designed for sustainable habit formation
- Quiet: One message per day unless user initiates
- Neutral Tone: Supportive without being pushy or exuberant
- Daily reply rate to digests
- Multi-month retention (2–3+ months)
- Improvement in habit adherence over time
- Low opt-out rate
- User-reported habit internalization
- Quick Start Guide - Get up and running in 5 minutes
- Usage Examples - See example conversations and commands
- Deployment Guide - Deploy to production platforms
- CI/CD Setup Guide - Configure automated deployments
- Infrastructure: Firebase Cloud Functions (serverless, auto-scaling)
- Database: Cloud Firestore (NoSQL, real-time, fully managed)
- SMS Gateway: Twilio API
- Hosting: Firebase Hosting (global CDN)
- Scheduling: Cloud Scheduler (managed cron jobs)
- Authentication: Phone number-based (no passwords)
- Security: Firestore security rules for data protection
- Monitoring: Firebase Console and Cloud Logging
- SMS Compliance: STOP/START opt-out messaging support
- Development: Firebase Local Emulator Suite for testing
- Deployment: Single command deployment (
firebase deploy) - Scalability: Automatic scaling with Firebase infrastructure
- Cost: Free tier available, pay-as-you-grow pricing
This project has been migrated from a Node.js/Express app with SQLite to Firebase. The legacy code is preserved in the /src directory for reference. Key changes:
- Database: SQLite → Cloud Firestore
- Server: Express on VM/container → Cloud Functions (serverless)
- Scheduler: node-cron → Cloud Scheduler
- Hosting: Self-hosted → Firebase Hosting
- Deployment: Manual server setup →
firebase deploy
All API functionality remains the same. Twilio webhook configuration is the only external change needed.
ISC
Contributions welcome! Please feel free to submit a Pull Request.
Built to be simple, boring, and effective.