Write natural-language Kodus rules that catch real JavaScript anti-patterns
ailintingcode-quality

Write natural-language Kodus rules that catch real JavaScript anti-patterns

DDaniel Mercer
2026-05-22
20 min read

Learn how to write Kodus rules that catch promise bugs, blocking code, eval risks, and insecure env var patterns.

If you are evaluating Kodus rules for real teams, the bar is not “can it detect style issues?” The bar is whether natural language rules can catch the JavaScript anti-patterns that actually cost you production incidents, review churn, and security debt. That means focusing on patterns like uncaught promise chains, blocking work on the event loop, unsafe eval usage, and insecure environment variable handling. In the same way teams use a rigorous checklist to evaluate a tool before adoption, as in our guide on how to evaluate quantum SDKs for real projects, you should treat Kodus rule design as an engineering discipline, not a prompt-writing trick.

The practical appeal is obvious: you can describe a code-quality policy in plain English, wire it into PR checks, and start catching classes of bugs that static linters often miss or under-specify. This becomes especially valuable when your stack spans multiple frameworks, because the same policy needs to work in React, Node.js services, Vue apps, serverless functions, and shared libraries. If your team already thinks in terms of automated guardrails and operational reliability, this is the same mindset used in SRE-style reliability stacks and in product teams that use competency checks for prompt engineering before scaling automation.

What Kodus rules are, and why natural language matters

Rules as policy, not just pattern matching

Kodus rules are most useful when you treat them as policy statements that encode engineering intent. Instead of writing a brittle regex for every possible syntax shape, you describe the behavior you want to prevent or require, then let the agent reason about code context. That matters because JavaScript anti-patterns often hide behind seemingly valid syntax: a promise chain may compile cleanly, an eval call may be tucked into a dynamic parser, and a blocking loop may only appear in a helper function that gets called from a hot path. Natural language rules let you aim at the semantic problem rather than at one exact surface form.

This is similar to how teams document operational constraints in plain language for humans and tooling alike. Good policies are readable, auditable, and testable. They help reviewers understand what the rule is trying to protect, which reduces false positives and makes exceptions easier to govern. If your team has ever reviewed a complex transformation or migration plan, the structure is comparable to a practical private cloud migration checklist: you want criteria that are specific enough to enforce, but flexible enough to survive real-world edge cases.

Why JS anti-patterns are a strong fit

JavaScript has several recurring failure modes that are ideal for policy-driven review automation. Promise handling failures lead to silent rejections and partial failures. Event-loop blocking code creates latency spikes and can take down otherwise healthy services. Unsafe dynamic execution opens obvious security risks. Insecure environment variable patterns can leak secrets into logs, repos, browser bundles, or client-visible config. These are exactly the kinds of issues that don’t always trigger a compiler error but do trigger incidents.

Because these issues are common and expensive, they are also ideal candidates for PR checks. A developer can write code that “works on my machine,” yet still introduce a production-time bomb. That’s where natural-language Kodus rules shine: they become an automated reviewer that enforces the team’s expectations before merge, not after incident response. For broader context on protecting code, identity, and business data, it helps to compare this mindset with brand-risk management when taking public positions and with articles that explain how to keep user-facing systems safe, such as how clients should think about safety when generative AI is used in legal workflows.

Designing rules that catch uncaught promise chains

What to look for in the code

The most common promise anti-pattern is not “using promises.” It is starting asynchronous work and then failing to await, return, or otherwise handle the resulting promise. In Node.js, that can mean a rejection becomes unobserved. In UI code, it can mean a user action completes before a side effect has actually happened. In tests, it can create flaky behavior that only appears when timing changes. A good Kodus rule should target promise chains that are created but not consumed, especially inside event handlers, route handlers, background jobs, and error-prone data transformations.

A useful policy sentence is: “Flag any promise-returning call whose result is neither awaited, returned, nor explicitly handled with .catch() in the current control flow.” That is far more actionable than “avoid bad promise usage.” The latter is too vague; the former tells Kodus exactly what to inspect. If your application has service-layer orchestration or async workflows, this kind of rule has the same practical value as planning for resource bottlenecks in SLA economics when memory is the bottleneck: unobserved failure paths become expensive very quickly.

