Skip to main content
New aislop v0.9.3: rule-precision release. Fewer false positives across docs, imports, eval, wrappers, JSON-LD, and bundled files. Read more →
← Blog
Engineering · 6 min read · reads

If your function needs 80 lines, your agent gave up. If your file needs 400, it never started.

Is there a golden rule for function size or file size? Not really. Some teams say 50 lines. Some say 100. Some do not check. Here is what we landed on after 25 real projects, and why your agent does not feel the pain that used to keep files small.

The largest single file we flagged across 25 real projects was OnboardingSvgIllustration.tsx. 981 lines. One React component. All in the default export. An agent had been asked to inline an SVG illustration. It chose to render it as JSX, expanded every path element, named nothing, and stopped. Nobody had reviewed it because nobody was going to scroll a 981-line file at PR time.

aislop size limits, after 25 projects:

  • 80 lines per function
  • 400 lines per file
  • 800 lines for JSX and TSX
  • 10% soft tolerance

Is there a golden rule for function size or file size? Not really. Ask ten engineers and you will get ten answers. Some teams say 50 lines. Some say 100. Some do not check at all and trust the agent. That used to be fine because the human writing the code felt the pain of a file getting too big. The agent does not feel that pain. The numbers above are not sacred. They exist because somewhere in your repo there is a file nobody admits exists, and the numbers are what catch it.

The 981-line component is the extreme. The class of problem is everywhere. MediumWidget in SYMSavingsWidget.tsx. 171 lines for a single React component rendering three unrelated sub-views and doing its own data fetching. generate_seed_data. 176 lines in one Python function producing fixtures for six different models. useSessionMigration at 94 lines. useStoreReview at 99 lines. Both React hooks that should have been three hooks each. services/auth/authService.ts at 552 lines. utils/sharedStyles.ts at 492 lines. Every one of them written by an agent. Every one of them shipped.

The two limits, the two rules

aislop ships two complexity rules for size, both with a 10% soft tolerance so a single line over does not tank the score.

RuleApplies toHard limitWarn at
complexity/function-too-longfunctions80 lines88
complexity/file-too-largefiles400 lines440
complexity/file-too-large.jsx / .tsx800 lines880

Function and file are different limits because they fail in different ways. A long function fails on logic. You cannot hold the local state in your head, the branches multiply, the bug rate climbs. A long file fails on orientation. You cannot find anything, the imports lie about the file's responsibilities, and the next change goes in the wrong place because the right place was buried at line 820. The 10% tolerance is deliberate. 81 lines over an 80-line cap should not fail the score. An agent split that hits 88 and one that hits 91 are functionally the same outcome. 89 over 80 is where it stops being a rounding case and starts being a refusal to split.

Why 80 and 400

Both numbers are working-memory arguments dressed as limits. 80 lines is roughly what fits on a 16-inch laptop screen at a comfortable font size. A function you can hold on one screen is a function you can reason about without scrolling, without losing the local variable in line 12 by the time you are reading line 55. Above 80 the scrolling starts. Above 120 the scrolling becomes the work.

400 lines is roughly what a human can orient inside without a table of contents. You open the file, skim the imports, skim the exports, skim the top-level declarations, and you have a mental map. Above 400 you start needing search. Above 800 you start needing search to find what you were searching for.

JSX and TSX get double. 800 lines, soft cap 880. Component files carry a lot of declarative markup that does not load the same cognitive register as logic. A 600-line component that is 400 lines of tags and 200 lines of handlers reads more like a 200-line file. We let the limit reflect that and trust the function rule to catch the actual logic blowups.

Why agents don't feel the pain

A human writing a function starts to suffer around 80 lines. Not because anyone told them to suffer. Working memory is finite and exceeding it hurts in real time. You scroll up to remember what parsed meant. Scroll back. Lose your place. Try to hold the shape of three nested branches at once. Fail. The pain is the prompt to extract.

An agent does not have that pressure. The whole function fits in the context window. Line 10 and line 400 are equally accessible at generation time. The agent reasons about both at once, with no scrolling cost, no working-memory burden, no felt urgency to split. The motivation to extract is gone because the pain that motivates extraction is gone.

This would be fine if the next reader were also an agent with infinite context. But one of three things is always true. A human will eventually modify the function. A human will eventually debug the function. A human will eventually review the diff. All three still have working memory. The function is still 981 lines.

What aislop does about it

Detection is straightforward. The size engine counts AST nodes per function and lines per file, applies the threshold, applies the 10% tolerance, and emits two rule IDs. complexity/function-too-long and complexity/file-too-large. They show up in the scan with a file path, a line range, and a delta over the cap.

Auto-fix does not touch them. A 200-line function can be split four different ways and three of them change the semantics. Same with files. Splitting a 600-line file can move imports, change cyclic dependencies, and surface circular references that were previously masked. aislop fix only does rewrites we can guarantee are safe, and splitting is not on that list.

What aislop ships instead is the agent handoff. aislop fix --claude (or --codex, --cursor, --gemini, and the rest) hands the size violations to a coding agent with the rule, the file location, and enough context to do the refactor. The agent splits. The deterministic engine re-checks. The human reviews the diff. The deterministic tool measures, the agent transforms, the human approves. That is the only division of labor that scales.

A class of smell agents can't smell

Every code smell that depends on feeling tired is invisible to an agent. File too big. Function too long. Name too generic. Repetition too obvious. The agent never gets tired. The tool has to measure what the agent cannot feel, and the rules have to be specific enough that the measurement is unambiguous.

80 for a function. 400 for a file. 800 for JSX. 10% tolerance. Two rule IDs. One OnboardingSvgIllustration.tsx that nobody scrolled and the linter caught on the first scan. If your function is more than 80 lines, your agent is doing something wrong. If your file is more than 400, same story. The pain that kept humans honest is gone. The number does the keeping now.

Find the 981-line file in your own repo

$ npx aislop scan

Run it. You will see the file nobody admits exists. Star the AI Slop CLI on GitHub if you want the next release in your feed.