Skip to content

Every name a cold agent reads must convey its purpose without opening the file — because queryRequest tells an agent nothing, and FeaturePlanRequest tells it everything.

Principle

A Priori Friendly Naming

The test

Can the agent decide from the grep result alone?

agent $ grep -rn "def " src/

$rg "def " src/notion/

tags.py:12def process(data):must open file

tags.py:47def handle(item):must open file

tags.py:12def normalize_notion_task_tags(raw: dict):grep is enough

tags.py:47def dedupe_task_tags_case_insensitive(tags: list):grep is enough

A name is a prediction about what the body does — when the prediction is missing, the agent pays a roundtrip to read the body.

The violations

Generic becomes specific, or the name isn't doing its job.

Each row is a real violation. Left — zero signal. Right — full signal.

queryRequest→FeaturePlanRequest

process(data)→normalize_notion_task_tags(raw_tags)

Record<string, any>→interface FeaturePlanResponse

class Manager→class NotionTaskManager

raw dict payload→class NotionTaskTags(BaseModel)

If the name could plausibly belong to a different file, you haven't named it — you've placeholder'd it.

The scope

This is a code-construct rule — not a filename rule.

Governed

Apply a priori naming

  • Function & method names
  • Class names
  • Type aliases & interfaces
  • Pydantic model names
  • Module-scope variables

The things agents grep for and read in signatures.

Out of scope

Different rulebook

  • Filenames → Architecture is Agent Performance
  • HTML elements & CSS classes
  • Config keys → governed by schema

Named constructs live in signatures; filenames live in layouts.

Don't over-apply — and don't under-apply. The rule binds exactly where a cold agent reads the name before the body.

What named types buy you

A traceable flow across files, without a mental model.

One named type. Three sites. Grep stitches them into a story.

Created

FeaturePlanRequest

planner.py — builds the request

Transformed

FeaturePlanRequest

validator.py — adds constraints

Consumed

FeaturePlanRequest

executor.py — runs the plan

Record<string, any> — opaque, no breadcrumb, the agent must read every usage to trace the flow.

Named types are how agents navigate across file boundaries without loading the whole codebase into context.

The compounding cost

At one file it's noise. At a codebase it's a tax.

A codebase with 1,000 constructs. An agent invocation that touches 50 of them.

Violated — generic names

construct touches50

must open to infer50

tokens per open~800

orientation tax~40k tokens

Respected — dense names

construct touches50

must open to infer~3

tokens per open~800

orientation tax~2k tokens

Every agent invocation pays this tax on every construct it encounters — compounded across every call in the system's life.

The discipline

A name is a promise to a stranger — not a reminder to yourself.

Before you commit a name, ask: could a cold agent, reading this in a grep result with no other context, predict what it does? If not, rename it. The tax compounds on every invocation forever.