Example natural-language rule

Rule: “In application code, flag any promise-based call that is not awaited, returned from the current function, or chained with explicit rejection handling. Ignore top-level fire-and-forget jobs only when they are documented with a clear comment and wrapped in a safe scheduler or queue.”

This phrasing gives you three important controls. First, it catches forgotten promises. Second, it allows legitimate async flow control. Third, it provides an explicit escape hatch for intentional background tasks. That escape hatch is important because the goal is to reduce noise, not to block engineering reality. For teams building interfaces and client workflows, this mirrors the practical tradeoffs discussed in low-processing React Native camera experiences, where you accept some complexity to keep performance and correctness in balance.

How to test and iterate it

Test the rule with a small set of seed snippets: one that clearly violates it, one that is valid, and one edge case that is intentionally ambiguous. If the rule flags the valid example, tighten the exception language. If it misses the violation, make the trigger language more explicit. In practice, you want to measure precision before recall because high false-positive rates destroy trust. One strong workflow is to add the rule to a PR branch, then run it against a representative set of historical changes to see whether it surfaces known mistakes.

When iterating, keep a change log of false positives and false negatives. This is the same discipline used in teams that validate performance or capacity changes with repeatable test plans, like the approach described in practical test plans for lagging training apps. Your rule should improve over time by learning how your codebase actually uses async patterns, not by assuming a textbook application structure.

Writing rules for blocking event-loop code

Why the event loop is a production concern

Blocking the event loop is one of the most expensive mistakes in Node.js because the runtime depends on responsiveness. A synchronous filesystem operation, a CPU-heavy loop, or large JSON parsing in the wrong place can stall unrelated requests. In a busy API, a single hot-path blocking call can produce tail-latency spikes and make the entire service feel unreliable. Developers sometimes think of this as a performance issue only, but in practice it is a reliability and scalability issue too.

This is where natural language rules outperform generic “avoid sync methods” guidance. A good rule can express context: “flag synchronous file, crypto, compression, or JSON operations inside request handlers, middleware, queue workers, and any function that processes untrusted or high-volume input.” That context matters because some synchronous operations are acceptable in scripts, build tools, or startup code. You are not trying to ban every sync call; you are trying to prevent sync work in latency-sensitive paths.

Example natural-language rule

Rule: “Flag synchronous or CPU-heavy operations in request/response paths and shared event handlers, especially *Sync filesystem APIs, large JSON.parse calls on unbounded input, and tight loops that process data without yielding. Allow exceptions only for startup scripts, tests, or explicitly annotated maintenance tasks.”

This rule is strong because it names both the operation class and the execution context. If you want to catch more subtle blocking behavior, add wording for “nested loops over large collections,” “unbounded recursion,” and “third-party utilities that internally call synchronous APIs.” Those details are useful because event-loop blocking often hides inside helper abstractions. Teams that work across environments can think of this the way they think about scheduling, capacity, and throughput in reliability programs: avoid hot-path stalls before they become visible incidents.

Practical iteration strategy

Start by running the rule against performance-sensitive parts of your codebase. Look for signal in route handlers, webhook receivers, worker consumers, and data mappers. If the rule flags harmless code, narrow the scope with context terms like “inside server handlers” or “inside functions called from HTTP routes.” If it misses obvious blocking work, add explicit examples in the rule text. Natural-language systems usually improve quickly when you give them concrete exemplars rather than abstract admonitions.

It also helps to pair the rule with benchmarks. Before and after the rule’s introduction, measure request latency, event-loop lag, or build-time regressions in a small test suite. This turns the rule from a subjective lint into an objective quality gate. For teams that care about return on tooling investment, that style of evidence is similar to the costing discipline described in a five-step ROI approach for stadium tech: if you can show the prevention value, adoption becomes much easier.

Unsafe eval usage: how to write rules that catch real security risk

Why eval is not just a style issue

