c++March 2026

leetcli

A command-line interface for LeetCode. Submit and solve problems locally.

view project →

Motivation

I wanted to solve LeetCode problems without leaving my terminal. The web editor is fine, but I'm faster in my own editor with my own keybindings and tools. The goal was a CLI that could fetch problems, let me write solutions locally, and submit them directly — all without opening a browser.

Architecture

The CLI is built in Go and communicates with LeetCode's GraphQL API. It handles session authentication, problem fetching, code submission, and result polling.

type Client struct {
    session    string
    csrfToken  string
    httpClient *http.Client
}
 
type Problem struct {
    ID         int
    Title      string
    Slug       string
    Difficulty string
    Content    string
}

The workflow is straightforward: leetcli fetch <problem> pulls the problem description and generates a solution template in your preferred language. You write your solution locally, then leetcli submit sends it off and streams the result back.

func (c *Client) Submit(slug string, lang string, code string) (*Result, error) {
    payload := map[string]string{
        "lang":        lang,
        "question_id": slug,
        "typed_code":  code,
    }
 
    resp, err := c.post("/problems/"+slug+"/submit/", payload)
    if err != nil {
        return nil, err
    }
 
    return c.pollResult(resp.SubmissionID)
}

Challenges

The trickiest part was handling LeetCode's authentication flow. Sessions expire, CSRF tokens rotate, and rate limiting kicks in if you're not careful. I ended up implementing automatic session refresh and request retrying with exponential backoff.

Parsing problem descriptions from HTML into clean terminal output also required some work — stripping tags while preserving code blocks, examples, and constraints in a readable format.

Takeaways

This was a fun exercise in building a developer tool that scratches your own itch. The GraphQL API exploration taught me a lot about reverse-engineering undocumented APIs, and the project became part of my daily workflow.