For AI agentsA Markdown index of these docs is at /llms.txt. Every page is also Markdown: add .md to its address.

Agent Rules / Names and imports

What happens when two functions share a name?

Rule AR-03

One public name, one definition: don't define the same function name in two modules a file can import together.

A name search for format_date returns every definition and every call, and nothing in the text says which call belongs to which definition. That depends on the import lines in each caller. An agent that edits one format_date has to work out, file by file, which callers it affects, and a miss in that step looks like a clean edit. Give each public function a name that exists once in the codebase and the search result is the answer.

Why it happens

Python. A def binds its name in the module namespace. The from form of the import statement looks up the attribute on the source module and stores a reference in the current namespace under the attribute name, or under the as name if one is given. Nothing about the call site format_date(row.when) records which module it came from. The binding is whichever statement ran last in that scope. Two from x import format_date lines in one file don't conflict at the language level: the second silently replaces the first.

TypeScript and JavaScript. An import { formatDate } from "./a" creates a binding that links to the exporting module's binding (the spec calls it CreateImportBinding). A file that needs both functions must rename one at the import site or use a namespace import. An export * barrel over both modules makes the name ambiguous (see AR-02). tsc 7.0.2 reports the duplicate imports as TS2300 (Duplicate identifier 'formatDate'.) on both import lines, and the conflicting star exports as TS2308 in the barrel itself (see AR-02).

What tools can and can't do. The linters cover redefinition inside one scope, where the second definition replaces the first. They don't cover two modules each owning a function of the same name, because each module is correct by itself. That case is a naming decision, and the check is a search.

Bad and good

python# bad: two packages, same name, different behaviour # billing/utils.py (MONTHS = ["Jan", "Feb", ...]) def format_date(d): # "03 Mar 2026" return f"{d.day:02d} {MONTHS[d.month - 1]} {d.year}" # reports/utils.py def format_date(d): # "2026-03-03" return d.isoformat() # invoices/render.py from billing.utils import format_date from reports.utils import format_date # replaces the line above, no error
python# good: names say what they do and exist once # billing/utils.py (MONTHS = ["Jan", "Feb", ...]) def format_invoice_date(d): return f"{d.day:02d} {MONTHS[d.month - 1]} {d.year}" # reports/utils.py def format_report_date(d): return d.isoformat() # invoices/render.py from billing.utils import format_invoice_date from reports.utils import format_report_date
ts// bad: two modules export formatDate; callers must remember which // src/billing/utils.ts export function formatDate(d: Date): string { ... } // src/reports/utils.ts export function formatDate(d: Date): string { ... } import { formatDate } from "../billing/utils";
ts// good: one name, one definition // src/billing/utils.ts export function formatInvoiceDate(d: Date): string { ... } // src/reports/utils.ts export function formatReportDate(d: Date): string { ... } import { formatInvoiceDate } from "../billing/utils";

The rename makes a search for the old name a finite list of call sites you can fix, and a search for the new one returns only the right callers.

Trade-offs and when a shared name is acceptable

  • Methods of different classes (Invoice.render, Report.render) are fine. The receiver carries the context, though an agent still has to know the receiver's type.
  • Interface implementations and overrides: the same name in sibling classes is the point of the pattern. Keep the shared name on the interface or base class.
  • Test helpers and fixtures named the same in separate test packages don't matter while no file imports both.
  • Public libraries: you may not be able to rename a name your users import. Add the new name, keep the old as a thin wrapper, and note the deprecation.
  • Renaming has a cost. Every caller changes, and git blame loses the history of the name. Do it when the two functions behave differently, since that is the case where a mixed-up call is a bug.
  • A prefix isn't always the answer. If the two functions do the same thing, delete one and import the other. The rename is for functions that really differ.

Enforce it

ToolSettingWhat it catchesChecked
ruffF811 redefined-while-unuseda name defined or imported again in the same scope before the first one was used (example in the docs: import foo twice)2026-10-30
pyrightreportRedeclaration (error in basic, standard and strict)a symbol with more than one type declaration2026-10-30
mypyerror code no-redefa name defined twice in one namespace; silencing it makes references resolve to the first definition2026-10-30
eslintno-shadow (typescript-eslint has an extended version)a local declaration with the name of one in an enclosing scope; it does report a parameter that shadows an import (ESLint 9.39.5: 'formatDate' is already declared in the upper scope on line 1 column 10)2026-10-30
ripgrep`rg -n "^(async )?def (\w+)" -o -r '$2' --no-filename \sort \uniq -d`function names defined more than once in a Python tree (a review aid, not a gate)2026-10-30

None of the linter pages checked describe a rule that compares function names across modules. For that, run the ripgrep line above, or a short script, in CI and review the list.

In pyproject.toml:

toml[tool.ruff.lint] extend-select = ["F811"]

Rule block for AGENTS.md / CLAUDE.md

markdown- Before adding a top-level function or exported function, search the repo for its name (`rg -n "def name\b"` / `rg -n "function name\b"`). If it exists, choose a more specific name or reuse the existing function. - When you change a function that shares its name with another definition, list the callers of each one separately and say which one was edited. - Never fix a name clash by adding a second `import` of the same name.

Edge cases

  • Aliasing to coexist: from a import format_date as format_a lets both live in one file. It works and is sometimes the only option. The cost is in AR-04.
  • Same name, same module family: a function and its async twin (fetch and fetch_async) are different names. Don't give both fetch in two files.
  • Star imports make the clash invisible, which is how CH-10 happens. See AR-01.
  • Re-exports: a barrel that re-exports formatDate from a while b also exports formatDate is the ambiguous case from AR-02.
  • Decorated or conditionally defined functions: two def lines with the same name inside if branches are one logical definition. See AR-05.

What LLMGRAPH shows

When two functions share a name, LLMGRAPH asks which one and lists the callers of each separately. A call in a file that imports both names prints maybe_more ... (open: type unknown) under both.

References

  • Python Language Reference, "The import statement" (how from binds names, as names): https://docs.python.org/3/reference/simple_stmts.html#the-import-statement
  • Ruff F811: https://docs.astral.sh/ruff/rules/redefined-while-unused/
  • Pyright configuration (reportRedeclaration): https://github.com/microsoft/pyright/blob/main/docs/configuration.md
  • Mypy error codes (no-redef): https://mypy.readthedocs.io/en/stable/error_code_list.html
  • ECMAScript spec, module environment setup (CreateImportBinding, ambiguous resolution is a SyntaxError): https://tc39.es/ecma262/multipage/ecmascript-language-scripts-and-modules.html
  • ESLint no-shadow: https://eslint.org/docs/latest/rules/no-shadow
  • typescript-eslint no-shadow: https://typescript-eslint.io/rules/no-shadow/

Changelog

  • 2026-10-30: draft 1.
  • 2026-10-30: tool checks resolved (tsc 7.0.2, eslint 9.39.5, ruff 0.17.3, mypy 2.4.1, pyright 1.1.414)
  • 2026-10-30: copy-gate wording fixes
  • AR-01 Why do star imports make my coding agent miss callers?
  • AR-04 Do import aliases confuse coding agents?

Last verified

For agentsthis page as Markdown/agent-readable/ar-03.mdllms.txt