eval, new Function(), string-based timers, and dynamic module execution are security-sensitive because they turn data into code. Sometimes the use is deliberate, but even “controlled” dynamic execution often becomes a future vulnerability when assumptions change. Security teams do not want a review tool that merely says “eval is bad.” They want a rule that distinguishes normal parsing from code execution and flags dangerous places where user input or remote data can reach runtime evaluation.

A strong natural-language rule should be explicit about taint and trust boundaries. It should mention untrusted input, configuration files, query parameters, and remote payloads. It should also mention equivalents like indirect string execution. This matters because attackers do not care whether you used eval directly or assembled code through an indirect function constructor. They care whether arbitrary code paths are reachable at runtime. That mindset is similar to how analysts think about trust and misinformation in trust-problem narratives: the source of the data is the security boundary.

Example natural-language rule

Rule: “Flag any use of eval, new Function(), string arguments passed to timer APIs, or dynamic imports when the input can originate from users, environment variables, network responses, or unvalidated configuration. Allow only when the code is clearly documented as a trusted internal DSL and is isolated from untrusted data.”

This rule is practical because it identifies both dangerous APIs and the data sources that make them dangerous. It also gives a narrow exception for legitimate internal DSLs, which prevents the rule from becoming an absolute ban that engineers work around. If your organization handles regulated or sensitive data, you should treat this as part of your security baseline, not merely a code-style preference. That is the same kind of careful policy design teams use when dealing with disclosure rules and transparency or with product decisions where risk must be communicated clearly.

How to keep false positives low

False positives happen when the rule sees any dynamic execution and assumes malicious intent. Reduce that noise by including examples of safe patterns: static imports, JSON parsing, schema-based configuration, and function maps keyed by enum-like constants. Also make the rule care about the data flow, not just the API name. If a value is fully internal and never influenced by input, the agent should recognize that distinction. You can reinforce that by adding language like “flag only when the executed string is constructed from external or mutable data.”

Security automation works best when it is layered. Use Kodus for review-time feedback, but keep dedicated security scanners and dependency checks in the pipeline. That layered approach mirrors the way teams combine domain-specific tools with more general governance workflows, much like how procurement and maintenance decisions are strengthened by clear aftercare policies in warranty and support evaluations or by repairability thinking in repairability-oriented buying decisions.

Insecure env var patterns: rules for secrets, config, and deployment hygiene

What insecure env var usage looks like

Environment variables are convenient, but they are also a common source of secret leakage and deployment drift. Problems include hardcoding fallback secrets in source code, logging the full environment object, exposing server-side variables in client bundles, and treating unvalidated env values as safe configuration. In modern JavaScript stacks, especially framework-based apps, a mistake in env handling can expose tokens, API keys, or internal service URLs to the browser or to build artifacts.

A good Kodus rule should therefore look for more than simply “process.env usage.” It should target unsafe defaults, client-side access to server-only variables, and debug logging that prints secrets. It should also watch for values that are interpolated into shell commands or network requests without validation. Teams often underestimate these issues because environment variables feel operational rather than application-level, but in practice they are part of your software’s trust boundary. For a broader lens on how tool choices affect long-term control and cost, see the lessons from our Kodus AI deep dive on model control and cost transparency.

Example natural-language rule

Rule: “Flag any code that logs environment variables, hardcodes secret-like fallback values, exposes server-only env vars to browser code, or uses env data in shell commands without validation and escaping. Allow only non-sensitive configuration constants and documented public prefixes for client-safe variables.”

This rule works because it aligns with how teams actually ship JavaScript applications. It recognizes that some env values are intentionally public, such as feature flags or public API base URLs, while others must remain server-side. It also catches the most common accident: a developer copies a local fallback into production code and assumes the deployment platform will override it. That assumption is exactly how leaks happen. If your organization already cares about supply-chain and packaging quality, the same discipline that informs quality and margin control in production workflows applies here: default paths should be designed for safety.

Testing the env-var rule

