<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Viktor</title>
    <description>The latest articles on DEV Community by Viktor (@viktor123).</description>
    <link>https://dev.to/viktor123</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3901094%2Fee5a3d0c-c4fa-4ef0-ae83-8ee1a35cf8fd.jpg</url>
      <title>DEV Community: Viktor</title>
      <link>https://dev.to/viktor123</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/viktor123"/>
    <language>en</language>
    <item>
      <title>How to survive as a developer without AI code-gen and without autocomplete</title>
      <dc:creator>Viktor</dc:creator>
      <pubDate>Mon, 27 Apr 2026 19:35:10 +0000</pubDate>
      <link>https://dev.to/viktor123/how-to-survive-as-a-developer-without-ai-code-gen-and-without-autocomplete-6k2</link>
      <guid>https://dev.to/viktor123/how-to-survive-as-a-developer-without-ai-code-gen-and-without-autocomplete-6k2</guid>
      <description>&lt;h1&gt;
  
  
  How to survive as a developer without AI code-gen and without autocomplete
&lt;/h1&gt;

&lt;p&gt;Hey everyone! My name is Viktor, I'm a senior backend dev at an online store, working on the logistics team.&lt;/p&gt;

&lt;p&gt;Today I'll tell you how I survive as a developer surrounded by vibe-coders, code-writing agents, and a legacy project. I'll also talk about how I use LLMs and my experience with neural nets, etc&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I've been using AI tools since 2019 (tabnine → cursor → newer stuff), but consciously chose to write code by hand. For self-development, deeper project understanding, etc&lt;/li&gt;
&lt;li&gt;For a 13-year-old legacy project, AI code-gen hallucinates and breaks conventions. AI for &lt;strong&gt;review&lt;/strong&gt; is a different story — works great&lt;/li&gt;
&lt;li&gt;I built 1 orchestrator + 7 specialized subagents (logic, style, security, perf-db, ops, ai-smell, tests) running in parallel on the diff vs master&lt;/li&gt;
&lt;li&gt;The AI-smell agent specifically catches vibe-coded PRs from teammates AND my own tired-eyes mistakes — both end up in the same noise&lt;/li&gt;
&lt;li&gt;All of it is just &lt;code&gt;.claude/agents/*.md&lt;/code&gt; markdown files — copy-pasteable to any project. Setup details + gotchas at the bottom&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Why I don't write code with AI
&lt;/h1&gt;

&lt;p&gt;Real quick — I'm not someone who just opened AI tools yesterday. Since 2019 I've been using tabnine, then moved to cursor, then looked at newer stuff. So my choice to write code by hand — it's not from being clueless, it's a conscious one, for self-development, deeper project understanding, etc.&lt;/p&gt;

&lt;p&gt;Main problem — it's a project that's over 13 years old: code is written inconsistently, functions, classes and variables are used not as intended, other logic is wired into them, or they just sit around as dead weight tagged &lt;code&gt;TODO&lt;/code&gt; or &lt;code&gt;FIXME&lt;/code&gt;. Because of all this combined with a huge codebase, right now we're ripping out domain logic, but for now we live in this world :). When working with such a project, AI models hallucinate, generate inconsistent code, and often just get it wrong.&lt;/p&gt;

&lt;p&gt;Also important to mention — devs in our org are tightly bound to their domain, so part of the analytical work, onboarding managers and analysts, writing docs — all of it requires really deep understanding of the project's code. This is what lets you efficiently research tasks, work with incidents, and predict timelines for new tasks and requirements.&lt;/p&gt;

&lt;h1&gt;
  
  
  What I use AI for
&lt;/h1&gt;

&lt;p&gt;The main thing I use for working with code — that's code quality tools: ruff, mypy, writing tests via pytest, and now also AI for detailed review on the project. I built a set of agents — 1 orchestrator and 7 subagents — working in different directions: security check, algorithm logic check, code style check, autotests check, code organization and bloat check, devops check, and DB check. I'll briefly describe each one.&lt;/p&gt;

&lt;p&gt;Here's what the final report from the orchestrator looks like (anonymized example, real findings from one PR):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ID&lt;/th&gt;
&lt;th&gt;Sev&lt;/th&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;File:line&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;BLOCKER&lt;/td&gt;
&lt;td&gt;Logic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;payments/insurance.py:355&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;MIN_INSURANCE_COST = 1&lt;/code&gt; set in main currency, but provider works in cents → insurance is 100× lower than expected&lt;/td&gt;
&lt;td&gt;Set to &lt;code&gt;100&lt;/code&gt;, comment &lt;code&gt;# in cents&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;BLOCKER&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;scripts/executor.py:57&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;exec()&lt;/code&gt; with full &lt;code&gt;__builtins__&lt;/code&gt;, only protected by &lt;code&gt;IS_PRODUCTION&lt;/code&gt; flag — any prod misconfig = full RCE&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;RestrictedPython&lt;/code&gt; or subprocess + seccomp&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;BLOCKER&lt;/td&gt;
&lt;td&gt;Migration&lt;/td&gt;
&lt;td&gt;&lt;code&gt;orders/migrations/0021_add_entity.py&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AddField(entity, FK, default=None)&lt;/code&gt; without &lt;code&gt;null=True&lt;/code&gt; — will crash on a non-empty table at deploy&lt;/td&gt;
&lt;td&gt;Two-step: &lt;code&gt;null=True&lt;/code&gt; + backfill in a separate migration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;H1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;Logic/Types&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/config.py:130&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;list[int]&lt;/code&gt; for whitelist, but &lt;code&gt;provider_item.id&lt;/code&gt; is &lt;code&gt;str&lt;/code&gt; → &lt;code&gt;str in list[int]&lt;/code&gt; always &lt;code&gt;False&lt;/code&gt; → feature is fully dead&lt;/td&gt;
&lt;td&gt;Replace with &lt;code&gt;list[str]&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;H2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;Logic/Ops&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/service.py:102&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fail-open on empty whitelist: &lt;code&gt;all(x in [] for x in set())&lt;/code&gt; is &lt;code&gt;True&lt;/code&gt; → gate inverted, releases everything when supposed to release nothing&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;if whitelist and not providers: return False&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;H3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;Perf-DB&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/service.py:102&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@cached_property&lt;/code&gt; reads two OneToOne (not in &lt;code&gt;select_related&lt;/code&gt;) + ORM fallback → up to 3 SQL per item, called twice per order in serializer (hot path &lt;code&gt;GET /orders/&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;select_related('outlet', 'delivery_info', 'ppo_info')&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;H4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;&lt;code&gt;payments/processor.py:172&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full payload (name, phone, email, items) logged on every request — PII leak into log storage&lt;/td&gt;
&lt;td&gt;Mask PII or log only &lt;code&gt;payment_id + amount + status&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;H5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;HIGH&lt;/td&gt;
&lt;td&gt;AI-smell&lt;/td&gt;
&lt;td&gt;&lt;code&gt;utils/helpers.py:42&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;from utils.misc import flatten&lt;/code&gt; — module/symbol does not exist in project, hallucinated import&lt;/td&gt;
&lt;td&gt;&lt;code&gt;list(itertools.chain.from_iterable(items))&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;M1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/tests/test_x.py:260&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Magic number &lt;code&gt;expected_insurance_sum = 1&lt;/code&gt; — should reference &lt;code&gt;Conf.MIN_INSURANCE_COST&lt;/code&gt; so test breaks on constant change&lt;/td&gt;
&lt;td&gt;&lt;code&gt;expected_insurance_sum = Conf.MIN_INSURANCE_COST&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;M2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MEDIUM&lt;/td&gt;
&lt;td&gt;Logging&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/service.py:101&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;New rejection branch is not logged — can't distinguish «provider not in whitelist» from «provider_item=None» during incidents&lt;/td&gt;
&lt;td&gt;&lt;code&gt;log_info('feature.provider_not_allowed', extra={...})&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Verdict: &lt;strong&gt;NEEDS WORK&lt;/strong&gt; — 3 Blockers must be fixed before merge.&lt;/p&gt;

&lt;p&gt;Each finding has author + sha (from &lt;code&gt;git blame&lt;/code&gt;) and a &lt;code&gt;Verify by:&lt;/code&gt; command, but I've trimmed those columns so the table fits. Now to the agents themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Style agent
&lt;/h2&gt;

&lt;p&gt;This agent looks at what a regular linter doesn't catch. Ruff already flags unused imports, line length, quotes, and PEP8 naming — that's routine, automation handles it just fine. So in the prompt for the style agent I write directly: "don't duplicate ruff". Its job is semantics. For example, function name &lt;code&gt;process_data&lt;/code&gt; says nothing to the reader, but &lt;code&gt;apply_discount&lt;/code&gt; does. Or a function called &lt;code&gt;get_user&lt;/code&gt; that also updates the record inside — that's already a trap. Or a boolean flag named &lt;code&gt;flag&lt;/code&gt; instead of &lt;code&gt;is_bulk&lt;/code&gt; or &lt;code&gt;should_retry&lt;/code&gt;. Or a variable without units in the name where it actually matters — &lt;code&gt;price&lt;/code&gt; instead of &lt;code&gt;price_kopecks&lt;/code&gt;, &lt;code&gt;timeout&lt;/code&gt; instead of &lt;code&gt;timeout_ms&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Besides naming, the agent looks at signatures (5+ positional args, mutable default), duplicated logic, functions over 40 lines, and just inconsistency with how the rest of the project is built. And separately — systemic patterns: if the same mistake appears in 5 places, it's not 5 findings, it's one with the note "this is what's all over your diff".&lt;/p&gt;

&lt;h2&gt;
  
  
  Logic agent
&lt;/h2&gt;

&lt;p&gt;The most important agent in the "don't deploy a bug" category. Focus — runtime correctness: types, algorithms, async, datetime/Decimal, error handling. Specific patterns that come up regularly in any project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Truthy traps: &lt;code&gt;value or default&lt;/code&gt; triggers on &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;""&lt;/code&gt;, &lt;code&gt;[]&lt;/code&gt;, &lt;code&gt;Decimal('0.00')&lt;/code&gt; — but you were waiting for "if None"&lt;/li&gt;
&lt;li&gt;Naive vs aware datetime, comparing datetime in different timezones&lt;/li&gt;
&lt;li&gt;Decimal rounding in the wrong place, or mixing &lt;code&gt;Decimal + float&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Missed &lt;code&gt;await&lt;/code&gt;, blocking &lt;code&gt;requests.get&lt;/code&gt; inside async-view, sequential &lt;code&gt;await&lt;/code&gt; where &lt;code&gt;gather&lt;/code&gt; is begging&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;except Exception: pass&lt;/code&gt; — silent error swallowing&lt;/li&gt;
&lt;li&gt;Off-by-one, inverted &lt;code&gt;if&lt;/code&gt;, changing function semantics without migrating tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each finding must contain a line, a concrete scenario, and &lt;code&gt;Verify by:&lt;/code&gt; — i.e. a command or test you can verify it with. Without that, the agent is forbidden to write "maybe there's a bug here" — otherwise it starts hallucinating and making noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security agent
&lt;/h2&gt;

&lt;p&gt;Standard OWASP plus a couple of modern things. From the classics — SQL/Command/Template injections, secrets in code or logs, SSRF (external HTTP without allowlist and timeouts), path traversal on &lt;code&gt;open(user_input)&lt;/code&gt;, unsafe deserialization (pickle, yaml without SafeLoader, eval), missed &lt;code&gt;@login_required&lt;/code&gt;/&lt;code&gt;permission_classes&lt;/code&gt;, IDOR.&lt;/p&gt;

&lt;p&gt;From the less obvious but very painful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DB-Lock-DoS on migrations&lt;/strong&gt; — separate category. &lt;code&gt;ALTER TABLE ADD COLUMN&lt;/code&gt; with volatile DEFAULT (&lt;code&gt;now()&lt;/code&gt;, &lt;code&gt;gen_random_uuid()&lt;/code&gt;), &lt;code&gt;CREATE INDEX&lt;/code&gt; without &lt;code&gt;CONCURRENTLY&lt;/code&gt;, &lt;code&gt;SET NOT NULL&lt;/code&gt; without two-step schema (&lt;code&gt;NOT VALID&lt;/code&gt; + &lt;code&gt;VALIDATE&lt;/code&gt;), DDL without &lt;code&gt;lock_timeout&lt;/code&gt;. It's not a "vulnerability" in the classic sense, but takes down prod just as well as SQL injection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supply-chain&lt;/strong&gt; — typosquatting in new dependencies (&lt;code&gt;reqeusts&lt;/code&gt; vs &lt;code&gt;requests&lt;/code&gt;), pins on pre-release versions, downgrade of a library with a security patch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LLM-specific&lt;/strong&gt; — if the code builds prompts for a neural net, we check prompt injection (user input straight into prompt), secret leaks via logged prompts, using LLM output as SQL/shell without validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important detail: the agent checks &lt;strong&gt;reachability&lt;/strong&gt;. If a dangerous pattern sits in test code or a dev script that's not reachable from outside — it's either Low or not a finding at all. Otherwise you get a flood of false positives and people stop using it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance and DB agent
&lt;/h2&gt;

&lt;p&gt;Everything that shows up under load. Algorithmic complexity (O(n²) where &lt;code&gt;set&lt;/code&gt; for lookup is begging), memory (loading a full dataset into RAM instead of streaming), async (blocking I/O in async, no timeouts and retry, unlimited &lt;code&gt;gather&lt;/code&gt; on a thousand tasks), but the main thing — &lt;strong&gt;DB and ORM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;N+1 — top-1 problem of legacy projects. Query in a loop, no &lt;code&gt;select_related&lt;/code&gt;/&lt;code&gt;prefetch_related&lt;/code&gt;, &lt;code&gt;SerializerMethodField&lt;/code&gt; without prefetch. Then — query quality: &lt;code&gt;WHERE LOWER(email) = ...&lt;/code&gt; kills the index, &lt;code&gt;LIKE '%pattern'&lt;/code&gt; too, &lt;code&gt;JSONB&lt;/code&gt; filters without GIN-index, &lt;code&gt;COUNT(*)&lt;/code&gt; on a big table (&lt;code&gt;EXISTS&lt;/code&gt; is faster), &lt;code&gt;SELECT *&lt;/code&gt; where &lt;code&gt;.only()&lt;/code&gt; would do. Transactions — long transactions with external I/O inside, &lt;code&gt;SELECT FOR UPDATE&lt;/code&gt; without &lt;code&gt;SKIP LOCKED&lt;/code&gt;. And cache — cache key without user/tenant (data leak between users), no TTL, cache stampede.&lt;/p&gt;

&lt;p&gt;Each finding contains &lt;code&gt;Hot path: Yes/No/Unknown&lt;/code&gt; — because N+1 in an endpoint pulled once a month and N+1 in hot-path are different priorities. If the agent couldn't tell — it writes Unknown, doesn't guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ops and compatibility agent
&lt;/h2&gt;

&lt;p&gt;What will break the deploy or monitoring, or breaks backward compatibility. New required env without default — breaks pod startup. &lt;code&gt;NOT NULL&lt;/code&gt; without DEFAULT in migration — breaks zero-downtime deploy. Dropping a column without two-step deploy — old pods crash. Changing Celery task signature without fan-out migration — old workers start failing. Changing Kafka message schema — consumers on the old schema break.&lt;/p&gt;

&lt;p&gt;Separately — &lt;strong&gt;observability&lt;/strong&gt;. Important new logic without logs, wrong level (&lt;code&gt;debug&lt;/code&gt; for critical, &lt;code&gt;error&lt;/code&gt; for normal branches), no metrics and span on a new external call, no structured logging where the project already uses it. And &lt;strong&gt;feature flags&lt;/strong&gt; — is there a way to turn the feature off without a release, is there a rollback plan.&lt;/p&gt;

&lt;p&gt;In each finding the agent writes &lt;code&gt;Deploy risk:&lt;/code&gt; (what and when will break — at deploy / in prod / over time) and &lt;code&gt;Rollback:&lt;/code&gt; (is there a rollback plan). This turns the review into a checklist for the deploy conversation, instead of an abstract "maybe something will happen".&lt;/p&gt;

&lt;h2&gt;
  
  
  AI-smell agent
&lt;/h2&gt;

&lt;p&gt;The most "socially useful" agent in 2026, when a significant part of PRs are AI-assisted. I use this review to run other devs' code through too — it might be vibe-coded partially or fully, and without this filter a lot of garbage lands in master. Plus, it catches my own tired-eyes mistakes: when you sit on a task all day, things like &lt;code&gt;try/except: pass&lt;/code&gt;, a forgotten &lt;code&gt;print&lt;/code&gt;, an extra helper or a commented-out block "I'll delete it later" — you just stop noticing them. The agent is a fresh look.&lt;/p&gt;

&lt;p&gt;Its job is to bring the code back to the minimum-needed solution. What it catches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hallucinations&lt;/strong&gt; — import of a non-existent module/function, calling a method with a non-existent name, reference to a missing attribute, &lt;code&gt;settings.XXXXX&lt;/code&gt; for a key not in config. Verified via grep on the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Over-engineering&lt;/strong&gt; — &lt;code&gt;class Helper&lt;/code&gt;/&lt;code&gt;Manager&lt;/code&gt;/&lt;code&gt;Factory&lt;/code&gt; for a one-function task, ABC/Protocol with a single implementation, generic with one type-param, decorator for one-off use, DI where an import is enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defensive noise&lt;/strong&gt; — &lt;code&gt;if x is not None&lt;/code&gt; right after &lt;code&gt;x = get_x()&lt;/code&gt; returning &lt;code&gt;X&lt;/code&gt;, &lt;code&gt;try/except: pass&lt;/code&gt; for no reason, isinstance on internal data, validating already-validated-by-serializer inputs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Noisy docstrings&lt;/strong&gt; — literal repetition of the signature, multiline docstrings on a one-line function, &lt;code&gt;# increment counter&lt;/code&gt; before &lt;code&gt;counter += 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dead code from refactors&lt;/strong&gt; — private function with no callers, commented-out blocks "just in case", a function param no longer used inside, an &lt;code&gt;if/else&lt;/code&gt; with the same code in both branches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Duplication&lt;/strong&gt; — new helper that already exists (found via grep), reinvented &lt;code&gt;flatten&lt;/code&gt;/&lt;code&gt;chunked&lt;/code&gt;/&lt;code&gt;lru_cache&lt;/code&gt; from stdlib.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-tells&lt;/strong&gt; — overly "schoolbook" naming (&lt;code&gt;calculate_total_price_with_discount&lt;/code&gt; when the project uses &lt;code&gt;calc_total&lt;/code&gt;), emoji in logs where there's none anywhere else, "Successfully completed..." logs, overly polite error messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Main rule of the agent: "would removing this make the code worse? If no — it's noise."&lt;/p&gt;

&lt;h2&gt;
  
  
  Test agent
&lt;/h2&gt;

&lt;p&gt;Optional — only works if docker-stack is up. Never runs the full suite (that's hours), instead does three things: finds tests relevant to the diff, runs them in parallel, calculates differential coverage on changed lines.&lt;/p&gt;

&lt;p&gt;Relevance is calculated four ways at once: by directory structure (&lt;code&gt;app/module.py&lt;/code&gt; → &lt;code&gt;app/tests/test_module.py&lt;/code&gt;), by imports (grep for &lt;code&gt;from .module import&lt;/code&gt;), by function/class name in tests (grep for the symbol), and the test files in the diff itself. Then — dedup, limit to 20 files, and &lt;code&gt;pytest --lf -n auto -x&lt;/code&gt; (last-failed first, parallel by cores, stop on first failure).&lt;/p&gt;

&lt;p&gt;Differential coverage — the most useful part. We take &lt;code&gt;coverage json&lt;/code&gt;, compare &lt;code&gt;executed_lines&lt;/code&gt; against changed lines from diff, calculate the percentage. If less than 50% — High. This is way more honest than overall project coverage: it might be 80%, but the actual new code has zero tests.&lt;/p&gt;

&lt;p&gt;If docker isn't available — status &lt;code&gt;SKIPPED&lt;/code&gt;, the agent still returns a list of tests for manual run. It's not an error, it's a normal mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Orchestrator
&lt;/h2&gt;

&lt;p&gt;The conductor that ties everything together. Here there's an architectural limit of Claude Code SDK: a subagent can't spawn other subagents. So the orchestrator isn't a separate subagent, it's a playbook the main agent reads in its main context and follows itself.&lt;/p&gt;

&lt;p&gt;Five steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Diff collection&lt;/strong&gt; — &lt;code&gt;git diff --merge-base origin/master HEAD&lt;/code&gt;, stats, list of files, commits. Saved to /tmp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-analysis&lt;/strong&gt; — deterministic checks before subagents: ruff with auto-fix, search for migrations and dependencies in diff, regex-scan for hardcoded secrets. This reduces LLM load and hallucinations — concrete bugs are caught by regex, agents handle what regex can't catch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blame&lt;/strong&gt; — for each added line we run &lt;code&gt;git blame -L&lt;/code&gt;, build &lt;code&gt;file:line → author + sha&lt;/code&gt;. This block then goes into the final table — next to each finding you see whose code it is. Very useful for the PR-review conversation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel dispatch&lt;/strong&gt; — main agent &lt;strong&gt;in one message&lt;/strong&gt; launches all 6 (or 7 with tests) subagents through the Agent tool. This is critical — only this way they run in parallel, not sequentially.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report synthesis&lt;/strong&gt; — parse agents' responses, dedupe by key &lt;code&gt;(file, line, category)&lt;/code&gt; (same file+lines in multiple agents = one row in the table, "Aspect" column has all agents through slash), prioritize Blocker → High → Medium → Low, format the final markdown table with verdict READY TO MERGE / NEEDS ATTENTION / NEEDS WORK.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Implementation gotchas I tripped on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Artifacts go into the prompt as text, not as a &lt;code&gt;/tmp&lt;/code&gt; path&lt;/strong&gt;. Subagents kept hanging on &lt;code&gt;cat /tmp/review_diff.patch&lt;/code&gt; — turns out, in some runtimes their &lt;code&gt;/tmp&lt;/code&gt; and the main agent's &lt;code&gt;/tmp&lt;/code&gt; are different. Solution: paste the diff straight into the prompt between &lt;code&gt;=== DIFF === ... === END DIFF ===&lt;/code&gt;. ~20 KB limit per artifact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short-circuit for trivial diffs&lt;/strong&gt; — under 20 lines, only .md/docs, no .py/.sql/migrations → skip the parallel run, return minimal report. Saves tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relative paths only&lt;/strong&gt; (&lt;code&gt;server/path/file.py:LINE&lt;/code&gt;, not &lt;code&gt;/Users/...&lt;/code&gt;) — IDE links don't click otherwise, and sharing with colleagues breaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence per finding&lt;/strong&gt; (High/Med/Low). Low = agent isn't sure, check by hand. More honest than making it stay silent on suspicions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Verify by:&lt;/code&gt; per finding&lt;/strong&gt; — a concrete command. Stops the agent from writing abstract "maybe there's a problem here".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dedup by &lt;code&gt;(file, line_range, category)&lt;/code&gt;&lt;/strong&gt; — otherwise one bug gets reported 3× by three agents and the review becomes unreadable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How to integrate agents at your place
&lt;/h1&gt;

&lt;p&gt;All agents live in &lt;code&gt;.claude/agents/*.md&lt;/code&gt;, skills — in &lt;code&gt;.claude/commands/*.md&lt;/code&gt;. These are just markdown files with frontmatter (&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;tools&lt;/code&gt;) and instructions in the body. Claude Code picks them up automatically. Global install — same thing but in &lt;code&gt;~/.claude/agents/&lt;/code&gt; and &lt;code&gt;~/.claude/commands/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Minimal subagent template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-reviewer&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Brief description for the main agent — when to call&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sonnet&lt;/span&gt;
&lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Read&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Grep&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Glob&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Bash&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="gh"&gt;# Agent prompt&lt;/span&gt;

What to do, what to check, response format.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Practical tips from getting burned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tool names — PascalCase&lt;/strong&gt; (&lt;code&gt;Read&lt;/code&gt;, &lt;code&gt;Bash&lt;/code&gt;, &lt;code&gt;Grep&lt;/code&gt;, &lt;code&gt;Glob&lt;/code&gt;, &lt;code&gt;Agent&lt;/code&gt;). &lt;code&gt;read_file&lt;/code&gt;/&lt;code&gt;bash&lt;/code&gt; doesn't work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model IDs — short&lt;/strong&gt;: &lt;code&gt;sonnet&lt;/code&gt; / &lt;code&gt;opus&lt;/code&gt; / &lt;code&gt;haiku&lt;/code&gt; / &lt;code&gt;inherit&lt;/code&gt;. For the orchestrator &lt;code&gt;inherit&lt;/code&gt; is best — it runs on the model of the current session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't give subagents the &lt;code&gt;Agent&lt;/code&gt; tool&lt;/strong&gt; — they can't spawn other subagents, and if they try, the runtime crashes with an unclear error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict output format&lt;/strong&gt; — each agent returns a structured block (&lt;code&gt;=== AGENT: name === ... === END: name ===&lt;/code&gt;) with FINDINGS containing ID, Severity, Confidence, Location, Fix, Verify by. Free-form output → synthesis becomes mush.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Severity ≠ Confidence&lt;/strong&gt; — Severity is how scary (Blocker/High/Med/Low), Confidence is how sure the agent is. Two axes, not one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts in your team's language, terms in English&lt;/strong&gt; — if your team isn't English-speaking, agents read more naturally this way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pre-analysis is deterministic&lt;/strong&gt; — linter, regex, blame run &lt;em&gt;before&lt;/em&gt; the LLM. Cheaper for the agent to check pre-filtered material than to search from scratch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skills (slash-commands) — even simpler. Markdown describing what to do with the user input from &lt;code&gt;$ARGUMENTS&lt;/code&gt;. Useful home-skills I've made:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/diff&lt;/code&gt; — branch changes summary vs master (files, commits, affected functions, migrations). Handy before a PR.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/lint&lt;/code&gt; — wrapper over &lt;code&gt;make format&lt;/code&gt; (ruff + auto-fix).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/find-usage &amp;lt;name&amp;gt;&lt;/code&gt; — search all usages of a symbol (definition → imports → calls → tests → templates).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/debug &amp;lt;traceback&amp;gt;&lt;/code&gt; — traceback analysis: last frame, reading source at the right line, fix suggestion.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/logs [search] [--lines=N] [--level=ERROR]&lt;/code&gt; — viewing structured logs inside docker-container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/orm &amp;lt;expr|sql&amp;gt;&lt;/code&gt; — running Django ORM or raw SQL inside docker (with auto-LIMIT, confirmation request on DELETE/UPDATE).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/new-test &amp;lt;path&amp;gt; [name]&lt;/code&gt; — generating a pytest-file by project conventions with a run via docker.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/make &amp;lt;target&amp;gt; [args]&lt;/code&gt; — proxy to Makefile with categorized reference.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main thing about skills — they should be &lt;strong&gt;thin&lt;/strong&gt;. Not "universal devops agent", but "wrapper over one command with a couple of if-else's". The less freedom a skill has, the more predictable the result.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus step
&lt;/h1&gt;

&lt;p&gt;Besides code review agents, there's an option to ask the bots to highlight a developer's problems at the level of language understanding, etc — code that one writes can pass all checks but not be ideal (no such thing). Also the bot can suggest what things you can improve, watch the dynamics of your growth and give advice.&lt;/p&gt;

&lt;h1&gt;
  
  
  How it works
&lt;/h1&gt;

&lt;p&gt;Step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write code in a branch&lt;/li&gt;
&lt;li&gt;Run agents on the diff of feature branch and main branch&lt;/li&gt;
&lt;li&gt;Look at the review, study, fix or leave as is&lt;/li&gt;
&lt;li&gt;Get fewer bugs and better code, without losing the developer's project context&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbric0mrnpsvndaig9ke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvbric0mrnpsvndaig9ke.png" alt=" " width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping up
&lt;/h1&gt;

&lt;p&gt;Already there's a problem that code-writing by agents is pretty expensive + agents can't work with legacy code + project devs and analysts are important for its growth. New approaches are starting to appear that have the potential to solve these problems, but we're still needed in this world and we should do it as efficiently as possible to stay afloat longer and grow faster than new AI models :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez93kmxubv1l0h6yuvfr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fez93kmxubv1l0h6yuvfr.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
Main thing to remember — Bender is our brother, and the one who doesn't develop, degrades!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>beginners</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
