Skip to content

Five-Day Build Plan — peek v0.1.0

Assumption: All-day coding, ~10–12 hours/day, one person (or two pairing). Python-primary. Goal: shippable peek v0.1.0 on PyPI + GitHub by end of Day 5, with demo GIF and launch-ready README.

Total estimated effort: ~45 hours of focused work + 5 hours buffer.


Overview

Day Theme Deliverable by EOD Hours
1 Scanner + Project Scaffolding peek scan . prints file stats + tech stack 9
2 Analyzer (AST graph + ranking + summary) peek analyze . prints ranked "start here" + summary 10
3 Renderer — Static (Rich) + TUI (Textual) peek . shows beautiful output, TUI navigable 10
4 Polish, P1 features, Testing --html, --pack, --find, tests, edge cases 9
5 Packaging, Demo, Docs, Launch PyPI + GitHub + GIF + README + launch posts 8

Buffer: 5 hours distributed (scope cuts listed per day).


Day 1 — Scanner + Scaffolding (9h)

Goal: peek scan . walks any repo and reports what it found.

Tasks

# Task Hours Details
1.1 Scaffold repo + pyproject.toml 1.0 uv init or poetry init → pyproject.toml with typer, rich, textual, pathspec; peek/__init__.py, peek/cli.py stub, tests/
1.2 .gitignore handling 1.5 pathspec — load .gitignore, .peekignore, default ignores (__pycache__, .git, .venv, node_modules, dist, build, .pytest_cache, *.pyc); test with real repos
1.3 File walker 2.0 scanner.scan(path) → ScanResult: walk, collect FileInfo(path, size, ext, loc), count LOC (simple: non-empty lines minus comments heuristic), language breakdown; benchmark on 500-file repo
1.4 Tech stack detection 1.5 Check for pyproject.toml, requirements.txt, package.json, Cargo.toml, go.mod, Dockerfile, Makefile, py.typed, etc. → TechStack dict; parse pyproject.toml for deps
1.5 Entry point detection 2.0 Heuristics: filename (main.py, app.py, cli.py, etc.), if __name__ == "__main__", pyproject.toml [project.scripts], Dockerfile CMD; return ranked EntryPoint list
1.6 CLI stub + manual test 1.0 peek scan . command that prints ScanResult as Rich table; test on 3 repos (tiny fixture, requests, your own)

Code sketch — scanner

# peek/scanner.py
from dataclasses import dataclass
from pathlib import Path
import pathspec

DEFAULT_IGNORE = ["__pycache__", ".git", ".venv", "node_modules", "dist", "build"]

@dataclass
class FileInfo:
    path: Path
    ext: str
    loc: int
    size: int

@dataclass
class ScanResult:
    files: list[FileInfo]
    tech_stack: dict
    entry_candidates: list[Path]
    stats: dict  # {total_files, total_loc, by_lang: {...}}

def scan(root: Path) -> ScanResult: ...
def detect_tech_stack(root: Path, files: list[FileInfo]) -> dict: ...
def detect_entry_points(root: Path, files: list[FileInfo]) -> list[Path]: ...

EOD check

peek scan .                    # works on current repo
peek scan /tmp/some-other-repo # works on any path
# Output: Rich table with file count, LOC, tech stack, entry points

Scope cuts if behind

  • Drop LOC accuracy (use file size proxy)
  • Drop pyproject.toml script parsing (just filename heuristics)

Day 2 — Analyzer (10h)

Goal: peek analyze . builds import graph, ranks files, generates summary.

Tasks

# Task Hours Details
2.1 AST import extraction 2.5 ast.parse each .py file → Import/ImportFrom → resolve to local files vs external deps; handle from . import, relative imports, __all__; skip SyntaxError files gracefully
2.2 Graph construction 2.0 dict[Path, set[Path]] — file → {imported_local_files}; also reverse_graph for in-degree; handle __init__.py package imports
2.3 Centrality + ranking 2.0 In-degree + simple PageRank (5 iterations) + entry bonus; rank_files(graph, entry_candidates) → sorted RankedFile(path, score, reason); test ranking on known repos (does main.py rank top?)
2.4 Heuristic summary 1.5 Template-based: detect framework (fastapi/django/flask/click/typer in imports), DB (sqlalchemy/psycopg2), queue (celery/rq), etc. → sentence; fallback to "Python project with N modules"
2.5 Wire scan → analyze → CLI 1.0 peek analyze . prints ranked list + summary as Rich; AnalyzerResult dataclass
2.6 Test on 3 real repos 1.0 Clone requests, fastapi, textual → verify ranking makes sense; fix edge cases (circular imports, namespace packages)