Build a mini fixture set with safe and unsafe examples. Safe examples should include client-safe prefixes, structured config validation, and secret loading from a dedicated vault or runtime secret manager. Unsafe examples should include console.log(process.env), API_KEY || 'dev-secret', and using an env var directly in child_process commands. Then ask Kodus to explain each decision. If the explanation is weak, the rule text probably needs more boundary language. If it is too broad, add concrete exclusions. This kind of iterative refinement is how you get from generic linting to governance-grade automation.

How to test, measure, and improve Kodus rules

Use a golden set of code samples

The fastest way to validate a natural-language rule is to create a golden set: a handful of code snippets that represent true positives, true negatives, and ambiguous edge cases. Keep them small and focused. One snippet should demonstrate the anti-pattern in the clearest possible way, while another should show the preferred safe pattern. Over time, add real snippets from your own codebase as you discover misses and false alarms. This gives you a living regression suite for rule quality.

If your team has experience with structured assessment, this should feel familiar. It is the same logic behind why great tutoring beats solo studying: a focused feedback loop improves performance faster than vague effort. In rule engineering, the “tutor” is the combination of examples, explanations, and repeated evaluation. The more concrete your examples, the faster Kodus adapts to your codebase.

Measure precision, recall, and review burden

You do not need a research lab to measure rule quality. Track three practical metrics: how often the rule catches a real issue, how often it fires on acceptable code, and how much reviewer time it saves. If a rule has high signal but noisy output, tighten the wording. If it is precise but misses too much, broaden the triggers with explicit context. A rule that never fires is not useful, even if it looks elegant in the settings panel.

Think of this like tuning a production system rather than writing a one-off prompt. You want stable behavior under realistic load, not theoretical perfection. The same commercial logic applies in other categories too, from smart shopping decisions in repair-vs-replace decisions to practical quality control in premiumized product categories: cost, signal, and lifecycle support all matter.

Iterate with PR checks and exception governance

Once a rule is reasonably accurate, move it into PR checks and define how exceptions are handled. A healthy exception process includes who can approve bypasses, what documentation is required, and when the exception expires. Without that discipline, the “temporary” escape hatch becomes permanent technical debt. Strong teams treat rules as part of code quality automation, not as optional hints.

If you are scaling this across engineering teams, start with one or two high-value rules. Prove value before expanding. That rollout strategy resembles the measured adoption advice found in content strategy guides like messaging that converts when budgets tighten: focus on the highest-intent pain points first, then expand once stakeholders trust the system.

The four rules to deploy first

If you want a practical starting point, begin with four rules: unhandled promises, blocking event-loop code, unsafe eval usage, and insecure env var patterns. These four map directly to reliability, performance, and security risk. They are easy to explain to reviewers, easy to test with examples, and broad enough to catch meaningful bugs without requiring deep domain-specific configuration. For many teams, this covers the majority of avoidable JavaScript review mistakes in the first pass.

Here is a concise version you can adapt:

  • Unhandled promises: flag promise-returning calls that are not awaited, returned, or explicitly caught.
  • Blocking event loop: flag sync or CPU-heavy work in request paths and handlers.
  • Unsafe eval: flag any dynamic code execution from external or mutable data.
  • Insecure env vars: flag secret leakage, unsafe fallbacks, and client exposure of server-only config.

These rules also pair well with broader review automation. If you are building a review workflow, it is worth studying how teams structure repeatable editorial or operational formats in pieces like replicable interview formats or data-driven brief workflows. The underlying principle is the same: format creates consistency, and consistency creates quality.

What to expand next

After the starter pack proves itself, add rules for unvalidated JSON parsing, dangerous RegExp backtracking, insecure deserialization patterns, dependency pinning, and missing error boundaries in async flows. At that point, Kodus becomes more than a reviewer; it becomes an embedded policy engine for your codebase. That is where natural-language rules become especially valuable, because the team can read, debate, and refine policy without learning a new DSL for every change. The result is faster adoption and better long-term maintenance.

Pro Tip: The best Kodus rules are written like engineering policies, not like generic AI instructions. Name the risk, name the context, specify the exception, and include a safe example in your test set.

Comparison table: good vs weak natural-language rules

