Build a Habit Tracker CLI That Teaches Files and Args

You want a streak count, and the tutorial still has you printing hello in a loop. This small project cuts straight to skills you’ll use every week as a developer: parsing command line arguments, reading/writing structured files, and handling date math that won’t break when you cross a time zone. You’ll ship a working tool in an afternoon, no fancy frameworks or external APIs required.

Commands a habit CLI must accept on day one

Your core functionality fits into three simple commands, no extra bloat for the initial release. The following command map defines every interaction you need to support for v0.1:

Build a Habit Tracker CLI That Teaches Files and Args desk detail
Desk detail for this page — not a measured lab photo.
Command Required Arguments Optional Arguments Expected Action
`init` None `–path` (custom file path for habit storage, defaults to `~/.habits.json`) Creates a blank, valid habit JSON file. Skips execution if a file already exists at the target path to avoid accidental data loss.
`log` `–habit` (name of the completed habit, e.g. “daily walk”) `–date` (YYYY-MM-DD formatted date, defaults to current UTC date), `–note` (free text context for the entry) Adds a new completion entry to the habit JSON, and appends the habit name to `habits_tracked` if it does not already exist.
`status` None `–habit` (filter results to a single habit name) Prints current streak count and total lifetime completions for all tracked habits, or the single specified habit.

You can build this argument parsing logic with standard libraries in almost every language: Python’s `argparse`, Node.js’s `process.argv`, Go’s `flag` package, all work without installing third-party dependencies. Test each command as you build it: run `init` first, confirm the file is created at the expected path, then run `log –habit “read 10 pages”` and check that the entry appears in the JSON as expected.

JSON file layout you can open in a text editor

You don’t need a dedicated database for a tool this small; plain JSON is portable, human-readable, and easy to debug if you make a typo or want to bulk edit entries. The below sample shape is designed to be flexible enough for future feature additions, while remaining simple enough to edit manually if needed:

“`json

Illustrative card for Build a Habit Tracker CLI That Teaches Files and A
Illustrative worksheet for this topic. Treat numbers as examples.

{

“created_at”: “2024-03-01”,

“habits_tracked”: [“read 10 pages”, “daily walk”, “meditate”],

“completion_log”: [

{“habit”: “read 10 pages”, “date”: “2024-05-10”, “note”: “chapter 3 of Atomic Habits”},

{“habit”: “daily walk”, “date”: “2024-05-10”, “note”: “20 minutes around the neighborhood”},

{“habit”: “read 10 pages”, “date”: “2024-05-11”, “note”: “finished section on streak framing”},

{“habit”: “meditate”, “date”: “2024-05-11”, “note”: “10 minute guided session”}

]

}

“`

Each field serves a clear purpose: `created_at` stores the date you first ran `init` for your own reference, `habits_tracked` keeps a canonical list of habit names so you can avoid duplicate entries from typos like “read 10 page” instead of “read 10 pages”, and `completion_log` is a flat list of every time you finished a habit. All dates are stored as YYYY-MM-DD UTC strings, no timezone-aware datetime objects or unix timestamps, so you can open the file on any device and read the dates clearly without conversion.

Streak math that does not depend on wall-clock luck

A lot of beginner habit tracker projects break because they rely on local system time or poorly written date math that fails across time zones or leap days. Start with two non-negotiable rules for streak calculation: first, every date is normalized to UTC YYYY-MM-DD before storage or comparison, so logging a habit at 11pm EST (which is 3am UTC the next day) will be assigned to the correct UTC date, no random broken streaks from travel. Second, never write your own date addition or subtraction logic; use your language’s standard date library to iterate backwards through days.

Illustrative example: If your most recent “read 10 pages” entry is dated 2024-05-12, check 2024-05-11 for an entry, then 2024-05-10, and so on until you hit a day with no matching entry. The number of consecutive days with entries is your streak. If you forgot to log a day last week, you can manually add it with the `log –date` flag at any time, and the streak calculation will update automatically. Avoid common pitfalls like counting multiple entries on the same day as extra streak days, or skipping days because the system clock was off when you logged the entry.

Help text you write before the third flag

Help text is not a post-launch afterthought; write it as you build each command, so you don’t have to dig through your code to remember how to use the tool a month from now. Most argument parsing libraries let you define help text inline when you add a new flag, so you can auto-generate the full help output without writing it manually. For example, running `habit-tracker –help` should print a list of all three commands, their core purpose, and their available flags. Running `habit-tracker log –help` should explicitly state that `–habit` is required, that `–date` defaults to the current UTC date, and include a sample command like `Example: habit-tracker log –habit “drink 8 cups water” –date 2024-05-10 –note “had last cup before bed”`. Add clear error messaging alongside help text: if a user runs `log` without the `–habit` flag, the error output should tell them exactly what they missed, not throw a generic runtime error.

Tag v0.1 after three real days of logging

You don’t have a working v0.1 release until you’ve used the tool to log your own habits for three consecutive days. This real-world use will catch bugs you’d never find in isolated testing: for example, if you misspell a habit name, does the tool throw a warning or silently add a new habit to `habits_tracked`? If you log the same habit twice in one day, does it count as one entry for streak purposes, or inflate your total completion count? Fix these small edge cases as you find them, no feature creep allowed for v0.1.

Example measurement: Your final v0.1 codebase should be under 200 lines of code if you use standard libraries, with no external dependencies, so you can run it on any device with your language of choice installed without extra setup. Once you’ve confirmed it works for three days of real use, tag the commit as v0.1 in Git, so you can always revert to this stable version if you add new features like habit reminders or CSV exports later that break core functionality.

Open your code editor right now, create a new file for your habit tracker, and write the first 20 lines that parse the init, log, and status commands before you add any file writing or streak calculation logic.