Why this rule
An agent that writes code in a language with no automated tests has no way to verify its own work. Tests are the agent’s exit condition — without them it can only produce a diff, not a proof. The AGENTS.md standard treats the test command as one of the highest-value pieces of context an agent can have. AE-TEST-001 checks that there is actually something to run — before AE-AUTO-001 checks that the command is discoverable.What triggers it
Charter detects active languages from manifest files committed to the repo:| Language | Manifest |
|---|---|
| Go | go.mod |
| JavaScript / TypeScript | package.json |
| Rust | Cargo.toml |
| Python | pyproject.toml or requirements.txt |
| Java / Kotlin | pom.xml or build.gradle |
| Ruby, C#, PHP | Equivalents |
scripts/, vendor/, node_modules/, dist/, build/).
For each active language, Charter checks whether at least one test file exists using standard naming conventions:
| Language | Test file patterns |
|---|---|
| Go | *_test.go |
| JavaScript / TypeScript | *.test.*, *.spec.* |
| Python | test_*.py, *_test.py, conftest.py |
| Rust | Files under tests/, inline #[cfg(test)] markers |
| Java / Kotlin | *Test.java, *Test.kt |
test/, tests/, spec/, or __tests__/ also count, regardless of language.
Charter detects active languages by manifest, not by line count. A
go.mod with one .go source file (non-test) counts as an active language and requires at least one test file.Examples
- Failing
- Passing
A Go module with source files under A TypeScript project with source files but no test files:
internal/ but no *_test.go file anywhere:How to fix
Add a minimal test file for each active language that Charter flags. The test does not need comprehensive coverage — Charter checks for presence, not coverage percentage or pyramid shape.Identify the active languages
Run
charter doctor or charter explain AE-TEST-001 to see which languages are flagged and which manifest triggered each one.Add a minimal test file
Create at least one test file using the language’s standard naming convention. A single passing test satisfies the rule.
Score impact
High (−10); no hard cap. If multiple active languages all lack tests, each fires a separate finding instance.
Edge cases
Docs, config, and tooling-only repos
Docs, config, and tooling-only repos
AE-TEST-001 does not fire when no recognized code language is active. A repo containing only Markdown, YAML config, or tooling scripts is not penalized.
Embedded web assets in Go binaries
Embedded web assets in Go binaries
A
//go:embed’d web asset (e.g. a report.js embedded into a Go binary) is a bundled resource, not a language surface. It does not activate JavaScript/TypeScript even when a build-tooling package.json is present.Stray secondary-language files
Stray secondary-language files
A lone
*.rb Homebrew formula with no Gemfile, or a stray *.py helper with no pyproject.toml, is not an active language and does not require tests.Rust inline tests
Rust inline tests
Rust inline unit tests count via the
#[cfg(test)] / #[test] content signal — no separate tests/ directory is required.Related rules
AE-AUTO-001
Requires a discoverable command to run the tests that this rule checks for.
AE-CI-002
Requires CI to run those tests on every pull request.