Anti-patternWeak ruleStrong Kodus ruleWhy it works
Uncaught promise chains“Watch for async bugs.”“Flag promise-returning calls that are not awaited, returned, or explicitly caught.”Targets the exact failure mode.
Blocking event loop“Avoid slow code.”“Flag sync or CPU-heavy work in request handlers and hot paths.”Combines operation and context.
Unsafe eval“Don’t use eval.”“Flag eval, Function constructors, and string timers when influenced by external or mutable data.”Focuses on taint and execution risk.
Insecure env vars“Be careful with env.”“Flag secret logging, hardcoded fallback secrets, and server-only env exposure in browser code.”Catches real leakage patterns.
False positives“Ban dynamic code.”“Allow documented internal DSLs isolated from untrusted input.”Creates controlled exceptions.

Rollout playbook for teams using Kodus rules in PR checks

Phase 1: define policy ownership

Assign rule ownership to a small group of senior engineers or platform/security stakeholders. That group should be responsible for initial authoring, example curation, and exception policy. Without ownership, rule sets grow inconsistently and trust collapses. Policy ownership also makes it easier to connect the rule set to broader engineering standards, which is essential if you want the automation to scale across multiple repos and frameworks.

Phase 2: run on historical pull requests

Before enforcing a rule on new code, run it against historical PRs and incident-linked commits. That gives you a realistic estimate of whether the rule would have prevented known problems. It also gives the team concrete examples to discuss, which makes tuning much easier. This is the most efficient way to build credibility because it anchors the rule in real code rather than abstract best practice.

Phase 3: enforce softly, then harden

Start with informational comments or non-blocking PR checks. Once the false-positive rate is acceptable and the team understands the rule, move it to blocking status for new changes. This staged rollout avoids surprise and gives developers a chance to adapt. For cross-functional tooling programs, this is the same adoption logic used in high-trust, high-feedback environments across product and operations.

FAQ and decision guidance

How specific should a natural-language Kodus rule be?

Specific enough to name the risky behavior, the context where it matters, and the exception path. If a rule can be interpreted in five different ways, it is probably too vague for enforcement.

Can Kodus replace ESLint or security scanners?

No. It should complement them. ESLint is great for syntax-level and style-level checks, while Kodus is better suited for policy-driven review and context-sensitive patterns. Security scanners still matter for dependency and secret detection.

What is the best first rule to add?

Unhandled promises are usually the fastest win because they are common, easy to explain, and often cause real bugs. Blocking event-loop code is a close second for Node.js services.

How do I reduce false positives?

Add explicit examples, narrow the execution context, and document exceptions. If possible, test the rule against historical code and revise the wording until the signal is strong enough for PR enforcement.

Should rules be written by developers or security teams?

Both. Developers understand the code paths and normal patterns, while security or platform teams can define risk boundaries and exception policy. The best rules come from collaboration.

How many rules should we start with?

Start with a small, high-value set of four to six rules. That keeps review noise manageable and makes it easier to prove value before expanding coverage.

Final takeaway: make the rules read like production policy

Natural-language Kodus rules are most effective when they behave like explicit engineering policy: concrete, contextual, and testable. If you can describe the anti-pattern in one sentence, provide one unsafe example, one safe example, and define a clear exception path, you are close to a rule that will survive real usage. The four most valuable starters for JavaScript teams are still uncaught promise chains, blocking event-loop code, unsafe eval usage, and insecure env var patterns. Those rules address reliability, performance, and security in a way that developers can actually understand and accept.

As you refine the rule set, think less about “prompting the AI” and more about building a small governance system for code quality automation. That shift in mindset is what turns review automation into measurable engineering leverage. If you want to continue building that capability, revisit our broader guidance on Kodus AI, compare your rollout plan with structured tool evaluation, and keep tightening the policy until the rules catch the bugs your team actually ships.

Related Topics

#ai#linting#code-quality
D

Daniel Mercer

Senior SEO Content Strategist

Senior editor and content strategist. Writing about technology, design, and the future of digital media. Follow along for deep dives into the industry's moving parts.

2026-05-24T22:48:41.522Z