autonomous-coding-toolkit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +22 -0
- package/.claude-plugin/plugin.json +13 -0
- package/LICENSE +21 -0
- package/Makefile +21 -0
- package/README.md +140 -0
- package/SECURITY.md +28 -0
- package/agents/bash-expert.md +113 -0
- package/agents/dependency-auditor.md +138 -0
- package/agents/integration-tester.md +120 -0
- package/agents/lesson-scanner.md +149 -0
- package/agents/python-expert.md +179 -0
- package/agents/service-monitor.md +141 -0
- package/agents/shell-expert.md +147 -0
- package/benchmarks/runner.sh +147 -0
- package/benchmarks/tasks/01-rest-endpoint/rubric.sh +29 -0
- package/benchmarks/tasks/01-rest-endpoint/task.md +17 -0
- package/benchmarks/tasks/02-refactor-module/task.md +8 -0
- package/benchmarks/tasks/03-fix-integration-bug/task.md +8 -0
- package/benchmarks/tasks/04-add-test-coverage/task.md +8 -0
- package/benchmarks/tasks/05-multi-file-feature/task.md +8 -0
- package/bin/act.js +238 -0
- package/commands/autocode.md +6 -0
- package/commands/cancel-ralph.md +18 -0
- package/commands/code-factory.md +53 -0
- package/commands/create-prd.md +55 -0
- package/commands/ralph-loop.md +18 -0
- package/commands/run-plan.md +117 -0
- package/commands/submit-lesson.md +122 -0
- package/docs/ARCHITECTURE.md +630 -0
- package/docs/CONTRIBUTING.md +125 -0
- package/docs/lessons/0001-bare-exception-swallowing.md +34 -0
- package/docs/lessons/0002-async-def-without-await.md +28 -0
- package/docs/lessons/0003-create-task-without-callback.md +28 -0
- package/docs/lessons/0004-hardcoded-test-counts.md +28 -0
- package/docs/lessons/0005-sqlite-without-closing.md +33 -0
- package/docs/lessons/0006-venv-pip-path.md +27 -0
- package/docs/lessons/0007-runner-state-self-rejection.md +35 -0
- package/docs/lessons/0008-quality-gate-blind-spot.md +33 -0
- package/docs/lessons/0009-parser-overcount-empty-batches.md +36 -0
- package/docs/lessons/0010-local-outside-function-bash.md +33 -0
- package/docs/lessons/0011-batch-tests-for-unimplemented-code.md +36 -0
- package/docs/lessons/0012-api-markdown-unescaped-chars.md +33 -0
- package/docs/lessons/0013-export-prefix-env-parsing.md +33 -0
- package/docs/lessons/0014-decorator-registry-import-side-effect.md +43 -0
- package/docs/lessons/0015-frontend-backend-schema-drift.md +43 -0
- package/docs/lessons/0016-event-driven-cold-start-seeding.md +44 -0
- package/docs/lessons/0017-copy-paste-logic-diverges.md +43 -0
- package/docs/lessons/0018-layer-passes-pipeline-broken.md +45 -0
- package/docs/lessons/0019-systemd-envfile-ignores-export.md +41 -0
- package/docs/lessons/0020-persist-state-incrementally.md +44 -0
- package/docs/lessons/0021-dual-axis-testing.md +48 -0
- package/docs/lessons/0022-jsx-factory-shadowing.md +43 -0
- package/docs/lessons/0023-static-analysis-spiral.md +51 -0
- package/docs/lessons/0024-shared-pipeline-implementation.md +55 -0
- package/docs/lessons/0025-defense-in-depth-all-entry-points.md +65 -0
- package/docs/lessons/0026-linter-no-rules-false-enforcement.md +54 -0
- package/docs/lessons/0027-jsx-silent-prop-drop.md +64 -0
- package/docs/lessons/0028-no-infrastructure-in-client-code.md +49 -0
- package/docs/lessons/0029-never-write-secrets-to-files.md +61 -0
- package/docs/lessons/0030-cache-merge-not-replace.md +62 -0
- package/docs/lessons/0031-verify-units-at-boundaries.md +66 -0
- package/docs/lessons/0032-module-lifecycle-subscribe-unsubscribe.md +89 -0
- package/docs/lessons/0033-async-iteration-mutable-snapshot.md +72 -0
- package/docs/lessons/0034-caller-missing-await-silent-discard.md +65 -0
- package/docs/lessons/0035-duplicate-registration-silent-overwrite.md +85 -0
- package/docs/lessons/0036-websocket-dirty-disconnect.md +33 -0
- package/docs/lessons/0037-parallel-agents-worktree-corruption.md +31 -0
- package/docs/lessons/0038-subscribe-no-stored-ref.md +36 -0
- package/docs/lessons/0039-fallback-or-default-hides-bugs.md +34 -0
- package/docs/lessons/0040-event-firehose-filter-first.md +36 -0
- package/docs/lessons/0041-ambiguous-base-dir-path-nesting.md +32 -0
- package/docs/lessons/0042-spec-compliance-insufficient.md +36 -0
- package/docs/lessons/0043-exact-count-extensible-collections.md +32 -0
- package/docs/lessons/0044-relative-file-deps-worktree.md +39 -0
- package/docs/lessons/0045-iterative-design-improvement.md +33 -0
- package/docs/lessons/0046-plan-assertion-math-bugs.md +38 -0
- package/docs/lessons/0047-pytest-single-threaded-default.md +37 -0
- package/docs/lessons/0048-integration-wiring-batch.md +40 -0
- package/docs/lessons/0049-ab-verification.md +41 -0
- package/docs/lessons/0050-editing-sourced-files-during-execution.md +33 -0
- package/docs/lessons/0051-infrastructure-fixes-cant-self-heal.md +30 -0
- package/docs/lessons/0052-uncommitted-changes-poison-quality-gates.md +31 -0
- package/docs/lessons/0053-jq-compact-flag-inconsistency.md +31 -0
- package/docs/lessons/0054-parser-matches-inside-code-blocks.md +30 -0
- package/docs/lessons/0055-agents-compensate-for-garbled-prompts.md +31 -0
- package/docs/lessons/0056-grep-count-exit-code-on-zero.md +42 -0
- package/docs/lessons/0057-new-artifacts-break-git-clean-gates.md +42 -0
- package/docs/lessons/0058-dead-config-keys-never-consumed.md +49 -0
- package/docs/lessons/0059-contract-test-shared-structures.md +53 -0
- package/docs/lessons/0060-set-e-silent-death-in-runners.md +53 -0
- package/docs/lessons/0061-context-injection-dirty-state.md +50 -0
- package/docs/lessons/0062-sibling-bug-neighborhood-scan.md +29 -0
- package/docs/lessons/0063-one-flag-two-lifetimes.md +31 -0
- package/docs/lessons/0064-test-passes-wrong-reason.md +31 -0
- package/docs/lessons/0065-pipefail-grep-count-double-output.md +39 -0
- package/docs/lessons/0066-local-keyword-outside-function.md +37 -0
- package/docs/lessons/0067-stdin-hang-non-interactive-shell.md +36 -0
- package/docs/lessons/0068-agent-builds-wrong-thing-correctly.md +31 -0
- package/docs/lessons/0069-plan-quality-dominates-execution.md +30 -0
- package/docs/lessons/0070-spec-echo-back-prevents-drift.md +31 -0
- package/docs/lessons/0071-positive-instructions-outperform-negative.md +30 -0
- package/docs/lessons/0072-lost-in-the-middle-context-placement.md +30 -0
- package/docs/lessons/0073-unscoped-lessons-cause-false-positives.md +30 -0
- package/docs/lessons/0074-stale-context-injection-wrong-batch.md +32 -0
- package/docs/lessons/0075-research-artifacts-must-persist.md +32 -0
- package/docs/lessons/0076-wrong-decomposition-contaminates-downstream.md +30 -0
- package/docs/lessons/0077-cherry-pick-merges-need-manual-resolution.md +30 -0
- package/docs/lessons/0078-static-review-without-live-test.md +30 -0
- package/docs/lessons/0079-integration-wiring-batch-required.md +32 -0
- package/docs/lessons/FRAMEWORK.md +161 -0
- package/docs/lessons/SUMMARY.md +201 -0
- package/docs/lessons/TEMPLATE.md +85 -0
- package/docs/plans/2026-02-21-code-factory-v2-design.md +204 -0
- package/docs/plans/2026-02-21-code-factory-v2-implementation-plan.md +2189 -0
- package/docs/plans/2026-02-21-code-factory-v2-phase4-design.md +537 -0
- package/docs/plans/2026-02-21-code-factory-v2-phase4-implementation-plan.md +2012 -0
- package/docs/plans/2026-02-21-hardening-pass-design.md +108 -0
- package/docs/plans/2026-02-21-hardening-pass-plan.md +1378 -0
- package/docs/plans/2026-02-21-mab-research-report.md +406 -0
- package/docs/plans/2026-02-21-marketplace-restructure-design.md +240 -0
- package/docs/plans/2026-02-21-marketplace-restructure-plan.md +832 -0
- package/docs/plans/2026-02-21-phase4-completion-plan.md +697 -0
- package/docs/plans/2026-02-21-validator-suite-design.md +148 -0
- package/docs/plans/2026-02-21-validator-suite-plan.md +540 -0
- package/docs/plans/2026-02-22-mab-research-round2.md +556 -0
- package/docs/plans/2026-02-22-mab-run-design.md +462 -0
- package/docs/plans/2026-02-22-mab-run-plan.md +2046 -0
- package/docs/plans/2026-02-22-operations-design-methodology-research.md +681 -0
- package/docs/plans/2026-02-22-research-agent-failure-taxonomy.md +532 -0
- package/docs/plans/2026-02-22-research-code-guideline-policies.md +886 -0
- package/docs/plans/2026-02-22-research-codebase-audit-refactoring.md +908 -0
- package/docs/plans/2026-02-22-research-coding-standards-documentation.md +541 -0
- package/docs/plans/2026-02-22-research-competitive-landscape.md +687 -0
- package/docs/plans/2026-02-22-research-comprehensive-testing.md +1076 -0
- package/docs/plans/2026-02-22-research-context-utilization.md +459 -0
- package/docs/plans/2026-02-22-research-cost-quality-tradeoff.md +548 -0
- package/docs/plans/2026-02-22-research-lesson-transferability.md +508 -0
- package/docs/plans/2026-02-22-research-multi-agent-coordination.md +312 -0
- package/docs/plans/2026-02-22-research-phase-integration.md +602 -0
- package/docs/plans/2026-02-22-research-plan-quality.md +428 -0
- package/docs/plans/2026-02-22-research-prompt-engineering.md +558 -0
- package/docs/plans/2026-02-22-research-unconventional-perspectives.md +528 -0
- package/docs/plans/2026-02-22-research-user-adoption.md +638 -0
- package/docs/plans/2026-02-22-research-verification-effectiveness.md +433 -0
- package/docs/plans/2026-02-23-agent-suite-design.md +299 -0
- package/docs/plans/2026-02-23-agent-suite-plan.md +578 -0
- package/docs/plans/2026-02-23-phase3-cost-infrastructure-design.md +148 -0
- package/docs/plans/2026-02-23-phase3-cost-infrastructure-plan.md +1062 -0
- package/docs/plans/2026-02-23-research-bash-expert-agent.md +543 -0
- package/docs/plans/2026-02-23-research-dependency-auditor-agent.md +564 -0
- package/docs/plans/2026-02-23-research-improving-existing-agents.md +503 -0
- package/docs/plans/2026-02-23-research-integration-tester-agent.md +454 -0
- package/docs/plans/2026-02-23-research-python-expert-agent.md +429 -0
- package/docs/plans/2026-02-23-research-service-monitor-agent.md +425 -0
- package/docs/plans/2026-02-23-research-shell-expert-agent.md +533 -0
- package/docs/plans/2026-02-23-roadmap-to-completion.md +530 -0
- package/docs/plans/2026-02-24-headless-module-split-design.md +98 -0
- package/docs/plans/2026-02-24-headless-module-split.md +443 -0
- package/docs/plans/2026-02-24-lesson-scope-metadata-design.md +228 -0
- package/docs/plans/2026-02-24-lesson-scope-metadata-plan.md +968 -0
- package/docs/plans/2026-02-24-npm-packaging-design.md +841 -0
- package/docs/plans/2026-02-24-npm-packaging-plan.md +1965 -0
- package/docs/plans/audit-findings.md +186 -0
- package/docs/telegram-notification-format.md +98 -0
- package/examples/example-plan.md +51 -0
- package/examples/example-prd.json +72 -0
- package/examples/example-roadmap.md +33 -0
- package/examples/quickstart-plan.md +63 -0
- package/hooks/hooks.json +26 -0
- package/hooks/setup-symlinks.sh +48 -0
- package/hooks/stop-hook.sh +135 -0
- package/package.json +47 -0
- package/policies/bash.md +71 -0
- package/policies/python.md +71 -0
- package/policies/testing.md +61 -0
- package/policies/universal.md +60 -0
- package/scripts/analyze-report.sh +97 -0
- package/scripts/architecture-map.sh +145 -0
- package/scripts/auto-compound.sh +273 -0
- package/scripts/batch-audit.sh +42 -0
- package/scripts/batch-test.sh +101 -0
- package/scripts/entropy-audit.sh +221 -0
- package/scripts/failure-digest.sh +51 -0
- package/scripts/generate-ast-rules.sh +96 -0
- package/scripts/init.sh +112 -0
- package/scripts/lesson-check.sh +428 -0
- package/scripts/lib/common.sh +61 -0
- package/scripts/lib/cost-tracking.sh +153 -0
- package/scripts/lib/ollama.sh +60 -0
- package/scripts/lib/progress-writer.sh +128 -0
- package/scripts/lib/run-plan-context.sh +215 -0
- package/scripts/lib/run-plan-echo-back.sh +231 -0
- package/scripts/lib/run-plan-headless.sh +396 -0
- package/scripts/lib/run-plan-notify.sh +57 -0
- package/scripts/lib/run-plan-parser.sh +81 -0
- package/scripts/lib/run-plan-prompt.sh +215 -0
- package/scripts/lib/run-plan-quality-gate.sh +132 -0
- package/scripts/lib/run-plan-routing.sh +315 -0
- package/scripts/lib/run-plan-sampling.sh +170 -0
- package/scripts/lib/run-plan-scoring.sh +146 -0
- package/scripts/lib/run-plan-state.sh +142 -0
- package/scripts/lib/run-plan-team.sh +199 -0
- package/scripts/lib/telegram.sh +54 -0
- package/scripts/lib/thompson-sampling.sh +176 -0
- package/scripts/license-check.sh +74 -0
- package/scripts/mab-run.sh +575 -0
- package/scripts/module-size-check.sh +146 -0
- package/scripts/patterns/async-no-await.yml +5 -0
- package/scripts/patterns/bare-except.yml +6 -0
- package/scripts/patterns/empty-catch.yml +6 -0
- package/scripts/patterns/hardcoded-localhost.yml +9 -0
- package/scripts/patterns/retry-loop-no-backoff.yml +12 -0
- package/scripts/pipeline-status.sh +197 -0
- package/scripts/policy-check.sh +226 -0
- package/scripts/prior-art-search.sh +133 -0
- package/scripts/promote-mab-lessons.sh +126 -0
- package/scripts/prompts/agent-a-superpowers.md +29 -0
- package/scripts/prompts/agent-b-ralph.md +29 -0
- package/scripts/prompts/judge-agent.md +61 -0
- package/scripts/prompts/planner-agent.md +44 -0
- package/scripts/pull-community-lessons.sh +90 -0
- package/scripts/quality-gate.sh +266 -0
- package/scripts/research-gate.sh +90 -0
- package/scripts/run-plan.sh +329 -0
- package/scripts/scope-infer.sh +159 -0
- package/scripts/setup-ralph-loop.sh +155 -0
- package/scripts/telemetry.sh +230 -0
- package/scripts/tests/run-all-tests.sh +52 -0
- package/scripts/tests/test-act-cli.sh +46 -0
- package/scripts/tests/test-agents-md.sh +87 -0
- package/scripts/tests/test-analyze-report.sh +114 -0
- package/scripts/tests/test-architecture-map.sh +89 -0
- package/scripts/tests/test-auto-compound.sh +169 -0
- package/scripts/tests/test-batch-test.sh +65 -0
- package/scripts/tests/test-benchmark-runner.sh +25 -0
- package/scripts/tests/test-common.sh +168 -0
- package/scripts/tests/test-cost-tracking.sh +158 -0
- package/scripts/tests/test-echo-back.sh +180 -0
- package/scripts/tests/test-entropy-audit.sh +146 -0
- package/scripts/tests/test-failure-digest.sh +66 -0
- package/scripts/tests/test-generate-ast-rules.sh +145 -0
- package/scripts/tests/test-helpers.sh +82 -0
- package/scripts/tests/test-init.sh +47 -0
- package/scripts/tests/test-lesson-check.sh +278 -0
- package/scripts/tests/test-lesson-local.sh +55 -0
- package/scripts/tests/test-license-check.sh +109 -0
- package/scripts/tests/test-mab-run.sh +182 -0
- package/scripts/tests/test-ollama-lib.sh +49 -0
- package/scripts/tests/test-ollama.sh +60 -0
- package/scripts/tests/test-pipeline-status.sh +198 -0
- package/scripts/tests/test-policy-check.sh +124 -0
- package/scripts/tests/test-prior-art-search.sh +96 -0
- package/scripts/tests/test-progress-writer.sh +140 -0
- package/scripts/tests/test-promote-mab-lessons.sh +110 -0
- package/scripts/tests/test-pull-community-lessons.sh +149 -0
- package/scripts/tests/test-quality-gate.sh +241 -0
- package/scripts/tests/test-research-gate.sh +132 -0
- package/scripts/tests/test-run-plan-cli.sh +86 -0
- package/scripts/tests/test-run-plan-context.sh +305 -0
- package/scripts/tests/test-run-plan-e2e.sh +153 -0
- package/scripts/tests/test-run-plan-headless.sh +424 -0
- package/scripts/tests/test-run-plan-notify.sh +124 -0
- package/scripts/tests/test-run-plan-parser.sh +217 -0
- package/scripts/tests/test-run-plan-prompt.sh +254 -0
- package/scripts/tests/test-run-plan-quality-gate.sh +222 -0
- package/scripts/tests/test-run-plan-routing.sh +178 -0
- package/scripts/tests/test-run-plan-scoring.sh +148 -0
- package/scripts/tests/test-run-plan-state.sh +261 -0
- package/scripts/tests/test-run-plan-team.sh +157 -0
- package/scripts/tests/test-scope-infer.sh +150 -0
- package/scripts/tests/test-setup-ralph-loop.sh +63 -0
- package/scripts/tests/test-telegram-env.sh +38 -0
- package/scripts/tests/test-telegram.sh +121 -0
- package/scripts/tests/test-telemetry.sh +46 -0
- package/scripts/tests/test-thompson-sampling.sh +139 -0
- package/scripts/tests/test-validate-all.sh +60 -0
- package/scripts/tests/test-validate-commands.sh +89 -0
- package/scripts/tests/test-validate-hooks.sh +98 -0
- package/scripts/tests/test-validate-lessons.sh +150 -0
- package/scripts/tests/test-validate-plan-quality.sh +235 -0
- package/scripts/tests/test-validate-plans.sh +187 -0
- package/scripts/tests/test-validate-plugin.sh +106 -0
- package/scripts/tests/test-validate-prd.sh +184 -0
- package/scripts/tests/test-validate-skills.sh +134 -0
- package/scripts/validate-all.sh +57 -0
- package/scripts/validate-commands.sh +67 -0
- package/scripts/validate-hooks.sh +89 -0
- package/scripts/validate-lessons.sh +98 -0
- package/scripts/validate-plan-quality.sh +369 -0
- package/scripts/validate-plans.sh +120 -0
- package/scripts/validate-plugin.sh +86 -0
- package/scripts/validate-policies.sh +42 -0
- package/scripts/validate-prd.sh +118 -0
- package/scripts/validate-skills.sh +96 -0
- package/skills/autocode/SKILL.md +285 -0
- package/skills/autocode/ab-verification.md +51 -0
- package/skills/autocode/code-quality-standards.md +37 -0
- package/skills/autocode/competitive-mode.md +364 -0
- package/skills/brainstorming/SKILL.md +97 -0
- package/skills/capture-lesson/SKILL.md +187 -0
- package/skills/check-lessons/SKILL.md +116 -0
- package/skills/dispatching-parallel-agents/SKILL.md +110 -0
- package/skills/executing-plans/SKILL.md +85 -0
- package/skills/finishing-a-development-branch/SKILL.md +201 -0
- package/skills/receiving-code-review/SKILL.md +72 -0
- package/skills/requesting-code-review/SKILL.md +59 -0
- package/skills/requesting-code-review/code-reviewer.md +82 -0
- package/skills/research/SKILL.md +145 -0
- package/skills/roadmap/SKILL.md +115 -0
- package/skills/subagent-driven-development/SKILL.md +98 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +18 -0
- package/skills/subagent-driven-development/implementer-prompt.md +73 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +57 -0
- package/skills/systematic-debugging/SKILL.md +134 -0
- package/skills/systematic-debugging/condition-based-waiting.md +64 -0
- package/skills/systematic-debugging/defense-in-depth.md +32 -0
- package/skills/systematic-debugging/root-cause-tracing.md +55 -0
- package/skills/test-driven-development/SKILL.md +167 -0
- package/skills/using-git-worktrees/SKILL.md +219 -0
- package/skills/using-superpowers/SKILL.md +54 -0
- package/skills/verification-before-completion/SKILL.md +140 -0
- package/skills/verify/SKILL.md +82 -0
- package/skills/writing-plans/SKILL.md +128 -0
- package/skills/writing-skills/SKILL.md +93 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
# Research: Python Expert Claude Code Agent
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-02-23
|
|
4
|
+
**Status:** Complete
|
|
5
|
+
**Confidence:** High on tool landscape; Medium on agent structure (novel combination)
|
|
6
|
+
**Cynefin domain:** Complicated — knowable with expert analysis
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## BLUF
|
|
11
|
+
|
|
12
|
+
A Python expert agent for Justin's stack (HA, Telegram, Notion, Ollama) should be built as a **review-mode Claude Code subagent** that extends the existing `lesson-scanner` with three new scan groups: async discipline, WebSocket lifecycle, and type safety. The tooling ecosystem (ruff RUF006/RUF029, flake8-async ASYNC2xx, semgrep) provides the detection vocabulary; the agent's value-add is contextual judgment on patterns the linters cannot classify (e.g., "is this `async def` waiting on I/O or not?"). Build as `.claude/agents/python-expert.md`.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Section 1: Claude Code Custom Agents — Pattern Survey
|
|
17
|
+
|
|
18
|
+
### Sources
|
|
19
|
+
|
|
20
|
+
- [VoltAgent/awesome-claude-code-subagents](https://github.com/VoltAgent/awesome-claude-code-subagents) — 100+ production subagents
|
|
21
|
+
- [affaan-m/everything-claude-code](https://github.com/affaan-m/everything-claude-code) — architect agent pattern
|
|
22
|
+
- [Anthropic subagent docs](https://code.claude.com/docs/en/sub-agents)
|
|
23
|
+
|
|
24
|
+
### Findings
|
|
25
|
+
|
|
26
|
+
**Structural pattern (frontmatter + prose):**
|
|
27
|
+
```yaml
|
|
28
|
+
---
|
|
29
|
+
name: python-expert
|
|
30
|
+
description: "Use this agent when you need to review Python code for async discipline, resource lifecycle, and type safety in asyncio/MQTT/SQLite/WebSocket contexts."
|
|
31
|
+
tools: Read, Grep, Glob, Bash
|
|
32
|
+
model: sonnet
|
|
33
|
+
---
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The description field controls automatic dispatch — Claude routes to the agent when user intent matches. Be specific: generic descriptions cause false invocations.
|
|
37
|
+
|
|
38
|
+
**python-pro agent (VoltAgent) — key elements:**
|
|
39
|
+
- Type hints for all function signatures and class attributes
|
|
40
|
+
- Async/await for I/O-bound operations (but no mechanism to enforce the "only if I/O" constraint)
|
|
41
|
+
- Task groups and exception handling mentioned but not operationalized
|
|
42
|
+
- No project-specific scan patterns — too generic
|
|
43
|
+
|
|
44
|
+
**code-reviewer agent (VoltAgent) — model choice:**
|
|
45
|
+
- Uses `model: opus` — correct for architectural review where judgment depth matters
|
|
46
|
+
- Checklist-driven review with cyclomatic complexity, coverage, resource leaks
|
|
47
|
+
- Performance analysis section includes "async patterns" and "resource leaks" — aligned with our needs
|
|
48
|
+
|
|
49
|
+
**architect agent (everything-claude-code):**
|
|
50
|
+
- Uses `model: opus`, read-only tools (`Read, Grep, Glob`)
|
|
51
|
+
- Trade-off analysis format: Pros / Cons / Alternatives / Decision
|
|
52
|
+
- Explicitly scoped to planning, not code production — separation of concerns
|
|
53
|
+
|
|
54
|
+
**Gap in all surveyed agents:** None encode project-specific lesson numbers, specific API patterns (MQTT subscribe teardown, sqlite3.closing()), or scan groups with grep patterns. They describe *what* to check but not *how* to mechanically find it. The lesson-scanner agent (existing) is more operationally precise than any public example.
|
|
55
|
+
|
|
56
|
+
**Adoption decision:** Use lesson-scanner's grep-pattern-per-scan-group structure as the model. The python-expert agent should extend lesson-scanner's format with three new groups, not replace it.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Section 2: Async Discipline Tools
|
|
61
|
+
|
|
62
|
+
### Sources
|
|
63
|
+
|
|
64
|
+
- [flake8-async (python-trio)](https://github.com/python-trio/flake8-async) — the canonical asyncio linter
|
|
65
|
+
- [ruff ASYNC rules](https://docs.astral.sh/ruff/rules/) — flake8-async rules ported to ruff
|
|
66
|
+
- [ruff RUF029 unused-async](https://docs.astral.sh/ruff/rules/unused-async/) — detects `async def` without I/O
|
|
67
|
+
- [ruff RUF006 asyncio-dangling-task](https://docs.astral.sh/ruff/rules/asyncio-dangling-task/) — detects create_task without reference
|
|
68
|
+
- [flake8-async ASYNC300 create-task-no-reference](https://github.com/python-trio/flake8-async/issues/207)
|
|
69
|
+
- [SuperFastPython asyncio linting guide](https://superfastpython.com/lint-asyncio-code/)
|
|
70
|
+
|
|
71
|
+
### Key Rules Mapped to Production Failures
|
|
72
|
+
|
|
73
|
+
**Lesson #25 / #30 — `async def` without I/O:**
|
|
74
|
+
- **RUF029** (ruff preview): "Checks for functions declared `async` that do not `await` or otherwise use features requiring the function to be declared async." This is exactly Lesson #25.
|
|
75
|
+
- Status: Preview mode (`--preview` flag required). Not in ruff stable yet.
|
|
76
|
+
- Workaround: The existing lesson-scanner Scan 1a (reads function body for `await` presence) is the operative check until RUF029 stabilizes.
|
|
77
|
+
|
|
78
|
+
**Lesson #43 — `create_task` without done_callback:**
|
|
79
|
+
- **RUF006**: "Checks for `asyncio.create_task` and `asyncio.ensure_future` calls that do not store a reference to the returned result."
|
|
80
|
+
- Rule is stable (added v0.0.247). Detects the reference-not-stored case.
|
|
81
|
+
- Limitation: RUF006 does not require `add_done_callback` — it accepts storing the reference in any variable. The lesson requires both: store reference AND add_done_callback for error visibility.
|
|
82
|
+
- Agent check must go beyond RUF006: for each `create_task` call, verify that the task variable has `.add_done_callback(` within 5 lines.
|
|
83
|
+
|
|
84
|
+
**Lesson #25 / #30 — blocking calls in async context:**
|
|
85
|
+
- **ASYNC210**: "Async functions should not call blocking HTTP methods"
|
|
86
|
+
- **ASYNC220–222**: Blocking subprocess methods in async context
|
|
87
|
+
- **ASYNC230**: "Async functions should not open files with blocking methods like `open`" — directly relevant to HA/Notion sync code
|
|
88
|
+
- **ASYNC251**: "Blocking call to `time.sleep()` in async context"
|
|
89
|
+
- All are stable in ruff (no `--preview` needed).
|
|
90
|
+
|
|
91
|
+
**Missing await at call sites (Lesson #25, #30):**
|
|
92
|
+
- No static rule catches a missing `await` for a project-specific async function — these are unknown to linters.
|
|
93
|
+
- Python's `asyncio` emits `RuntimeWarning: coroutine 'X' was never awaited` at runtime, but this is silent in logs unless `asyncio.get_event_loop().set_debug(True)` is set.
|
|
94
|
+
- Agent approach: grep for calls to known async functions without preceding `await`. Requires project-specific pattern list.
|
|
95
|
+
|
|
96
|
+
**Recommended ruff configuration (pyproject.toml):**
|
|
97
|
+
```toml
|
|
98
|
+
[tool.ruff.lint]
|
|
99
|
+
select = [
|
|
100
|
+
"ASYNC", # flake8-async rules (blocking calls, async discipline)
|
|
101
|
+
"RUF006", # asyncio-dangling-task (create_task without reference)
|
|
102
|
+
"RUF029", # unused-async (async def without I/O) -- requires --preview
|
|
103
|
+
"B", # flake8-bugbear (general design problems)
|
|
104
|
+
]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Section 3: SQLite Lifecycle
|
|
110
|
+
|
|
111
|
+
### Sources
|
|
112
|
+
|
|
113
|
+
- [Python docs sqlite3](https://docs.python.org/3/library/sqlite3.html)
|
|
114
|
+
- [Robin's Blog — sqlite3 context manager gotcha](https://blog.rtwilson.com/a-python-sqlite3-context-manager-gotcha/)
|
|
115
|
+
- [alexwlchan TIL — sqlite3 context manager doesn't close](https://alexwlchan.net/til/2024/sqlite3-context-manager-doesnt-close-connections/)
|
|
116
|
+
- [Python discuss — implicitly close sqlite3 with context managers](https://discuss.python.org/t/implicitly-close-sqlite3-connections-with-context-managers/33320)
|
|
117
|
+
- [Simple sqlite3 context manager gist](https://gist.github.com/miku/6522074)
|
|
118
|
+
|
|
119
|
+
### Findings
|
|
120
|
+
|
|
121
|
+
**The core misunderstanding (Lesson #33):**
|
|
122
|
+
```python
|
|
123
|
+
# WRONG — does NOT close the connection on exit
|
|
124
|
+
with sqlite3.connect("db.sqlite3") as conn:
|
|
125
|
+
conn.execute(...)
|
|
126
|
+
# conn is still open here
|
|
127
|
+
|
|
128
|
+
# RIGHT — closes on exit
|
|
129
|
+
from contextlib import closing
|
|
130
|
+
with closing(sqlite3.connect("db.sqlite3")) as conn:
|
|
131
|
+
conn.execute(...)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The `sqlite3.Connection.__exit__` method commits or rolls back the transaction but explicitly does *not* close the connection. This is documented but widely misread. Python's discussion forum has an open thread (2023) about adding implicit close to the context manager — not yet resolved as of 2025.
|
|
135
|
+
|
|
136
|
+
**Detection pattern (already in lesson-scanner Scan 3c):**
|
|
137
|
+
```
|
|
138
|
+
pattern: sqlite3\.connect\(
|
|
139
|
+
glob: **/*.py
|
|
140
|
+
```
|
|
141
|
+
Read ±5 lines. If not wrapped in `closing(...)` or an explicit `conn.close()` in a `finally` block, flag as Should-Fix.
|
|
142
|
+
|
|
143
|
+
**Async SQLite:**
|
|
144
|
+
For async code (HA, Telegram bots), the standard is `aiosqlite`, which provides an async context manager that *does* close the connection:
|
|
145
|
+
```python
|
|
146
|
+
async with aiosqlite.connect("db.sqlite3") as db:
|
|
147
|
+
await db.execute(...)
|
|
148
|
+
# connection closed here
|
|
149
|
+
```
|
|
150
|
+
The agent should flag synchronous `sqlite3.connect` inside `async def` as a blocking I/O violation (ASYNC230 covers `open`; sqlite3 is not yet covered by ruff — check manually).
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Section 4: Python Code Review Bots — Architectural Review
|
|
155
|
+
|
|
156
|
+
### Sources
|
|
157
|
+
|
|
158
|
+
- [DeepSource Python anti-patterns](https://deepsource.com/blog/8-new-python-antipatterns)
|
|
159
|
+
- [semgrep-rules (semgrep/semgrep-rules)](https://github.com/semgrep/semgrep-rules)
|
|
160
|
+
- [Trail of Bits semgrep rules](https://github.com/trailofbits/semgrep-rules)
|
|
161
|
+
- [quantifiedcode/python-anti-patterns](https://github.com/quantifiedcode/python-anti-patterns)
|
|
162
|
+
- [charlax/professional-programming antipatterns](https://github.com/charlax/professional-programming/blob/master/antipatterns/error-handling-antipatterns.md)
|
|
163
|
+
|
|
164
|
+
### Findings
|
|
165
|
+
|
|
166
|
+
**Semgrep vs ruff vs pylint — decision matrix:**
|
|
167
|
+
|
|
168
|
+
| Tool | Strength | Weakness | Use case |
|
|
169
|
+
|------|----------|----------|----------|
|
|
170
|
+
| ruff | Fast, stable, 800+ rules, CI-friendly | Cannot do cross-file analysis, no custom AST traversal | Pre-commit gate, CI |
|
|
171
|
+
| semgrep | Semantic pattern matching, cross-file, custom rules | Slower, YAML rule syntax | Architectural checks, custom patterns |
|
|
172
|
+
| pylint | Mature, configurable | Slow, noisy | Optional second pass |
|
|
173
|
+
| Agent (LLM) | Contextual judgment, project-specific knowledge | Cannot run at CI speed | Review gate on PR/commit |
|
|
174
|
+
|
|
175
|
+
**Semgrep rules relevant to Justin's stack:**
|
|
176
|
+
- `python.lang.security.audit.dangerous-asyncio-create-exec-audit` — asyncio exec injection
|
|
177
|
+
- Custom rule opportunity: write a semgrep rule for `sqlite3.connect` not wrapped in `closing()`
|
|
178
|
+
- Trail of Bits rules: focus on security rather than lifecycle, but include good error handling patterns
|
|
179
|
+
|
|
180
|
+
**DeepSource patterns (anti-patterns beyond basic linting):**
|
|
181
|
+
1. Using mutable default arguments (`def f(x=[])`)
|
|
182
|
+
2. Using `type()` instead of `isinstance()`
|
|
183
|
+
3. Comparison to `None` with `==` instead of `is`
|
|
184
|
+
4. Bare `raise` in wrong context
|
|
185
|
+
5. Not using context managers for file/resource handling
|
|
186
|
+
|
|
187
|
+
**charlax error-handling anti-patterns (directly relevant):**
|
|
188
|
+
- Silencing errors: `except Exception: pass` (Lesson #7)
|
|
189
|
+
- Catching too broadly, then re-raising wrong exception
|
|
190
|
+
- Not logging before returning fallback (Lesson #7)
|
|
191
|
+
- Missing `exc_info=True` on exception log calls (Lesson #43)
|
|
192
|
+
|
|
193
|
+
**Architectural review dimension missing from all tools:**
|
|
194
|
+
None of the tools above can detect:
|
|
195
|
+
- "Is this MQTT subscription paired with an unsubscribe in shutdown?" (Lesson #37)
|
|
196
|
+
- "Is this callback stored as `self._unsub = subscribe(...)` so it can be cancelled?" (Lesson #37)
|
|
197
|
+
- "Does this class with a subscriber have a `shutdown()` or `async_will_remove_from_hass()`?" (Lesson #37)
|
|
198
|
+
These require reading class structure across methods — semantic analysis that only an LLM agent can do.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Section 5: Python Anti-Pattern Detection — Resource Lifecycle
|
|
203
|
+
|
|
204
|
+
### Sources
|
|
205
|
+
|
|
206
|
+
- [flake8-bugbear (PyCQA)](https://github.com/PyCQA/flake8-bugbear) — design problem warnings
|
|
207
|
+
- [HA MQTT async example](https://github.com/home-assistant/example-custom-config/blob/master/custom_components/mqtt_basic_async/__init__.py)
|
|
208
|
+
- [HA async developer docs](https://developers.home-assistant.io/docs/asyncio_working_with_async/)
|
|
209
|
+
- [asyncdef/eventemitter](https://github.com/asyncdef/eventemitter) — async event emitter patterns
|
|
210
|
+
- [aiopubsub (PyPI)](https://pypi.org/project/aiopubsub/) — pub/sub lifecycle patterns
|
|
211
|
+
|
|
212
|
+
### Findings
|
|
213
|
+
|
|
214
|
+
**Subscriber lifecycle pattern (Lesson #37):**
|
|
215
|
+
|
|
216
|
+
The canonical HA pattern stores the unsubscribe reference:
|
|
217
|
+
```python
|
|
218
|
+
class MyEntity:
|
|
219
|
+
def __init__(self):
|
|
220
|
+
self._unsub_state = None # must be stored on self
|
|
221
|
+
|
|
222
|
+
async def async_added_to_hass(self):
|
|
223
|
+
# Store reference — if you don't store it, you can't unsubscribe
|
|
224
|
+
self._unsub_state = async_track_state_change_event(
|
|
225
|
+
self.hass, self.entity_id, self._handle_state_change
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
async def async_will_remove_from_hass(self):
|
|
229
|
+
if self._unsub_state:
|
|
230
|
+
self._unsub_state() # teardown paired with setup
|
|
231
|
+
self._unsub_state = None
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The HA example code (`mqtt_basic_async/__init__.py`) uses `await hass.components.mqtt.async_subscribe(topic, message_received)` but the returned unsubscribe callable is not stored — this is the exact anti-pattern from Lesson #37.
|
|
235
|
+
|
|
236
|
+
**Detection approach:**
|
|
237
|
+
1. Grep for `.subscribe(`, `.async_track_state_change(`, `.listen(`, `.on_event(`
|
|
238
|
+
2. For each file with subscribe calls, check that:
|
|
239
|
+
- The result is assigned to `self._something`
|
|
240
|
+
- The class has a method containing the corresponding cancel/unsubscribe call
|
|
241
|
+
3. Files with subscribe but no teardown = Blocker
|
|
242
|
+
|
|
243
|
+
**WebSocket send guard (Lesson #34):**
|
|
244
|
+
|
|
245
|
+
The websockets library recommends EAFP (try/except over state-check):
|
|
246
|
+
```python
|
|
247
|
+
# WRONG — race condition between check and send
|
|
248
|
+
if ws.open:
|
|
249
|
+
await ws.send(data)
|
|
250
|
+
|
|
251
|
+
# RIGHT — EAFP with ConnectionClosed handling
|
|
252
|
+
try:
|
|
253
|
+
await ws.send(data)
|
|
254
|
+
except websockets.exceptions.ConnectionClosed:
|
|
255
|
+
logger.warning("WebSocket send failed: connection closed")
|
|
256
|
+
self._ws = None
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Static detection: grep for `await.*\.send(` inside `async def` and verify try/except wrapping. Unguarded sends are Should-Fix.
|
|
260
|
+
|
|
261
|
+
**Resource lifecycle checklist (consolidated from lessons #33, #34, #37, #43):**
|
|
262
|
+
|
|
263
|
+
| Resource | Open pattern | Must close with | Agent check |
|
|
264
|
+
|----------|-------------|-----------------|-------------|
|
|
265
|
+
| sqlite3 | `sqlite3.connect()` | `contextlib.closing()` or explicit `finally: conn.close()` | Scan 3c (existing) |
|
|
266
|
+
| aiosqlite | `async with aiosqlite.connect()` | Built-in (context manager closes) | Flag if used outside `async with` |
|
|
267
|
+
| WebSocket | `await ws.send()` | try/except ConnectionClosed | New scan group |
|
|
268
|
+
| MQTT sub | `.subscribe()` | Return value stored + `unsubscribe()` in shutdown | New scan group |
|
|
269
|
+
| asyncio task | `create_task()` | Store ref + `.add_done_callback()` | Extend Scan 3d |
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Section 6: Type Safety and Runtime Validation
|
|
274
|
+
|
|
275
|
+
### Sources
|
|
276
|
+
|
|
277
|
+
- [Python typing guide 2025 (Medium)](https://khaled-jallouli.medium.com/python-typing-in-2025-a-comprehensive-guide-d61b4f562b99)
|
|
278
|
+
- [Type-Safe Python: Pyright + Pydantic (Medium)](https://medium.com/pythoneers/type-safe-python-leveraging-pyright-and-pydantic-for-reliable-applications-2a081e137d00)
|
|
279
|
+
- [Type Safety in Python: MyPy, Pydantic, Runtime Validation (dasroot.net)](https://dasroot.net/posts/2026/02/type-safety-python-mypy-pydantic-runtime-validation/)
|
|
280
|
+
- [Beartype runtime type checking](https://codecut.ai/beartype-fast-efficient-runtime-type-checking-for-python/)
|
|
281
|
+
- [awesome-python-typing (typeddjango)](https://github.com/typeddjango/awesome-python-typing/blob/master/README.md)
|
|
282
|
+
|
|
283
|
+
### Findings
|
|
284
|
+
|
|
285
|
+
**Two-layer model (static + runtime):**
|
|
286
|
+
|
|
287
|
+
Static analysis (mypy/pyright) catches type errors at write time. Runtime validation (pydantic/beartype) catches bad external data (MQTT payloads, API responses, HA state values) at execution time. Both layers are needed; neither replaces the other.
|
|
288
|
+
|
|
289
|
+
**Tool selection for Justin's stack:**
|
|
290
|
+
|
|
291
|
+
| Layer | Tool | Rationale |
|
|
292
|
+
|-------|------|-----------|
|
|
293
|
+
| Static | pyright (strict mode) | Faster than mypy, VSCode integration, catches `Optional` unwrapping |
|
|
294
|
+
| Runtime boundary | Pydantic v2 | Parses MQTT payloads, HA state data, Notion API responses — all external |
|
|
295
|
+
| Runtime hot paths | beartype | Zero-overhead decorator for internal functions where pydantic is too heavy |
|
|
296
|
+
| Type stubs | types-requests, types-aiofiles | Cover third-party libs without inline stubs |
|
|
297
|
+
|
|
298
|
+
**Patterns to enforce:**
|
|
299
|
+
|
|
300
|
+
1. **All public function signatures typed:** No bare `Any` without `# type: ignore` comment explaining why
|
|
301
|
+
2. **External data through Pydantic:** Any data from MQTT, HA state machine, Telegram updates, Notion API must pass through a `BaseModel` before use in business logic
|
|
302
|
+
3. **`Optional[X]` unwrapped before use:** Pyright strict mode catches `T | None` used as `T`, but the agent should verify `.get()` usage on dicts and explicit None guards
|
|
303
|
+
4. **TypedDict for dicts with known schema:** HA state attributes, MQTT payloads — `TypedDict` is lighter than `BaseModel` for read-only structures
|
|
304
|
+
|
|
305
|
+
**Detection patterns for agent:**
|
|
306
|
+
```
|
|
307
|
+
# Missing return type annotation
|
|
308
|
+
pattern: def \w+\([^)]*\)\s*:(?!\s*->)
|
|
309
|
+
# Missing argument type annotations (functions with args but no types)
|
|
310
|
+
pattern: def \w+\(\w+\s*[,)](?!\s*:\s*\w)
|
|
311
|
+
```
|
|
312
|
+
Flag untyped public functions as Nice-to-Have. Flag untyped boundary functions (ones that receive external data) as Should-Fix.
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Section 7: Synthesis — Best Patterns to Adopt
|
|
317
|
+
|
|
318
|
+
### What works, consolidated across all sources
|
|
319
|
+
|
|
320
|
+
**Detection vocabulary (what to check):**
|
|
321
|
+
|
|
322
|
+
| Anti-pattern | Detection tool | Lesson |
|
|
323
|
+
|-------------|----------------|--------|
|
|
324
|
+
| `async def` without I/O | RUF029 (preview) + agent body scan | #25, #30 |
|
|
325
|
+
| Blocking call in async | ASYNC210/ASYNC230/ASYNC251 (ruff) | #25 |
|
|
326
|
+
| `create_task` with no reference | RUF006 (ruff stable) | #43 |
|
|
327
|
+
| `create_task` with reference but no `done_callback` | Agent scan (ruff insufficient) | #43 |
|
|
328
|
+
| Missing `await` at call site | Runtime warning + agent context read | #25 |
|
|
329
|
+
| `sqlite3.connect` without `closing()` | Lesson-scanner Scan 3c | #33 |
|
|
330
|
+
| WebSocket send without try/except | Agent scan | #34 |
|
|
331
|
+
| Subscribe without stored reference | Agent scan | #37 |
|
|
332
|
+
| Subscribe without paired unsubscribe | Agent scan | #37 |
|
|
333
|
+
| Bare except with pass/return | Hookify (blocked) + lesson-scanner 3a | #7 |
|
|
334
|
+
| Exception log without `exc_info=True` | Lesson-scanner 3e | #43 |
|
|
335
|
+
| Untyped external boundary functions | Agent annotation check | — |
|
|
336
|
+
|
|
337
|
+
**Agent vs. linter division of labor:**
|
|
338
|
+
|
|
339
|
+
- **Linters (ruff, flake8-async):** Syntactic patterns with near-zero false positives. Run in pre-commit hook. Do not duplicate in agent.
|
|
340
|
+
- **Lesson-scanner agent:** Semantic patterns requiring ±context read (async def body scan, subscription teardown, create_task callback). Already exists — extend, don't replace.
|
|
341
|
+
- **Python-expert agent:** Project-specific judgment that requires understanding the codebase as a system. WebSocket lifecycle, subscriber patterns in HA context, type safety at external boundaries.
|
|
342
|
+
|
|
343
|
+
**Model selection:** sonnet for scan groups (mechanical); opus for architectural review pass (judgment). Two modes or two agents.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Section 8: Recommended Agent Structure
|
|
348
|
+
|
|
349
|
+
### Option A: Extend lesson-scanner (recommended)
|
|
350
|
+
|
|
351
|
+
Add three new scan groups to the existing `lesson-scanner.md`:
|
|
352
|
+
|
|
353
|
+
**Scan Group 7: WebSocket Lifecycle (Lesson #34)**
|
|
354
|
+
- Pattern: `await.*\.(send|recv)\(` inside `async def`
|
|
355
|
+
- Check: is it wrapped in `try: ... except.*ConnectionClosed`?
|
|
356
|
+
- Flag unguarded sends: Should-Fix
|
|
357
|
+
|
|
358
|
+
**Scan Group 8: Async SQLite (Lesson #33)**
|
|
359
|
+
- Pattern: `sqlite3\.connect\(` inside `async def`
|
|
360
|
+
- Flag: synchronous sqlite3 in async context is blocking I/O — use aiosqlite
|
|
361
|
+
- Pattern: `aiosqlite\.connect\(` outside `async with`
|
|
362
|
+
- Flag: connection not used as context manager — may not close on exception
|
|
363
|
+
|
|
364
|
+
**Scan Group 9: Type Boundary Violations**
|
|
365
|
+
- Pattern: `def \w+\([^)]*mqtt\|payload\|state\|update\|event[^)]*\)` without `BaseModel` in body
|
|
366
|
+
- Flag: external data entering business logic without Pydantic validation — Nice-to-Have
|
|
367
|
+
|
|
368
|
+
Rationale: extending lesson-scanner keeps all scan logic in one place, numbered consistently, and means `/audit` runs everything.
|
|
369
|
+
|
|
370
|
+
### Option B: Standalone python-expert agent (if scan volume grows)
|
|
371
|
+
|
|
372
|
+
Create `/home/justin/.claude/agents/python-expert.md` as a dedicated review agent that invokes lesson-scanner as a sub-step and adds deeper architectural judgment (class structure analysis, cross-file subscriber lifecycle, type coverage assessment). Use `model: opus`.
|
|
373
|
+
|
|
374
|
+
**When to choose Option B:** When you want the agent to do a full architectural review that produces recommendations, not just a violation list. If the primary use is "scan this codebase before commit," Option A is sufficient.
|
|
375
|
+
|
|
376
|
+
### Recommended config additions (pyproject.toml for all Python projects)
|
|
377
|
+
|
|
378
|
+
```toml
|
|
379
|
+
[tool.ruff]
|
|
380
|
+
target-version = "py312"
|
|
381
|
+
|
|
382
|
+
[tool.ruff.lint]
|
|
383
|
+
select = [
|
|
384
|
+
"E", "W", # pycodestyle
|
|
385
|
+
"F", # pyflakes
|
|
386
|
+
"B", # flake8-bugbear
|
|
387
|
+
"ASYNC", # flake8-async (blocking calls in async context)
|
|
388
|
+
"RUF006", # asyncio-dangling-task
|
|
389
|
+
"UP", # pyupgrade
|
|
390
|
+
"SIM", # flake8-simplify
|
|
391
|
+
]
|
|
392
|
+
# Enable when ruff preview stabilizes:
|
|
393
|
+
# "RUF029", # unused-async (async def without I/O)
|
|
394
|
+
|
|
395
|
+
[tool.ruff.lint.per-file-ignores]
|
|
396
|
+
"tests/**" = ["B"]
|
|
397
|
+
|
|
398
|
+
[tool.pyright]
|
|
399
|
+
pythonVersion = "3.12"
|
|
400
|
+
typeCheckingMode = "strict"
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Immediate next actions (ranked by impact)
|
|
404
|
+
|
|
405
|
+
1. **Add RUF006 to ruff config** in ha-aria, autonomous-coding-toolkit, and any Telegram bot repos — catches Lesson #43 create_task pattern at commit time, zero agent cost.
|
|
406
|
+
2. **Add ASYNC rules to ruff config** — catches blocking calls in async context (ASYNC210, ASYNC230, ASYNC251) without running the agent.
|
|
407
|
+
3. **Extend lesson-scanner with Scan Group 7 (WebSocket lifecycle)** — the one scan group not yet covered by any existing tool.
|
|
408
|
+
4. **Write python-expert agent** if architectural review (beyond grep patterns) is needed for ha-aria specifically — that codebase has the highest density of subscriber lifecycle complexity.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## References
|
|
413
|
+
|
|
414
|
+
- [VoltAgent/awesome-claude-code-subagents](https://github.com/VoltAgent/awesome-claude-code-subagents)
|
|
415
|
+
- [affaan-m/everything-claude-code](https://github.com/affaan-m/everything-claude-code)
|
|
416
|
+
- [python-trio/flake8-async](https://github.com/python-trio/flake8-async)
|
|
417
|
+
- [ruff rules index](https://docs.astral.sh/ruff/rules/)
|
|
418
|
+
- [ruff RUF006 asyncio-dangling-task](https://docs.astral.sh/ruff/rules/asyncio-dangling-task/)
|
|
419
|
+
- [ruff RUF029 unused-async](https://docs.astral.sh/ruff/rules/unused-async/)
|
|
420
|
+
- [semgrep-rules](https://github.com/semgrep/semgrep-rules)
|
|
421
|
+
- [quantifiedcode/python-anti-patterns](https://github.com/quantifiedcode/python-anti-patterns)
|
|
422
|
+
- [charlax/professional-programming antipatterns](https://github.com/charlax/professional-programming/blob/master/antipatterns/error-handling-antipatterns.md)
|
|
423
|
+
- [alexwlchan — sqlite3 context manager doesn't close](https://alexwlchan.net/til/2024/sqlite3-context-manager-doesnt-close-connections/)
|
|
424
|
+
- [Robin's Blog — sqlite3 gotcha](https://blog.rtwilson.com/a-python-sqlite3-context-manager-gotcha/)
|
|
425
|
+
- [HA async developer docs](https://developers.home-assistant.io/docs/asyncio_working_with_async/)
|
|
426
|
+
- [HA MQTT async example](https://github.com/home-assistant/example-custom-config/blob/master/custom_components/mqtt_basic_async/__init__.py)
|
|
427
|
+
- [websockets library docs](https://websockets.readthedocs.io/en/stable/faq/server.html)
|
|
428
|
+
- [awesome-python-typing](https://github.com/typeddjango/awesome-python-typing/blob/master/README.md)
|
|
429
|
+
- [SuperFastPython asyncio linting](https://superfastpython.com/lint-asyncio-code/)
|