Show up daily. Log in a click. Leave sharper.
Job hunting is a hundred small efforts a day: a LeetCode problem at breakfast, ML review at night, a batch of applications in between. Each one is forgettable β together, they're your entire preparation. PrepDojo makes sure none of it disappears, and everything happens on one dashboard page. Log anything with a single click (or just tell an AI "did two sum today"), and the same page shows the full picture the moment you need it: your streak, which topics are solid and which are shaky, how many applications went out this week, and which resume actually gets you interviews.
Everything stays in plain files on your own computer. No account, no subscription, nothing to lose access to. Built on Obsidian, free and local-first.
β³ Import your LeetCode solves with one click. Just crushed a few problems on LeetCode? Click β³ Import on the dashboard and your recent accepted submissions land in your daily notes.
οΌ Log any prep work with one click. An application fired off, an ML concept reviewed at lunch, a mock interview survived: every kind of prep has its own button. Click, answer a prompt or two, logged.
β Track every application to the end. Heard back? Hit β Update and log the new status in seconds. Interviews and offers rise to the top.
β A/B test your resume. Stop guessing which resume works. Every application you send is quietly running an experiment. See the results.
β¦ One page shows it all. Everything above lives on a single dashboard: your streak burning, topics ranked from solid to shaky, interviews and offers up top, resume rates below. Open it and today's story is already written. No assembly required.
β¦ Or let AI do the logging. Too tired to click? Toss Claude a LeetCode link or mumble "did two sum today" and the entry writes itself. Applications too: "Stripe moved me to phone screen" updates your tracker.
- Obsidian
- Python 3.9+ for the one-command setup. No Python at all? See manual setup.
Optional: the Claude desktop app (Cowork) or Claude Code, if you want AI logging.
Step 1 β Get the repo
git clone https://github.com/aaaxy/PrepDojo.git
cd PrepDojoStep 2 β Prepare your vault
- Pick the folder that is (or will be) your Obsidian vault. It should live outside this repo.
- Open that vault in Obsidian at least once.
- On Obsidian 1.12+: open Settings β General β enable Command line interface.
- Quit Obsidian (setup reopens it when installing the plugins).
Step 3 β Run setup with your vault's path, back in the terminal:
python3 setup.py /path/to/YourVaultSetup asks two optional questions along the way β your LeetCode username (powers the import button) and your daily-notes folder. Everything else has sensible defaults you can change later; see docs/configuration.md.
(Step 3b, only on Obsidian older than 1.12 β setup can't install the plugins without the CLI:)
- Open Settings β Community plugins and turn off Restricted mode.
- Click Browse, then install and enable Dataview, QuickAdd, and Calendar.
Step 4 β Finish in Obsidian, whichever version you're on:
- Open Settings β Community plugins, click the βοΈ next to Dataview, and turn on Enable JavaScript queries.
- Open the dashboard note in Reading view and click a button. Done.
The tables start empty. Your first log fills them, and your streak starts counting.
Step 5 (optional) β Add AI logging. Install once, in Claude Code or the Claude app:
/plugin marketplace add aaaxy/PrepDojo
/plugin install prepdojo@prepdojo
Your settings travel with your vault (setup writes a small prepdojo.json there), so the plugin needs no configuration and keeps working when you change settings.
That's it β you're all set. From here on, PrepDojo is just the dashboard and your daily grind.
Everything below is for later: changing settings, regenerating after a change, and updating PrepDojo itself.
The dashboard, templates, and logging flows are all generated from config.toml. The same three steps apply whether you changed a setting or are updating PrepDojo itself:
- Quit Obsidian.
- In the repo (after
git pull, if updating PrepDojo itself), run:
python3 generate.py /path/to/YourVaultThe path is remembered in config.toml, so a plain python3 generate.py works from then on.
- Restart Obsidian and reopen the dashboard note.
Reading the output: installed and up to date mean done. PRESERVED ... new version written to *.new means you've hand-edited that file since it was installed β compare it with the .new copy and merge at your own pace, or rerun with --force to take the new version wholesale.
What it can and cannot touch: generated files you haven't edited update in place; anything you have edited is preserved with a .new beside it; your data β daily notes and application CSVs β is never written, under any flag. One consequence: if an update adds a column to the applications CSV schema, append the new column name to your applications.csv header row yourself (release notes will say so; rows without a value are fine).
Two things never update automatically:
- Hotkeys β Obsidian's
hotkeys.jsonis shared with everything else, so PrepDojo never writes it. If an update added new flows, bind them in Settings β Hotkeys (or mergedist/obsidian/hotkeys-snippet.json). - The AI plugin β it updates through Claude's plugin manager, not
generate.py. After a PrepDojo release, refresh it from the/pluginmenu in Claude.
(Upgrading from the old .skill file? The plugin replaces it β remove the lc-logger skill from your Claude profile after installing the plugin. dist/claude-skill/ still builds for now, but it is deprecated and will be removed in a future release.)
Habits that keep this smooth: customize in the repo's templates/, not the installed vault copies β except PrepDojo's QuickAdd choices, which are managed from config.toml. And remember config changes affect future entries only: rename a tag and old entries keep the old one until you find-and-replace them.
To you, PrepDojo is one dashboard page. Under the hood, that page is the visible tip of three coordinated layers, all generated from one config file:
- Capture β log what you did in seconds, from wherever you are. Four doors into the same log: one-click dashboard buttons with guided prompts, QuickAdd hotkeys running the same flows from anywhere in Obsidian, an AI logging plugin for Claude (its skills read plain
prepdojo.json, so any LLM agent can follow the same contract) that turns "just did two sum" or a pasted LeetCode URL into a correctly formatted entry, and a CLI (prepdojo.py) for terminals and automation. A fifth door is automatic: the β³ LeetCode import fetches your recent accepted submissions. Every door validates entries, so the log can't drift into inconsistency - Storage β where your record lives. Plain text files on your own machine: markdown bullets in your daily notes for practice, CSV rows for job applications. Human-readable, grep-able, no database, no lock-in β every tool in this repo is replaceable, and your record outlives all of them
- Insight β how you see your progress. One dashboard note computes it all from your record: streaks, per-topic and per-difficulty breakdowns with date-range filters, a "needs re-review" list, and application stats (active interviews, offers, milestone summary, interview rate per resume version), updating live while the note is open. It stores nothing itself, so regenerating, moving, or customizing it is always safe
Daily workflow, from a solved problem to insight:
flowchart LR
subgraph capture ["β‘ Capture (seconds)"]
subgraph obs ["on the dashboard"]
BT["οΌ / β buttons<br/>guided prompts + dropdowns"]
IMP["β³ LeetCode import<br/>recent solves, one click"]
end
subgraph obs2 ["anywhere in Obsidian"]
QA["QuickAdd hotkeys<br/>same flows as the buttons"]
MB["Manual bullet<br/>type it yourself"]
end
subgraph cl ["chat with Claude"]
CS["AI plugin<br/>paste a link or say 'log it'"]
end
subgraph term ["terminal / scripts"]
CLI["prepdojo CLI<br/>hooks, automation, sync-lc"]
end
end
subgraph storage ["π Storage (plain files)"]
DN["Daily notes<br/><code>- LC #200 Number of Islands Β· Medium Β· bfs/dfs #lc</code>"]
CSV["applications.csv<br/>resume-versions.csv"]
end
subgraph insight ["π Insight (always current)"]
DB["Dataview dashboard<br/>streaks Β· topics Β· interviews & offers Β· resume rates"]
end
BT --> DN
IMP --> DN
QA --> DN
MB --> DN
CS --> DN
CLI --> DN
BT --> CSV
CS --> CSV
CLI --> CSV
DN --> DB
CSV --> DB
One-time setup, everything personalized from a single file:
flowchart LR
CFG["config.toml<br/>your few answers<br/>+ built-in defaults"] --> GEN["generate.py"]
GEN --> T["Daily note template"]
GEN --> D["Dashboard note"]
GEN --> Q["QuickAdd actions<br/>+ logging scripts"]
GEN --> CSVS["Starter CSVs<br/>(created once, never overwritten)"]
GEN --> PJ["prepdojo.json<br/>(read by the AI plugin)"]
T & D & Q & CSVS & PJ --> V["Your Obsidian vault"]
PolyForm Noncommercial 1.0.0: free to use, modify, and share for any noncommercial purpose (personal use, education, research, nonprofits). Commercial use requires a separate license from the author.
Copyright (c) 2026 aaaxy