erg-lang/erg
A statically typed language compatible with Python
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 5mo ago
- ✓2 active contributors
- ✓Apache-2.0 licensed
Show all 8 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Slowing — last commit 5mo ago
- ⚠Small team — 2 contributors active in recent commits
- ⚠Single-maintainer risk — top contributor 99% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/erg-lang/erg)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/erg-lang/erg on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: erg-lang/erg
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/erg-lang/erg shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 5mo ago
- 2 active contributors
- Apache-2.0 licensed
- CI configured
- Tests present
- ⚠ Slowing — last commit 5mo ago
- ⚠ Small team — 2 contributors active in recent commits
- ⚠ Single-maintainer risk — top contributor 99% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live erg-lang/erg
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/erg-lang/erg.
What it runs against: a local clone of erg-lang/erg — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in erg-lang/erg | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 185 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of erg-lang/erg. If you don't
# have one yet, run these first:
#
# git clone https://github.com/erg-lang/erg.git
# cd erg
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of erg-lang/erg and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "erg-lang/erg(\\.git)?\\b" \\
&& ok "origin remote is erg-lang/erg" \\
|| miss "origin remote is not erg-lang/erg (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "Cargo.toml" \\
&& ok "Cargo.toml" \\
|| miss "missing critical file: Cargo.toml"
test -f "crates/erg_compiler/lib.rs" \\
&& ok "crates/erg_compiler/lib.rs" \\
|| miss "missing critical file: crates/erg_compiler/lib.rs"
test -f "crates/erg_parser/lib.rs" \\
&& ok "crates/erg_parser/lib.rs" \\
|| miss "missing critical file: crates/erg_parser/lib.rs"
test -f "crates/erg_common/lib.rs" \\
&& ok "crates/erg_common/lib.rs" \\
|| miss "missing critical file: crates/erg_common/lib.rs"
test -f "crates/els/main.rs" \\
&& ok "crates/els/main.rs" \\
|| miss "missing critical file: crates/els/main.rs"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 185 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~155d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/erg-lang/erg"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Erg is a statically-typed programming language designed for Python interoperability and compatibility, written entirely in Rust. It provides Rust-like robustness with a powerful type system (including dependent types, refinement types, and Option types for null-safety) while maintaining Python syntax familiarity and the ability to import and use Python libraries seamlessly via pyimport. The compiler is structured as a multi-stage pipeline: lexer/parser (erg_parser), type checker/compiler (erg_compiler), and linter (erg_linter), with a Language Server Protocol implementation (els) for IDE integration. Monorepo structure under crates/: erg_compiler (core type checker and codegen), erg_parser (lexer/syntax tree), erg_common (shared utilities), erg_linter (static analysis), els (LSP server for editors), and erg_proc_macros (compile-time codegen). The build system uses Cargo with workspace features (debug, japanese, simplified_chinese, traditional_chinese, unicode, pretty, large_thread, parallel) that cascade to dependent crates, allowing targeted compilation modes. CI/CD pipelines in .github/workflows/ handle testing, documentation builds, and releases.
👥Who it's for
Python developers frustrated with dynamic typing who want compile-time safety without Rust's verbosity and memory management; systems programmers wanting a simpler alternative to Rust for creating robust, type-safe code; and language designers interested in dependent types and refinement types applied to a practical, general-purpose language.
🌱Maturity & risk
Actively developed but pre-1.0 (currently v0.6.53 as of the Cargo.toml snapshot). The project has comprehensive CI/CD via GitHub Actions (.github/workflows/main.yml, release.yml, docs.yml), a multi-crate workspace structure, and clear feature flags for debugging and localization. However, TODO.md explicitly documents unimplemented features, indicating this is still in active development with breaking changes possible; production use is not yet recommended.
The project is primarily Rust-centric (4.2M lines) with a single organization driving development (erg-lang GitHub org). Pre-1.0 status means the language spec and standard library are still evolving—code written today may require updates. The dependency surface is moderate (multi-crate workspace with erg_common, erg_parser, erg_compiler, erg_linter, els as core crates), but the lack of a stable release and small community adoption mean ecosystem support is nascent compared to Python or Rust.
Active areas of work
The project is in active feature development toward a stable release. Localization support is being expanded (japanese, simplified_chinese, traditional_chinese features present), and the LSP server (els/) is being enhanced with language server features (code_lens.rs, code_action.rs, completion.rs, call_hierarchy.rs visible in the file list). Build tooling is maturing (Cross.toml for cross-platform builds, cargo_publish.sh/bat scripts for release automation). The 0.6.x version series suggests incremental progress toward 0.7 or 1.0.
🚀Get running
Clone and build with Cargo: git clone https://github.com/erg-lang/erg && cd erg && cargo build --release. For development, use cargo build (debug mode) and cargo test to run the test suite. Set up the pre-commit hooks with pre-commit install (pre-commit-config.yaml is configured). For nightly development with Nix, direnv allow after entering the repo (see .envrc).
Daily commands:
Development: cargo build for debug binary, then run ./target/debug/erg your_script.er. The language server starts with cargo run --package els --release. For testing: cargo test (runs all workspace tests). For release builds: cargo build --release or use cargo_publish.sh (Linux/macOS) / cargo_publish.bat (Windows) for official releases.
🗺️Map of the codebase
Cargo.toml— Workspace root defining all member crates (erg_common, erg_compiler, erg_parser, erg_linter, els) and shared version/metadata—every contributor must understand the monorepo structure.crates/erg_compiler/lib.rs— Entry point for the Erg compiler; defines the public API and orchestrates parsing, type checking, and code generation.crates/erg_parser/lib.rs— Core parser crate that transforms Erg source text into AST; fundamental to all compilation pipelines.crates/erg_common/lib.rs— Shared utilities and types (error handling, config, opcodes, env) used across all crates; defines cross-crate conventions.crates/els/main.rs— Language Server Protocol entry point; bridges IDE tooling to the compiler infrastructure.build.rs— Build script handling version bumping and code generation at compile time; required for reproducible builds.crates/erg_compiler/codegen/mod.rs— Code generation layer translating HIR to Python bytecode; the final compiler stage before execution.
🛠️How to make changes
Add a new language feature (e.g., new keyword or expression type)
- Define the new AST node in the expression/statement enums (
crates/erg_parser/ast.rs) - Implement parsing logic in the recursive descent parser (
crates/erg_parser/parser.rs) - Add type checking rules and HIR desugaring (
crates/erg_compiler/type_checker/mod.rs) - Implement bytecode generation in the codegen module (
crates/erg_compiler/codegen/mod.rs) - Update LSP hover and completion to recognize the feature (
crates/els/hover.rs)
Add a new IDE feature (e.g., new diagnostic rule)
- Implement the analysis logic in a new els module or extend existing (
crates/els/diagnostics.rs) - Register the handler in the LSP server request dispatcher (
crates/els/server.rs) - Optionally add code actions to fix the issue (
crates/els/code_action.rs) - Write integration tests in the els test suite (
crates/els/tests/test.rs)
Add support for a new Python version
- Create a new opcode module for the Python version (e.g., opcode311.rs) (
crates/erg_common/opcode311.rs) - Update environment detection to recognize the version (
crates/erg_common/env.rs) - Update codegen to select the correct opcode set at runtime (
crates/erg_compiler/codegen/mod.rs) - Add version-specific tests to CI/CD (
.github/workflows/main.yml)
Add a new linting rule
- Define the rule logic in the linter (
crates/erg_linter/lib.rs) - Wire the linter into the compiler pipeline (
crates/erg_compiler/lib.rs) - Expose the lint result as a diagnostic in the LSP layer (
crates/els/diagnostics.rs)
🔧Why these technologies
- Rust — Type safety, performance, and memory safety required for a production compiler; prevents common compiler bugs.
- LSP (Language Server Protocol) — IDE-agnostic protocol allows Erg tooling to work in any LSP-compatible editor without editor-specific plugins.
- Python bytecode compilation target — Erg is designed as Python-compatible; leverages existing Python runtime, libraries, and ecosystem while adding static typing.
- Monorepo (Cargo workspace) — Tight coordination between parser, compiler, linter, and LSP; shared dependencies and version management simplify releases.
- Bidirectional type inference — Reduces boilerplate type annotations while maintaining static guarantees; compatible with Python's dynamic nature.
⚖️Trade-offs already made
-
Compile to Python bytecode rather than a custom VM
- Why: Compatibility with Python ecosystem and libraries.
- Consequence: Bound by Python runtime performance; Erg-only optimizations are harder than in a custom runtime.
-
Single-pass type checking with error recovery
- Why: Fast feedback loop for IDE and REPL use cases.
- Consequence: Cannot perform whole-program optimization; cascading type errors possible.
-
LSP as the primary IDE integration layer
- Why: Language-agnostic and decoupled from editor internals.
- Consequence: Feature parity across editors; loses editor-specific deep integrations (e.g., VS Code extensions).
-
Tolerant parsing for LSP completion and diagnostics
- Why: Must provide
- Consequence: undefined
🪤Traps & gotchas
Workspace features cascade: Enabling a feature in the root Cargo.toml (e.g., --features japanese) cascades to all member crates; if you only want to test one crate, build it directly (e.g., cargo build -p erg_compiler). Python interop requires Python runtime: erg code compiled with pyimport depends on a Python 3.x interpreter being available; standalone binaries still need Python available for stdlib imports. LSP server is a separate binary: els/ is not auto-started; you must run cargo run --package els --release in a separate terminal or configure your editor's LSP client to invoke it. Localization is compile-time: error messages are baked in; if you switch features, you must rebuild. Cross-compilation: Cross.toml exists for cross-platform builds, but the setup may require additional system dependencies (musl, etc.) not documented in the README. No stable stdlib ABI yet: the Erg standard library is still evolving; code relying on undocumented APIs may break between minor versions.
🏗️Architecture
💡Concepts to learn
- Dependent Types — Erg uses dependent types to encode constraints (e.g., array bounds, value ranges) in the type system, enabling compile-time detection of index-out-of-bounds and division-by-zero errors that Python would only catch at runtime.
- Refinement Types — Erg's type system includes refinement types (e.g., Nat as a refinement of Int ≥ 0), allowing predicates on types to be checked statically; the
.times!method in the README example only accepts Nat, catching negative argument bugs at compile time. - Hindley–Milner Type Inference — Erg's type inference engine (in erg_compiler) uses HM-style inference, allowing developers to omit type annotations while maintaining full static type safety; understanding this is critical when working on the type checker.
- Language Server Protocol (LSP) — The els/ crate implements LSP to integrate Erg with IDEs (VS Code, Vim, Emacs, etc.); understanding LSP is essential for extending IDE features like completion, hover, and diagnostics.
- Multi-stage Compiler Architecture — Erg's compilation pipeline (erg_parser → erg_compiler → codegen) mirrors professional language implementations; understanding each stage's responsibilities (parsing, type checking, code generation) is vital for debugging and extending the compiler.
- Python Interoperability via Bytecode — Erg compiles to Python bytecode (.pyc) and can import Python modules via
pyimport, requiring deep knowledge of Python's object model and CPython's bytecode format; this is unique among compiled languages and critical to Erg's value proposition. - Sum Types (Discriminated Unions) — Erg uses sum types (Option, Result-like types) for null safety and error handling, compiling them to Python at runtime; understanding how sum types are represented and pattern-matched is essential for both language features and interop.
🔗Related repos
rust-lang/rust— Erg's type system and compiler architecture are inspired by Rust's robustness; studying Rust's trait system and error messages directly informs Erg's design.python/cpython— Erg compiles to Python bytecode and must interoperate with CPython at runtime; understanding CPython's object model and bytecode format is essential for Erg's code generation.scala/scala— Erg explicitly targets users who want Scala's blend of OOP and functional paradigms; Scala's approach to type inference and implicit parameters influences Erg's design.mypy/mypy— MyPy's gradual typing approach for Python inspired Erg's Python interoperability strategy; both aim to add static types to Python ecosystems.erg-lang/erg-book— Official Erg language specification and tutorial; essential reference for language semantics and intended use cases beyond what the codebase alone reveals.
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for ELS (Erg Language Server) features
The crates/els directory contains multiple feature modules (completion.rs, hover.rs, definition.rs, rename.rs, etc.) but there's no visible test directory structure. Given that LSP is critical for developer experience and the repo has an active language server implementation, adding integration tests for these features would prevent regressions and improve reliability. This is especially valuable given the complexity of LSP protocol implementations.
- [ ] Create crates/els/tests/ directory structure
- [ ] Add integration tests for completion.rs covering basic and advanced completion scenarios
- [ ] Add tests for hover.rs with multiple type signatures
- [ ] Add tests for definition.rs and references.rs with cross-file navigation
- [ ] Add tests for rename.rs ensuring symbol renaming works across scopes
- [ ] Document test patterns in crates/els/README.md
Create GitHub Actions workflow for cross-platform binary releases
The repo has Cross.toml (indicating cross-compilation support) and release.yml workflow exists, but there's no documented or automated process for building and releasing binaries for multiple platforms (Linux x86_64, macOS, Windows, and ARM targets). Given the language has a CLI and LSP server, distributing pre-built binaries would significantly improve adoption. This involves creating a complete release pipeline.
- [ ] Review existing .github/workflows/release.yml and Cross.toml configuration
- [ ] Extend release.yml to build binaries for linux-x86_64, linux-arm64, macos-x86_64, macos-arm64, and windows-x86_64
- [ ] Add upload-artifact steps to attach binaries to GitHub releases
- [ ] Create RELEASES.md documenting the binary release process and supported platforms
- [ ] Add checksums (SHA256) generation for released binaries
- [ ] Test the workflow on a feature branch before merging
Add localization infrastructure tests for i18n features
The repo supports multiple languages (japanese, simplified_chinese, traditional_chinese, unicode features in Cargo.toml), but there's no visible test suite validating that translations are complete, properly formatted, and don't have missing keys across language variants. This prevents i18n bugs and inconsistencies in error messages and documentation strings across different language builds.
- [ ] Identify where translation strings are stored (likely in erg_common, erg_parser, erg_compiler crates)
- [ ] Create a new test module (test_i18n or similar) in each affected crate
- [ ] Add tests validating that all english keys have corresponding translations for japanese, simplified_chinese, and traditional_chinese
- [ ] Add tests checking for unused translation keys (dead code detection)
- [ ] Add tests validating character encoding for non-ASCII languages
- [ ] Document translation contribution guidelines in CONTRIBUTING.md
🌿Good first issues
- Add missing unit tests for edge cases in crates/erg_parser/src/ (e.g., error recovery in malformed syntax, handling of deeply nested expressions). The parser is critical for correctness; comprehensive test coverage would catch regressions early.
- Improve error messages for type mismatch failures in erg_compiler's type checker by adding context-aware suggestions (e.g., 'Expected Meter but found Kg; did you mean to use unit conversion?'). Look for type inference error reporting in erg_compiler/src/ and add suggestion logic similar to Rust's compiler.
- Expand the LSP server (crates/els/) with hover documentation support (code_action.rs and completion.rs exist, but hover.rs is likely missing). This would show type signatures and docstrings when users hover over symbols in their editor, following LSP specification.
📝Recent commits
Click to expand
Recent commits
b8bc4e3— Update Cargo.lock (mtshiba)3982b06— fix clippy warnings (mtshiba)1999f11— feat: support pyo3 v0.25 (mtshiba)96d223f— chore: fix clippy warnings (mtshiba)093bf73— feat: add type decl files (mtshiba)0076174— fix: clippy warnings (mtshiba)48d0dd3— Update _erg_str.py (mtshiba)0bfc1c8— Update ast.d.er (mtshiba)26620dd— Create symtable.d.er (mtshiba)7c10b6b— Merge pull request #540 from jorenham/patch-1 (mtshiba)
🔒Security observations
The Erg language repository demonstrates reasonable security practices with dual licensing, modular structure, and a defined security policy. However, the security policy lacks clarity regarding patch timelines for pre-release versions (0.x), which could leave users uncertain about update schedules. No obvious hardcoded secrets, injection risks, or critical misconfigurations were detected in the provided file structure. The main areas for improvement are: (1) enhancing the security policy with clearer support timelines, (2) documenting feature flag security implications, and (3) ensuring pre-commit hooks enforce security best practices. The codebase appears well-organized with proper CI/CD workflows and documentation.
- Medium · Incomplete Security Policy —
SECURITY.md. The SECURITY.md file indicates that only the 'latest' version is supported for security updates, and no versions prior to the latest are supported. However, the project is in 0.x version range (0.6.53) which explicitly states 'Erg does not guarantee any compatibility during 0.x'. This creates ambiguity about security patch applicability and may leave users on non-latest versions vulnerable. Fix: Define clear security support timelines and patch policies. Specify how long previous minor/patch versions will receive security updates. Provide explicit guidance for users on when to upgrade. - Low · Pre-commit Configuration Present —
.pre-commit-config.yaml. A .pre-commit-config.yaml file is present which may contain tool configurations. While not inherently a vulnerability, pre-commit hooks should be reviewed to ensure they don't introduce security risks or bypass security checks. Fix: Review and document all pre-commit hooks. Ensure hooks enforce security best practices (e.g., secret scanning, dependency auditing). Keep hook versions updated. - Low · Multiple License Types —
LICENSE-MIT, LICENSE-APACHE. The project uses dual licensing (MIT OR Apache-2.0) with separate LICENSE files. While not a security vulnerability, dual licensing can create compliance complexity and potential confusion about which license applies in different contexts. Fix: Clearly document in README which license applies to which components. Consider adding SPDX license identifiers to source files for clarity. - Low · Feature Flags May Hide Dependencies —
Cargo.toml - [features] section. The Cargo.toml defines multiple conditional feature flags (debug, backtrace, japanese, simplified_chinese, traditional_chinese, unicode, pretty, large_thread). Feature flags can obscure dependencies and make security auditing more complex if not properly documented. Fix: Document all feature flags clearly. Ensure security audits include analysis of dependencies pulled in by each feature flag combination. Consider using cargo-tree to visualize dependency trees for each feature set.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.