RepoPilotOpen in app →

oppiliappan/dijo

scriptable, curses-based, digital habit tracker

Mixed

Stale — last commit 2y ago

weakest axis
Use as dependencyMixed

last commit was 2y ago; no tests detected

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 14 active contributors
  • MIT licensed
  • CI configured
Show all 6 evidence items →
  • Stale — last commit 2y ago
  • Concentrated ownership — top contributor handles 70% of recent commits
  • No test directory detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/oppiliappan/dijo?axis=fork)](https://repopilot.app/r/oppiliappan/dijo)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/oppiliappan/dijo on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: oppiliappan/dijo

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/oppiliappan/dijo shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 2y ago

  • 14 active contributors
  • MIT licensed
  • CI configured
  • ⚠ Stale — last commit 2y ago
  • ⚠ Concentrated ownership — top contributor handles 70% of recent commits
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live oppiliappan/dijo repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/oppiliappan/dijo.

What it runs against: a local clone of oppiliappan/dijo — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in oppiliappan/dijo | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 662 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>oppiliappan/dijo</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of oppiliappan/dijo. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/oppiliappan/dijo.git
#   cd dijo
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of oppiliappan/dijo and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "oppiliappan/dijo(\\.git)?\\b" \\
  && ok "origin remote is oppiliappan/dijo" \\
  || miss "origin remote is not oppiliappan/dijo (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/main.rs" \\
  && ok "src/main.rs" \\
  || miss "missing critical file: src/main.rs"
test -f "src/app/mod.rs" \\
  && ok "src/app/mod.rs" \\
  || miss "missing critical file: src/app/mod.rs"
test -f "src/habit/mod.rs" \\
  && ok "src/habit/mod.rs" \\
  || miss "missing critical file: src/habit/mod.rs"
test -f "src/habit/traits.rs" \\
  && ok "src/habit/traits.rs" \\
  || miss "missing critical file: src/habit/traits.rs"
test -f "src/command.rs" \\
  && ok "src/command.rs" \\
  || miss "missing critical file: src/command.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 662 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~632d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/oppiliappan/dijo"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

dijo is a terminal-based habit tracker written in Rust using the Cursive TUI framework, with vim-like keybindings and a modal interface. It lets users track habits across different time granularities (daily, weekly, monthly views) and is fully scriptable via shell hooks, enabling automated habit tracking integrated with external programs like git commits. Monolithic binary structure: src/app/ handles UI state and views (cursor.rs, impl_view.rs, message.rs), src/habit/ contains three concrete habit types (bit.rs for boolean, count.rs for counters, float.rs for decimal tracking) with shared traits in traits.rs. Command parsing in src/command.rs, theme/styling in src/theme.rs, with main.rs orchestrating the cursive-based event loop.

👥Who it's for

Command-line power users and developers who want to track personal habits without leaving their terminal, particularly those familiar with vim's modal editing who want to script their tracking workflows (e.g., auto-logging git commits as coding habit streaks).

🌱Maturity & risk

Actively maintained but modest-scale project: v0.2.7 with CI/CD via GitHub Actions (main.yml) and published to crates.io. The codebase is well-organized with proper module structure but dependency list is minimal (serde, chrono, cursive 0.17, clap 2.33), suggesting a focused scope. Production-ready for personal use but smaller community than mainstream trackers.

Single-maintainer risk (oppiliappan/NerdyPepper) is the primary concern. Dependency on cursive 0.17 (2020-era) with outdated transitive deps (syn pinned to 1.0.57, clap 2.33 is ancient). No visible test suite in the file structure suggests low test coverage. Windows support requires explicit feature flag (crossterm-backend) indicating platform-specific fragility.

Active areas of work

No specific PR or milestone data visible in provided files. Last activity appears routine maintenance (Cargo.lock management, dependabot.yml exists for security updates). The notes.txt file may contain development direction but content not shown. Project appears in steady-state with focus on stability rather than major features.

🚀Get running

Clone and build with: git clone https://github.com/oppiliappan/dijo.git && cd dijo && cargo build --release. Then run with ./target/release/dijo. For development: cargo run launches the TUI directly. Windows users must use cargo run --no-default-features --features "crossterm-backend".

Daily commands: Standard Rust workflow: cargo run starts the interactive TUI. cargo test for tests (if any exist). cargo build --release for optimized binary. Windows: cargo run --no-default-features --features "crossterm-backend". The app is self-contained—no external services required, but reads/writes to ~/.local/share/dijo/ (per directories crate).

🗺️Map of the codebase

  • src/main.rs — Application entry point; initializes the curses UI, loads configuration, and starts the event loop that drives all habit tracking interactions.
  • src/app/mod.rs — Core application state and view management; orchestrates mode transitions, cursor tracking, and rendering logic for the entire TUI.
  • src/habit/mod.rs — Trait definitions and serialization logic for all habit types; any new habit variant must implement the traits defined here.
  • src/habit/traits.rs — Abstract behavior contract for habits (check, record, display); foundational for polymorphic habit handling across the codebase.
  • src/command.rs — Command parser and executor for vim-like syntax (:add, :delete, :q); bridges user input to application state mutations.
  • Cargo.toml — Dependency manifest including cursive TUI framework, serde for persistence, and chrono for date handling; essential for reproducible builds.
  • src/views.rs — View rendering logic that converts habit state into curses-compatible output; critical for all UI display logic.

🧩Components & responsibilities

  • app/mod.rs (Application State) (Cursive, typetag polymorphism) — Owns all habits, cursor position, view mode; routes input to mutations and rendering
    • Failure mode: State corruption if concurrent writes occur; in-memory loss on crash
  • habit/traits.rs (Habit Abst — undefined

🛠️How to make changes

Add a New Habit Type

  1. Create a new file src/habit/your_type.rs implementing a struct with fields for tracking (src/habit/your_type.rs)
  2. Implement the Habit trait from src/habit/traits.rs with methods for check, record, display, and serialization (src/habit/traits.rs)
  3. Register the new type in src/habit/mod.rs using the typetag crate for polymorphic serde serialization (src/habit/mod.rs)
  4. Add a case in src/command.rs to parse and instantiate the new habit type from :add commands (src/command.rs)
  5. Update src/views.rs to render the new habit type appropriately in the grid display (src/views.rs)

Add a New Command

  1. Define the command syntax and logic in src/command.rs within the command parser (src/command.rs)
  2. Implement the corresponding action in src/app/impl_self.rs to mutate app state (src/app/impl_self.rs)
  3. If the command changes visual state, update rendering logic in src/app/impl_view.rs or src/views.rs (src/app/impl_view.rs)

Add a New Keybinding

  1. Map the key code to an action in src/keybinds.rs or within the main event handler in src/app/impl_self.rs (src/keybinds.rs)
  2. Implement the corresponding state mutation in src/app/impl_self.rs (src/app/impl_self.rs)
  3. Test the keybinding by running the application and confirming the action is triggered (src/main.rs)

Change the Theme or Color Scheme

  1. Edit color definitions and style rules in src/theme.rs (src/theme.rs)
  2. Reference the theme colors in rendering calls throughout src/views.rs and src/app/impl_view.rs (src/views.rs)

🔧Why these technologies

  • Cursive (TUI framework) — Provides cross-platform terminal UI rendering; enables vim-like modal interface with minimal dependencies.
  • Serde + typetag — Enables polymorphic serialization of different habit types into a single JSON/TOML file; critical for persistence without boilerplate.
  • Chrono — Handles date arithmetic and formatting for daily habit tracking and timeline views.
  • Clap — Parses CLI flags; decouples command-line interface from application logic.
  • Notify — Watches habit configuration files for changes; enables auto-reload without restarting the app.

⚖️Trade-offs already made

  • Modal interface (vim-like) instead of mouse-based GUI

    • Why: Reduces cognitive load for power users and makes the tool scriptable and keyboard-efficient; aligns with author's design philosophy.
    • Consequence: Steeper learning curve for non-vim users; not suitable for mobile or heavy mouse workflows.
  • In-memory habit storage with periodic disk serialization

    • Why: Simplicity and fast UI response times; avoids complex database setup.
    • Consequence: No ACID guarantees; potential data loss if app crashes mid-write; not suitable for concurrent multi-client access.
  • Trait-based polymorphism for habit types instead of enums

    • Why: Extensible design; new habit types can be added without touching core rendering logic.
    • Consequence: Slightly higher runtime overhead from dynamic dispatch; requires typetag boilerplate for serialization.
  • Vim-like command syntax (:add, :delete) instead of interactive menus

    • Why: Scriptable and composable; integrates with shell pipelines and external automation.
    • Consequence: Users must memorize command syntax; no visual feedback during command composition.

🚫Non-goals (don't propose these)

  • Real-time synchronization across devices or users
  • Graphical user interface (desktop/web); terminal-only
  • Cloud storage or backup services; local-file-only persistence
  • Multi-user or role-based access control
  • Mobile app (implicitly terminal-focused)

🪤Traps & gotchas

Config is loaded from ~/.local/share/dijo/ (directories crate handles platform differences); no explicit error message if directory doesn't exist. Termion backend (default) does not work on Windows—must use --no-default-features --features "crossterm-backend" or builds will fail silently. Habit data is serialized with serde+typetag; custom habit types require explicit registration or they won't deserialize. The app uses blocking I/O with notify file watcher; high-frequency file changes can cause jank. Vim keybinds are hardcoded (no rebinding at runtime despite command-mode philosophy).

🏗️Architecture

💡Concepts to learn

  • Trait Objects + typetag Serialization — dijo uses erased-serde and typetag (src/habit/traits.rs) to serialize different habit types (Bit, Count, Float) polymorphically; critical for saving/loading habits to disk without type information at runtime
  • Modal Interface / State Machine — dijo mimics vim's modal editing (normal mode, command mode, insert mode); src/app/mod.rs tracks current mode and routes keybinds differently per mode
  • Curses / Terminal Control (TUI Framework) — Cursive (src/app/impl_view.rs) abstracts low-level terminal I/O; understanding how TUIs render to raw terminal cells is needed to modify layouts or add new views
  • File Watcher Pattern (notify crate) — dijo watches config file changes via notify crate to reload habits without restarting; enables scriptable external habit updates via file writes
  • Lazy Static Initialization — Global state (themes, keybinds) initialized once via lazy_static!; Rust pattern for avoiding runtime initialization overhead in a single-threaded TUI app
  • Serde Polymorphism — Different habit types serialize to the same JSON/TOML format (via serde + typetag) so config files are human-readable yet support diverse data structures
  • Time Windowing (Chrono Intervals) — Habits track over day/week/month windows; src/habit/traits.rs defines month/week/day views requiring date arithmetic via Chrono to compute ranges and aggregate stats
  • BurntSushi/xsv — CSV processing toolkit for terminal; shares minimalist CLI philosophy and used for automating data workflows like dijo's scriptability
  • gchp/iodide — Another Rust TUI app with modal keybinds and file-based persistence; similar architecture for exploring alternatives
  • extrawurst/gitui — Rust + Cursive TUI project with event handling patterns and backend abstractions applicable to dijo's terminal layer
  • jesseduffield/lazygit — Habit tracker use-case: dijo integrates with git via shell scripts; lazygit is the canonical git TUI that users of dijo often automate against
  • gremlin/triangle — Predecessor/inspiration: older Rust habit tracker with similar design goals; useful for understanding design evolution

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for habit trait implementations

The repo has multiple habit types (bit, count, float) in src/habit/ that implement a common trait interface, but there's no visible test module. Testing these implementations would catch regressions in serialization, state tracking, and habit-specific behavior. This is high-value because habits are the core data model.

  • [ ] Create src/habit/tests.rs with test modules for bit.rs, count.rs, and float.rs
  • [ ] Add tests for serialization/deserialization via serde_json (already a dependency)
  • [ ] Add tests for habit state transitions and reset logic
  • [ ] Add test fixtures using the toml config format referenced in Cargo.toml

Add GitHub Actions workflow for testing on multiple Rust versions and backends

The repo supports two backend features (termion-backend and crossterm-backend) as mutually exclusive options, but .github/workflows/main.yml likely doesn't test both. Adding matrix builds ensures both backends compile and pass tests. This catches breakage early since cursive backend APIs differ.

  • [ ] Extend .github/workflows/main.yml to test with --features termion-backend and --features crossterm-backend separately
  • [ ] Add Rust versions 1.56+ (MSRV) and stable to the test matrix given edition = 2018
  • [ ] Add cargo clippy and rustfmt checks (rustfmt.toml already exists)
  • [ ] Add test coverage reporting step using tarpaulin or llvm-cov

Add integration tests for command parsing and keybind execution

src/command.rs and src/keybinds.rs handle user input and mode switching (vim-like modal interface is a key feature), but no visible integration tests exist. Testing the command mode (:add, :delete, :q) and navigation keybinds (hjkl) prevents regressions in the core UX layer and is feasible without full terminal rendering.

  • [ ] Create tests/command_integration_test.rs to test src/command.rs parsing logic
  • [ ] Add test cases for valid commands (:add, :delete, :q) and error handling for invalid syntax
  • [ ] Create tests/keybinds_integration_test.rs for src/keybinds.rs mode transitions
  • [ ] Mock or stub the cursive View layer to test keybind routing without rendering

🌿Good first issues

  • Add unit tests for src/habit/count.rs and src/habit/float.rs; currently no test files visible in tree and habit logic (incrementing, boundary checks) is untested.
  • Extend README with concrete TOML config examples showing how to auto-track git commits (wiki mentions this but no examples in main repo docs).
  • Add configurable keybinds in src/keybinds.rs instead of hardcoded vim defaults; would require refactoring src/app/impl_self.rs to look up actions dynamically.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 43c995e — Merge pull request #141 from gyscos/master (oppiliappan)
  • 00e8147 — Update to cursive 0.17 (gyscos)
  • 27092d0 — Merge pull request #129 from purveshpatel511/master (oppiliappan)
  • d30bfc8 — added snap installtion instruction (purveshpatel511)
  • be6e0e3 — add install instructions for windows (oppiliappan)
  • 44c6faa — bump to v0.2.7 (oppiliappan)
  • 0fd22fb — reduce display width of FloatData (oppiliappan)
  • 22a3f02 — add initial float habit structure (oppiliappan)
  • fbcc966 — add GoalKinds (oppiliappan)
  • 3169cb6 — bump to v0.2.6 (oppiliappan)

🔒Security observations

The dijo habit tracker codebase demonstrates generally good security practices for a TUI application. No critical vulnerabilities were identified. The main concerns are: (1) a pinned, older version of the syn crate that may not receive updates; (2) use of deprecated lazy_static dependency; (3) potential path traversal risks in file operations; and (4) command execution via scripting features which could be vulnerable to injection if not properly implemented. The codebase lacks visible hardcoded secrets or obvious injection vulnerabilities. Recommendations focus on dependency updates and ensuring proper input validation for file and command operations.

  • Medium · Outdated syn Dependency with Pinned Version — Cargo.toml - syn dependency. The syn crate is pinned to version 1.0.57 using '=' constraint. This prevents automatic security updates and patches. The syn crate is a widely-used proc macro parser and any vulnerabilities in it could affect the entire build system. Fix: Update to the latest stable version of syn (currently 2.x) and use flexible versioning (e.g., 'syn = "2.0"') to receive security patches automatically.
  • Medium · Deprecated lazy_static Dependency — Cargo.toml - lazy_static dependency. The project uses lazy_static 1.4.0, which is considered deprecated. The Rust ecosystem has moved to once_cell (now std::sync::OnceLock in newer Rust versions). While not a direct security vulnerability, deprecated dependencies may not receive security updates. Fix: Migrate to once_cell crate or use std::sync::OnceLock if targeting Rust 1.70+. Ensure all dependencies receive timely security updates.
  • Low · Potential Path Traversal in File Operations — src/app, src/habit modules (implementation details not fully visible). The project uses the 'directories' crate for configuration paths and appears to handle file-based habit tracking. Without reviewing the implementation details, there's a potential risk of path traversal vulnerabilities if user-controlled input is used to construct file paths without proper validation. Fix: Ensure all file operations validate and sanitize path components. Use path canonicalization and verify paths remain within expected directories. Never concatenate user input directly into file paths.
  • Low · External Command Execution via Scripting — src/command.rs, src/main.rs (scripting functionality). The README mentions the project is 'fully scriptable' and can be configured to 'track external programs' and 'git commits'. This suggests potential use of external command execution. If user-controlled input reaches command execution functions, there could be command injection risks. Fix: If executing external commands, use parameterized execution (e.g., std::process::Command) instead of shell string concatenation. Never pass unsanitized user input to shell interpreters.
  • Low · Configuration Deserialization from TOML Files — src/ modules (toml parsing logic). The project uses toml 0.5.6 for configuration parsing. While toml parsing itself is generally safe, if configuration files contain complex nested structures or are sourced from untrusted locations, deserialize-to-object operations could be exploited. Fix: Validate TOML configuration structure and types during deserialization. Use strict schema validation. Ensure configuration files are only read from trusted, protected locations (user home directory with proper permissions).

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · oppiliappan/dijo — RepoPilot