KestrelCP
A VS Code extension for competitive programming — scaffold problems from URLs, run tests against bundled cases, and commit with AI-generated messages, all without leaving the editor.
[!NOTE]
This extension is primarily built for my personal use — a local environment to debug and implement competitive programming solutions from Kattis, Codeforces, and LeetCode. Kattis and Codeforces solutions still need to be manually submitted on each platform's official site; LeetCode can be submitted directly from the editor. A nice side benefit: committing solutions to a Git repo helps keep your GitHub contribution graph active.
Currently only Java is supported as the solution language. Support for other languages may come in the future.
If you find it useful, feel free to use it! Suggestions and new features are welcome via pull requests.
Check out cp-solutions-vault to see the extension in action with a real workspace.
⚡ What it does
- Scaffold a problem folder from a Kattis / Codeforces / LeetCode URL. Sample test cases are auto-fetched.
- Search LeetCode by title or keyword and pick a problem to scaffold.
- Test your
Solution.java with one click on the editor toolbar (top-right of the editor). LeetCode problems are run on LeetCode's official judge.
- Submit to LeetCode with one click on the editor toolbar — counts as an official submission, shows runtime / memory percentile.
- Commit with a Conventional-Commits message generated by Claude from your staged diff.
- LeetCode Daily Challenge widget in the sidebar — today's problem is one click away. Click to scaffold (or open if already done).
- Playground — a dedicated
playground/Playground.java for ad-hoc Java experimentation. One click on the editor toolbar compiles and runs it.
🚀 Install
Search for KestrelCP in the VS Code Extensions panel and click Install.
Or from the command line:
code --install-extension khoa-doan.kestrelcp
Alternatively, .vsix builds are attached to GitHub Releases for manual installation.
Requirements
🎯 Daily workflow
Open VS Code on a folder — either an existing CP folder or a brand-new one.
First time only (required): run KestrelCP: Initialize Workspace from the command palette to create the kattis/, codeforces/, leetcode/, and playground/Playground.java scaffolding. All other commands require the workspace to be initialized first.
Scaffold a new problem — three entry points, all via the command palette (Cmd+Shift+P):
- KestrelCP: New Problem — pick platform, paste the problem URL
- KestrelCP: Search LeetCode — type a title or keyword, pick from the results
- Click the LeetCode Daily Challenge entry in the KestrelCP sidebar to scaffold today's problem in one click
Solution.java opens automatically once scaffolding finishes. For LeetCode, it's the exact starter code shown in LeetCode's web editor (correct method signature, helper class imports, etc.) — you fill in the method body.
Solve it.
Run tests — click the ▶ button in the editor toolbar (top-right of the editor, visible whenever you're on a Solution.java), or Cmd+Shift+P → KestrelCP: Run Tests for Current Problem.
For Kattis / Codeforces, this runs javac + java locally against your *.in / *.out files. For LeetCode, this batches all *.in files into one call to LeetCode's "Run Code" judge (the same one their web editor uses) and reports per-case PASS / FAIL.
Submit (LeetCode only) — click the ☁️ button in the editor toolbar (only shown on a LeetCode Solution.java), or Cmd+Shift+P → KestrelCP: Submit to LeetCode. Counts as an official submission and reports runtime / memory percentile.
Commit — stage your files in the Source Control panel, then Cmd+Shift+P → KestrelCP: AI Commit. Claude proposes a Conventional Commit message; type y / n / e to accept / abort / edit.
🧪 Playground
Need to try a snippet without scaffolding a whole problem? KestrelCP: Initialize Workspace also creates playground/Playground.java — a free-form Java scratchpad. Open it (e.g. Cmd+P → Playground.java) and hit the ▶ button in the editor toolbar to compile + run. Add helper classes alongside it (Helper.java, etc.) — javac *.java picks them up automatically; java Playground is the entry point.
🎯 LeetCode Daily Challenge
The KestrelCP sidebar (cube icon in the activity bar) shows today's LeetCode Daily Challenge with its difficulty and acceptance rate. Click the row to scaffold it in one step; if you've already started it today, the click opens your existing Solution.java. The 🔄 button on the view title forces a re-fetch. No auth required for this — the daily-challenge endpoint is public.
🔑 LeetCode setup
Scaffolding LeetCode problems and searching the catalog work anonymously, but running tests and submitting require LeetCode's own session cookies — there is no public LeetCode API, so KestrelCP authenticates the same way your browser does.
One-time setup:
- Log in to leetcode.com in your browser.
- DevTools → Application → Cookies →
https://leetcode.com (Chrome / Edge), or Storage → Cookies (Firefox).
- Copy the values of these two cookies:
LEETCODE_SESSION (long JWT, ~600 chars)
csrftoken (~32 chars)
- Command palette → KestrelCP: Set LeetCode Cookies. Paste each value when prompted.
Cookies are stored in VS Code's SecretStorage (encrypted via the OS keychain), not in settings.json.
Expiry: LEETCODE_SESSION is a JWT that lasts about 2 weeks; csrftoken is effectively long-lived. KestrelCP decodes the JWT and refuses to make a doomed call when it's already expired — it tells you precisely which cookie to refresh:
- 🔑 "LEETCODE_SESSION expired on YYYY-MM-DD" → re-paste fresh cookies.
- 🛡️ "LeetCode rejected the csrftoken" → re-paste both (they're usually rotated together).
- ⏳ "LeetCode is rate-limiting" → wait a few seconds and try again.
To clear: run KestrelCP: Set LeetCode Cookies again and submit empty values for one or both prompts — empty input clears that secret.
📋 Commands
| Command |
What it does |
KestrelCP: Initialize Workspace |
Creates platform directories and playground/Playground.java. Required before using any other command. |
KestrelCP: New Problem |
Prompts for platform + URL, scaffolds the problem folder, fetches sample tests |
KestrelCP: Search LeetCode |
Searches LeetCode by title or keyword and scaffolds the picked problem |
KestrelCP: Run Tests for Current Problem |
For Kattis / Codeforces, compiles Solution.java and checks against every *.in / *.out. For LeetCode, runs the file on LeetCode's official judge via the "Run Code" endpoint (does not count as a submission). Only visible / runnable when a Solution.java is active. |
KestrelCP: Submit to LeetCode |
Submits the current LeetCode Solution.java for official judging. Reports verdict + runtime / memory percentile. Counts as a real submission. Only visible when a LeetCode Solution.java is active. |
KestrelCP: Set LeetCode Cookies |
Stores LEETCODE_SESSION and csrftoken in VS Code's SecretStorage (used by run / submit). Submit empty values to clear. See LeetCode setup. |
KestrelCP: Set Anthropic API Key |
Stores the Anthropic API key in SecretStorage (used by AI Commit). Submit empty to clear; otherwise the shell ANTHROPIC_API_KEY env var is used as a fallback. |
KestrelCP: Run Playground |
Compiles playground/*.java and runs Playground. Only visible when Playground.java is active. |
KestrelCP: AI Commit |
Generates a Conventional Commit message from staged changes via Claude (requires ANTHROPIC_API_KEY) |
⚙️ Settings
| Setting |
Default |
Purpose |
kestrelcp.commitModel |
claude-haiku-4-5 |
Anthropic model used by AI Commit |
Sensitive values (Anthropic API key, LeetCode cookies) are not stored in settings — they live in VS Code's encrypted SecretStorage. Use the KestrelCP: Set ... commands to manage them.
KestrelCP invokes python3 directly — it expects Python 3 to be on PATH and will show an error on activation if python3 --version fails. Users with a virtualenv should activate it before launching VS Code.
🔍 How it works
- Scaffolding (Kattis / Codeforces) parses HTML with
requests + BeautifulSoup and writes one *.in / *.out pair per sample.
- Scaffolding (LeetCode) uses LeetCode's public GraphQL endpoint to pull
exampleTestcases, codeSnippets (the editor's Java template), and the HTML problem statement. No auth needed for non-premium problems.
- Testing (Kattis / Codeforces) runs
javac Solution.java, then java Solution once per *.in with stdin redirected. Output is compared to the matching *.out ignoring trailing whitespace and blank lines. 5-second timeout per case.
- Testing (LeetCode) reads every
*.in for the problem, concatenates them into a single data_input, and POSTs to LeetCode's interpret_solution endpoint (the "Run Code" button). The judge runs every case in one container and returns parallel code_answer / expected_code_answer arrays. End-to-end latency is typically ~1-2 seconds regardless of case count, since the cost is dominated by judge container spin-up.
- For sample cases, KestrelCP honors LeetCode's overall verdict (
status_msg: "Accepted") even when string equality disagrees — so multi-valid-answer problems (e.g. two-sum returning [1,0] instead of [0,1]) don't get false FAILs.
- For custom inputs (any
<N>.in you add that LeetCode hasn't seen), there's no reference to compare against; the output is shown without a verdict so you can eyeball it. Local <N>.out files are deliberately not used for comparison.
- Submitting (LeetCode) POSTs to
/problems/<slug>/submit/ and polls until the judge returns the verdict (Accepted / Wrong Answer / TLE / Compile Error / Runtime Error). On Accepted, reports the runtime and memory percentile.
- AI Commit runs
git diff --staged, asks Claude for a one-line Conventional Commit message with an emoji prefix:
| Emoji |
Type |
When to use |
| ✨ |
feat |
New solution or feature |
| 🐛 |
fix |
Bug fix |
| 📝 |
docs |
Notes / README update |
| ♻️ |
refactor |
Rewrite without changing behavior |
| ✅ |
test |
Adding or fixing test cases |
| 🔧 |
chore |
Tooling, config, scripts |
| ⚡️ |
perf |
Performance improvement |
| 💄 |
style |
Formatting only |
Confirm with y (accept), n (abort), or e (edit before committing).
🛠️ Contributing / development
Working on the extension itself? Head to the GitHub repo for the dev loop, manual test plan, scraper canary, and release process.
🪪 License
MIT — see LICENSE.