Code sketch — analyzer

# peek/analyzer.py
from dataclasses import dataclass

@dataclass
class RankedFile:
    path: Path
    score: float
    reasons: list[str]  # ["entry point", "hub (imported by 5 files)"]

@dataclass
class AnalyzerResult:
    graph: dict[Path, set[Path]]
    ranked: list[RankedFile]
    summary: str
    tech_stack: dict

def build_graph(files: list[FileInfo], root: Path) -> dict[Path, set[Path]]: ...
def rank_files(graph, entry_candidates) -> list[RankedFile]: ...
def summarize(graph, ranked, tech_stack) -> str: ...
def analyze(scan_result: ScanResult) -> AnalyzerResult: ...

EOD check

peek analyze . 
# Output:
# Summary: FastAPI-based API with Postgres...
# Start Here:
#   1. app/main.py (entry, hub) — score 9.2
#   2. app/core/executor.py (hub, central) — score 8.1
#   ...

Scope cuts if behind

  • Skip PageRank — use in-degree only (good enough for MVP)
  • Skip framework detection — use generic summary template

Day 3 — Renderer: Static + TUI (10h)

Goal: peek . is beautiful. TUI is navigable.

Tasks

# Task Hours Details
3.1 Rich static renderer 3.0 renderer.render(result) → 4 Rich panels: Summary, Architecture (ranked list as "graph"), Start Here (table), Stats/Stack; Columns layout; --no-tui flag; test in various terminal widths
3.2 ASCII mini-graph 1.0 _ascii_graph.py: graph → "cli → api → core → db" one-liner; or vertical cli\n │\n api → core; keep simple — ranked list IS the graph for MVP
3.3 Textual TUI skeleton 2.5 tui.PeekApp(AnalyzerResult) — layout: header + 4 panels + footer; mount Rich panels as Static widgets; key bindings: q quit, j/k nav
3.4 TUI interactivity 2.5 Navigate Start Here list; enter drills into file (show its imports/dependents); o opens $EDITOR; / filter; live summary update
3.5 Wire peek . (default = TUI, --no-tui = static) 1.0 cli.py — peek [PATH] → scan → analyze → render or tui; handle --no-tui/--help; test both modes

Code sketch — renderer + TUI

# peek/renderer.py
from rich.console import Console
from rich.panel import Panel
from rich.table import Table

def render_static(result: AnalyzerResult, console: Console): ...

# peek/tui.py
from textual.app import App
from textual.widgets import Static, ListView

class PeekApp(App):
    CSS = """..."""
    BINDINGS = [("q", "quit", "Quit"), ("o", "open", "Open"), ...]
    def compose(self): ...
    def on_key(self, event): ...

EOD check

peek .              # TUI appears, navigable, beautiful
peek . --no-tui     # Static Rich output, pipeable
# Screenshot both — they should be tweet-ready

Scope cuts if behind

  • Drop drill-in (enter) — just nav + quit for MVP
  • Drop / filter — add in P1
  • Drop ASCII graph — Start Here list alone is enough

Day 4 — Polish, P1 Features, Testing (9h)

Goal: P1 features + robustness + tests.

Tasks

# Task Hours Details
4.1 --html export 1.5 Render static output to self-contained HTML (Jinja template + Rich export_html or manual); peek . --html -o peek.html
4.2 --pack (smart LLM pack) 2.0 peek . --pack → concatenates ranked files (top N by score, within token budget) → clipboard (pyperclip) or stdout/file; respects token estimate (tiktoken or len/4 heuristic); peek . --pack --ask "auth" filters by keyword
4.3 --find "query" 1.0 Keyword search over filenames + file contents (top 20 lines) ranked by AnalyzerResult score + keyword match; peek --find "token validation"
4.4 Optional LLM summary 1.0 peek/llm.py — if OPENAI_API_KEY/ANTHROPIC_API_KEY set, call cheap model for better summary; fallback to heuristic; peek . --llm forces it
4.5 Tests 2.0 tests/test_scanner.py, test_analyzer.py, test_renderer.py — fixtures: 3 sample repos (tiny 5-file, medium 30-file, clone of requests); assert scan count, ranking, no crash on weird files
4.6 Edge cases + perf 1.5 Handle: non-Python repos (graceful), huge repos (2k+ files, timeout after 5s scan), binary files, SyntaxError files, empty repos, permission errors; benchmark < 2 sec for 500 files

EOD check

