Codebase Inspection with pygount: LOC, Languages, Ratios
Inspect codebases w/ pygount: LOC, languages, ratios.
Written by Neura Market from the official Hermes Agent documentation for Codebase Inspection. Commands, paths, and version numbers are reproduced from the source unchanged.
Read the official documentationThis skill answers the recurring question of how large a repository actually is, broken down by language and by code versus comments. It wraps pygount, a line-counting tool, into a repeatable workflow you can run from inside Hermes Agent whenever someone asks for LOC, a language breakdown, or a sense of a repo's composition.
Reach for it when you need numbers rather than impressions: sizing a codebase before you start work in it, comparing the weight of different languages in a polyglot project, or checking how much of a file is documentation versus executable logic.
What it does
The skill drives pygount against a directory and produces a summary table: each detected language, how many files it accounts for, how many lines are code, how many are comments, and what share of the total that represents. It can also emit per-file detail and JSON, so the same tool covers both a quick human-readable answer and a machine-readable one you can feed into another step.
Before you start
pygount is not assumed to be present, so the skill installs it first:
pip install --break-system-packages pygount 2>/dev/null || pip install pygount
The command tries a system-level install first and falls back to a plain user install if that fails. The skill is bundled with Hermes Agent, so there is nothing to add to your agent configuration. It runs on linux, macos, and windows.
1. Basic summary
This is the form you will use most often. It gives a full language breakdown with file counts, code lines, and comment lines:
cd /path/to/repo
pygount --format=summary \
--folders-to-skip=".git,node_modules,venv,.venv,__pycache__,.cache,dist,build,.next,.tox,.eggs,*.egg-info" \
.
The --folders-to-skip list is not optional in practice. Without it, pygount walks dependency and build directories too, which on a real project means a very long run or a hang. Treat the exclusion list as part of the command, not a tuning knob.
2. Common folder exclusions
Which directories to skip depends on the project. The skill offers three starting points:
# Python projects
--folders-to-skip=".git,venv,.venv,__pycache__,.cache,dist,build,.tox,.eggs,.mypy_cache"
# JavaScript/TypeScript projects
--folders-to-skip=".git,node_modules,dist,build,.next,.cache,.turbo,coverage"
# General catch-all
--folders-to-skip=".git,node_modules,venv,.venv,__pycache__,.cache,dist,build,.next,.tox,vendor,third_party"
Pick the one closest to the repo in front of you and adjust from there. The goal is the same in every case: keep the scan on first-party source.
3. Filter by specific language
When you only care about one language, or a short list, restrict the scan by suffix:
# Only count Python files
pygount --suffix=py --format=summary .
# Only count Python and YAML
pygount --suffix=py,yaml,yml --format=summary .
This is the cheapest way to get a fast answer on a large tree, since files outside the suffix list are not counted.
4. Detailed file-by-file output
Dropping --format=summary gives a per-file breakdown instead of an aggregate:
# Default format shows per-file breakdown
pygount --folders-to-skip=".git,node_modules,venv" .
# Sort by code lines (pipe through sort)
pygount --folders-to-skip=".git,node_modules,venv" . | sort -t$'\t' -k1 -nr | head -20
The second form pipes the output through sort to surface the largest files by code line count, capped at twenty. Use it when the summary tells you a language dominates and you want to know which files are responsible.
5. Output formats
Three output shapes are documented:
# Summary table (default recommendation)
pygount --format=summary .
# JSON output for programmatic use
pygount --format=json .
# Pipe-friendly: Language, file count, code, docs, empty, string
pygount --format=summary . 2>/dev/null
Use summary for a person reading the result, json when another tool or step consumes it, and the redirected form when you want the table without anything written to standard error mixed in.
6. Interpreting results
The summary table has five columns: Language (the detected programming language), Files (how many files of that language), Code (lines of actual code, whether executable or declarative), Comment (lines that are comments or documentation), and % (share of the total).
Alongside real languages, the table can contain pseudo-language rows:
__empty__for empty files__binary__for binary files such as images or compiled artifacts__generated__for auto-generated files, detected heuristically__duplicate__for files with identical content__unknown__for unrecognized file types
Seeing these rows is normal. They are how the tool accounts for content that does not belong to a language bucket.
Limits and gotchas
Four things trip people up.
First, always exclude .git, node_modules, and venv. Without --folders-to-skip, the scan covers everything and can take minutes or hang on large dependency trees.
Second, Markdown reports zero code lines. pygount classifies all Markdown content as comments rather than code. That is expected, not a bug, so do not read a documentation-heavy repo as having no code.
Third, JSON files show low code counts because pygount may count JSON lines conservatively. If you need an accurate JSON line count, use wc -l on those files directly instead of trusting the table.
Fourth, on very large monorepos, consider narrowing with --suffix to target specific languages rather than scanning the whole tree.
What pairs with it
For repository work beyond counting, the related skill is github.