peek . --html -o /tmp/peek.html && open /tmp/peek.html
peek . --pack | wc -c
peek --find "auth" .
pytest -q  # all green

Scope cuts if behind

  • Drop --find (keyword search is nice but not P0)
  • Drop LLM summary (heuristic is fine for v0.1.0)
  • Minimal tests (just smoke tests) — full suite in v0.1.1

Day 5 — Packaging, Demo, Docs, Launch (8h)

Goal: pip install peek works + GitHub repo is launch-ready.

Tasks

# Task Hours Details
5.1 pyproject.toml polish + PyPI 1.5 Finalize pyproject.toml (metadata, readme, keywords, classifiers, project.urls, project.scripts = {peek = "peek.cli:app"}); python -m build; twine check; twine upload (test.pypi first); verify pip install peek in fresh venv
5.2 README — the landing page 2.0 GIF at top (see 5.3), one-liner + install + demo, features, usage, examples (peek on 3 famous repos with screenshots), comparison table, contributing; use rich README template; badges (PyPI, stars, license)
5.3 Demo GIF/video 1.5 Record with vhs (charmbracelet/vhs) or asciinema + agg or simple screen record; script: git clone requests → peek . → TUI nav → peek . --no-tui → peek --find; 15–20 sec, 800px wide, < 3MB; also static screenshot fallback
5.4 GitHub repo polish 1.0 LICENSE (MIT), CONTRIBUTING.md (minimal), assets/ (GIF, screenshots), repo description + topics (python, cli, tui, codebase, visualization), pin README GIF
5.5 Launch posts (draft, don't publish yet) 1.5 HN Show HN post (title + body), Twitter thread (3 tweets + GIF), Reddit r/Python post, Product Hunt draft; see 08_launch_playbook.md
5.6 Smoke test + tag release 0.5 Fresh machine/VM: pipx install peek → peek . on 2 repos → peek --help; git tag v0.1.0 && git push --tags; GitHub Release with notes

README skeleton

<p align="center">
  <img src="assets/demo.gif" width="800" />
</p>

<h1 align="center">peek — htop for codebases</h1>
<p align="center">Understand any codebase in 5 seconds. <code>pip install peek && peek .</code></p>
<p align="center">
  <a href="https://pypi.org/project/peek/"><img src="https://img.shields.io/pypi/v/peek" /></a>
  <a href="https://github.com/you/peek"><img src="https://img.shields.io/github/stars/you/peek?style=social" /></a>
</p>

## Install

\`\`\`bash
pip install peek        # or: pipx install peek / uv tool install peek
\`\`\`

## Usage

\`\`\`bash
peek .                  # interactive TUI
peek . --no-tui         # static output (for screenshots/CI)
peek . --html -o map.html
peek --find "auth" .
\`\`\`
...

EOD check — launch readiness

  • [ ] pip install peek works in fresh venv on macOS + Linux
  • [ ] peek . TUI beautiful on 80×24 and 120×40 terminals
  • [ ] peek . --no-tui screenshot is tweet-ready
  • [ ] demo.gif < 3MB, < 20 sec, autoplay, no audio needed
  • [ ] README GIF visible without scrolling
  • [ ] pytest -q green, ruff check clean
  • [ ] GitHub Release v0.1.0 created

Launch timing

  • Don't launch Day 5 evening — launch next morning (Tue–Thu 08:00 UTC) for HN max visibility. Use Day 5 evening to rest and draft posts.

Risk Mitigations

Risk Likelihood Mitigation
Textual TUI bugs on some terminals Medium Ship --no-tui as primary demo fallback; TUI is progressive enhancement
AST parse fails on Python 2 / weird syntax Medium try/except SyntaxError → skip file, log warning, don't crash
Huge repo (5k+ files) slow Low Cap scan at 2k files for MVP, show "…and 3k more"
peek name taken on PyPI Medium Alternatives: codepeek, peek-code, peekcode, repeek — check on Day 1 morning
Scope creep (want to add everything) High Strict P0/P1/P2 — cut P2 ruthlessly; P1 is "if time"

Hour-by-Hour Summary

Day Hours Cumulative
1 9 9
2 10 19
3 10 29
4 9 38
5 8 46

This is tight but realistic for all-day coding. If you have a pair, Day 3–4 parallelize (one on TUI, one on --pack/--html).


Next → 07_competitive_landscape.md and 08_launch_playbook.md.


Author: Hariom Lohar -- hariomlohar.new@gmail.com -- https://hariomlohardev.github.io/ -- 2026-08-10