agent-easy-framework 0.0.3__tar.gz

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.
Files changed (105) hide show
  1. agent_easy_framework-0.0.3/.cursor/rules/skill-orchestrator-gate.mdc +51 -0
  2. agent_easy_framework-0.0.3/.cursor/skills/adoption-validation/SKILL.md +267 -0
  3. agent_easy_framework-0.0.3/.cursor/skills/code-smell-review/SKILL.md +201 -0
  4. agent_easy_framework-0.0.3/.cursor/skills/code-smell-review/examples.md +162 -0
  5. agent_easy_framework-0.0.3/.cursor/skills/onboarding-validation/SKILL.md +134 -0
  6. agent_easy_framework-0.0.3/.cursor/skills/skill-orchestrator/SKILL.md +334 -0
  7. agent_easy_framework-0.0.3/.cursor/skills/skill-orchestrator/pipelines.md +71 -0
  8. agent_easy_framework-0.0.3/.github/branch-protection.md +17 -0
  9. agent_easy_framework-0.0.3/.github/scripts/release_publish.sh +67 -0
  10. agent_easy_framework-0.0.3/.github/workflows/build-deploy.yml +67 -0
  11. agent_easy_framework-0.0.3/.github/workflows/ci.yml +123 -0
  12. agent_easy_framework-0.0.3/.gitignore +15 -0
  13. agent_easy_framework-0.0.3/.pre-commit-config.yaml +42 -0
  14. agent_easy_framework-0.0.3/GOLDEN_PATH.md +370 -0
  15. agent_easy_framework-0.0.3/LICENSE +21 -0
  16. agent_easy_framework-0.0.3/Makefile +83 -0
  17. agent_easy_framework-0.0.3/PKG-INFO +499 -0
  18. agent_easy_framework-0.0.3/README.md +461 -0
  19. agent_easy_framework-0.0.3/config/base.yaml +25 -0
  20. agent_easy_framework-0.0.3/config/profiles/local-http.yaml +10 -0
  21. agent_easy_framework-0.0.3/config/profiles/local.yaml +6 -0
  22. agent_easy_framework-0.0.3/config/profiles/prod.yaml +32 -0
  23. agent_easy_framework-0.0.3/examples/README.md +125 -0
  24. agent_easy_framework-0.0.3/examples/call_ping.py +43 -0
  25. agent_easy_framework-0.0.3/examples/call_ping_http.py +52 -0
  26. agent_easy_framework-0.0.3/examples/smoke_ops.sh +26 -0
  27. agent_easy_framework-0.0.3/proto/agent_server.proto +35 -0
  28. agent_easy_framework-0.0.3/pyproject.toml +85 -0
  29. agent_easy_framework-0.0.3/src/agent_server/__about__.py +3 -0
  30. agent_easy_framework-0.0.3/src/agent_server/__init__.py +13 -0
  31. agent_easy_framework-0.0.3/src/agent_server/__main__.py +8 -0
  32. agent_easy_framework-0.0.3/src/agent_server/auth/__init__.py +1 -0
  33. agent_easy_framework-0.0.3/src/agent_server/auth/base.py +67 -0
  34. agent_easy_framework-0.0.3/src/agent_server/auth/basic.py +95 -0
  35. agent_easy_framework-0.0.3/src/agent_server/auth/none.py +28 -0
  36. agent_easy_framework-0.0.3/src/agent_server/auth/oidc.py +114 -0
  37. agent_easy_framework-0.0.3/src/agent_server/bootstrap.py +32 -0
  38. agent_easy_framework-0.0.3/src/agent_server/checks/__init__.py +12 -0
  39. agent_easy_framework-0.0.3/src/agent_server/checks/invariants.py +324 -0
  40. agent_easy_framework-0.0.3/src/agent_server/cli.py +56 -0
  41. agent_easy_framework-0.0.3/src/agent_server/config/__init__.py +1 -0
  42. agent_easy_framework-0.0.3/src/agent_server/config/loader.py +102 -0
  43. agent_easy_framework-0.0.3/src/agent_server/config/schema.py +61 -0
  44. agent_easy_framework-0.0.3/src/agent_server/config/secrets/__init__.py +1 -0
  45. agent_easy_framework-0.0.3/src/agent_server/config/secrets/base.py +53 -0
  46. agent_easy_framework-0.0.3/src/agent_server/config/secrets/file_provider.py +46 -0
  47. agent_easy_framework-0.0.3/src/agent_server/core/__init__.py +1 -0
  48. agent_easy_framework-0.0.3/src/agent_server/core/context.py +54 -0
  49. agent_easy_framework-0.0.3/src/agent_server/core/registry.py +155 -0
  50. agent_easy_framework-0.0.3/src/agent_server/core/tools/__init__.py +12 -0
  51. agent_easy_framework-0.0.3/src/agent_server/core/tools/example.py +28 -0
  52. agent_easy_framework-0.0.3/src/agent_server/datasources/__init__.py +1 -0
  53. agent_easy_framework-0.0.3/src/agent_server/datasources/base.py +61 -0
  54. agent_easy_framework-0.0.3/src/agent_server/datasources/neo4j.py +72 -0
  55. agent_easy_framework-0.0.3/src/agent_server/datasources/postgres.py +76 -0
  56. agent_easy_framework-0.0.3/src/agent_server/docs/__init__.py +16 -0
  57. agent_easy_framework-0.0.3/src/agent_server/docs/server.py +176 -0
  58. agent_easy_framework-0.0.3/src/agent_server/ops/__init__.py +1 -0
  59. agent_easy_framework-0.0.3/src/agent_server/ops/app.py +59 -0
  60. agent_easy_framework-0.0.3/src/agent_server/ops/schemas.py +35 -0
  61. agent_easy_framework-0.0.3/src/agent_server/py.typed +0 -0
  62. agent_easy_framework-0.0.3/src/agent_server/runtime.py +39 -0
  63. agent_easy_framework-0.0.3/src/agent_server/transports/__init__.py +55 -0
  64. agent_easy_framework-0.0.3/src/agent_server/transports/dispatch.py +28 -0
  65. agent_easy_framework-0.0.3/src/agent_server/transports/grpc/__init__.py +10 -0
  66. agent_easy_framework-0.0.3/src/agent_server/transports/grpc/agent_server_pb2.py +45 -0
  67. agent_easy_framework-0.0.3/src/agent_server/transports/grpc/agent_server_pb2_grpc.py +153 -0
  68. agent_easy_framework-0.0.3/src/agent_server/transports/grpc/server.py +110 -0
  69. agent_easy_framework-0.0.3/src/agent_server/transports/http.py +84 -0
  70. agent_easy_framework-0.0.3/src/agent_server/transports/mcp_app.py +72 -0
  71. agent_easy_framework-0.0.3/src/agent_server/transports/stdio.py +27 -0
  72. agent_easy_framework-0.0.3/src/create_agent_server/__about__.py +7 -0
  73. agent_easy_framework-0.0.3/src/create_agent_server/__init__.py +17 -0
  74. agent_easy_framework-0.0.3/src/create_agent_server/add_tool.py +167 -0
  75. agent_easy_framework-0.0.3/src/create_agent_server/cli.py +205 -0
  76. agent_easy_framework-0.0.3/src/create_agent_server/generator.py +832 -0
  77. agent_easy_framework-0.0.3/src/create_agent_server/py.typed +0 -0
  78. agent_easy_framework-0.0.3/src/create_agent_server/template_paths.py +89 -0
  79. agent_easy_framework-0.0.3/src/create_agent_server/templates/config/base.yaml +25 -0
  80. agent_easy_framework-0.0.3/src/create_agent_server/templates/config/profiles/local-http.yaml +10 -0
  81. agent_easy_framework-0.0.3/src/create_agent_server/templates/config/profiles/local.yaml +6 -0
  82. agent_easy_framework-0.0.3/src/create_agent_server/templates/config/profiles/prod.yaml +32 -0
  83. agent_easy_framework-0.0.3/src/create_agent_server/templates/examples/README.md +125 -0
  84. agent_easy_framework-0.0.3/src/create_agent_server/templates/examples/call_ping.py +43 -0
  85. agent_easy_framework-0.0.3/src/create_agent_server/templates/examples/call_ping_http.py +52 -0
  86. agent_easy_framework-0.0.3/src/create_agent_server/templates/examples/smoke_ops.sh +26 -0
  87. agent_easy_framework-0.0.3/src/create_agent_server/templates/gitignore +15 -0
  88. agent_easy_framework-0.0.3/src/create_agent_server/templates/pre-commit-config.yaml +42 -0
  89. agent_easy_framework-0.0.3/src/create_agent_server/templates/proto/agent_server.proto +35 -0
  90. agent_easy_framework-0.0.3/src/create_agent_server/templates/tools/checks/run_checks.py +63 -0
  91. agent_easy_framework-0.0.3/src/create_agent_server/templates/tools/checks/validate_typing.py +74 -0
  92. agent_easy_framework-0.0.3/tests/integration/test_generate_and_boot.py +17 -0
  93. agent_easy_framework-0.0.3/tests/unit/test_add_tool.py +82 -0
  94. agent_easy_framework-0.0.3/tests/unit/test_auth.py +68 -0
  95. agent_easy_framework-0.0.3/tests/unit/test_checks.py +111 -0
  96. agent_easy_framework-0.0.3/tests/unit/test_cli.py +85 -0
  97. agent_easy_framework-0.0.3/tests/unit/test_datasources.py +186 -0
  98. agent_easy_framework-0.0.3/tests/unit/test_foundation.py +126 -0
  99. agent_easy_framework-0.0.3/tests/unit/test_generator.py +108 -0
  100. agent_easy_framework-0.0.3/tests/unit/test_transports.py +67 -0
  101. agent_easy_framework-0.0.3/tools/checks/run_checks.py +63 -0
  102. agent_easy_framework-0.0.3/tools/checks/validate_typing.py +74 -0
  103. agent_easy_framework-0.0.3/tools/sync_generator_templates.py +48 -0
  104. agent_easy_framework-0.0.3/tools/verify_generated.py +245 -0
  105. agent_easy_framework-0.0.3/uv.lock +1366 -0
@@ -0,0 +1,51 @@
1
+ ---
2
+ description: >-
3
+ Mandatory completion gate — run skill-orchestrator after every code change
4
+ before marking a task done.
5
+ alwaysApply: true
6
+ ---
7
+
8
+ # Skill orchestrator completion gate
9
+
10
+ After **any code change** in this repo, follow [skill-orchestrator](../skills/skill-orchestrator/SKILL.md) **before** telling the user the task is done.
11
+
12
+ ## Required flow
13
+
14
+ ```
15
+ implement → skill-orchestrator → close report (Ready to ship: YES) → then done
16
+ ```
17
+
18
+ ## Triggers
19
+
20
+ Run the orchestrator when you edit:
21
+
22
+ - `src/`, `tests/`, `tools/`
23
+ - `*.py`, generator, or templates under `create_agent_server/`
24
+
25
+ If there is no git diff yet, validate the files changed in the session.
26
+
27
+ ## Blocks close
28
+
29
+ Do **not** mark the task complete while any of these fail:
30
+
31
+ - code-smell-review (must_fix > 0)
32
+ - onboarding-validation Judge (when onboarding surfaces changed)
33
+ - adoption-validation P0 escalations (when release/adoption pipeline)
34
+ - `make check` or `make test`
35
+
36
+ ## Skip (rare)
37
+
38
+ Skip only when:
39
+
40
+ - **Question-only** or read-only work — no files changed
41
+ - User **explicitly** opts out for this task — note `SKIPPED` + reason in close report
42
+
43
+ ## Minimum pipeline
44
+
45
+ Most code-only changes → **pipeline A**: smell review → `make check` → `make test`.
46
+
47
+ Docs/generator/examples → **pipeline B**. Pre-release → **pipeline C**. See [pipelines.md](../skills/skill-orchestrator/pipelines.md).
48
+
49
+ ## Close report
50
+
51
+ Before saying done, produce the orchestrator close report from the skill with `Ready to ship: YES`.
@@ -0,0 +1,267 @@
1
+ ---
2
+ name: adoption-validation
3
+ description: >-
4
+ Docs-only multi-agent adoption test: a critical platform team with no prior
5
+ context tries to scaffold and run an MCP server using only published docs.
6
+ Use before releases, after README/CLI/generator changes, or when validating
7
+ whether real teams can adopt agent-easy. Findings that need fixes must
8
+ escalate through the onboarding-validation skill — never fix from adoption
9
+ reports alone.
10
+ ---
11
+
12
+ # Adoption Validation
13
+
14
+ Simulates a **skeptical platform team** adopting `agent-easy` for the first time. Sub-agents get **no conversation context** and **no source access** — only documented entry points. They must scaffold, configure, and invoke tools exactly as a PyPI user would.
15
+
16
+ If they find problems, **do not patch the framework from this skill**. Escalate through [onboarding-validation](../onboarding-validation/SKILL.md) so each issue is proven `GENUINE_UX_CONFUSION`, not team error.
17
+
18
+ ## When to Run
19
+
20
+ - Before PyPI release or major doc/CLI changes
21
+ - After changing README quickstart, `agent-easy mcp` flags, or generator output
22
+ - User asks to "test adoption", "can a team use this from docs", or "run the adoption team"
23
+ - After adoption FAIL — only **after** onboarding-validation confirms fixes
24
+
25
+ ## Adoption bar
26
+
27
+ The team is **critical and time-poor**. They will bounce if:
28
+
29
+ - Quickstart fails on first copy-paste
30
+ - Docs contradict each other (README vs generated README vs CLI output)
31
+ - They must read `src/` to succeed
32
+ - Surfaces are confused (in-process vs MCP HTTP vs ops REST)
33
+ - Generate-time flags do not match default runtime profile without explanation
34
+
35
+ **Verdict scale:**
36
+
37
+ | Verdict | Meaning |
38
+ |---------|---------|
39
+ | **ADOPT** | Team would standardize on this from docs alone |
40
+ | **ADOPT_WITH_FRICTION** | Works but docs/process need polish (escalate items) |
41
+ | **REJECT** | Team would abandon or fork; block release until resolved |
42
+
43
+ ## Roles (all docs-only)
44
+
45
+ | Agent | Persona | Must NOT |
46
+ |-------|---------|----------|
47
+ | **Platform engineer** | Owns the golden path; runs scaffold + setup | Read `src/`, `generator.py`, or prior chat |
48
+ | **Integrator** | Wires MCP clients; runs example flows | Modify framework source |
49
+ | **Adoption critic** | Staff engineer evaluating build vs buy | Soften findings; recommend architecture rewrites |
50
+
51
+ Each agent reports **PASS/FAIL**, exact commands, exact output, and **blockers** with severity (P0/P1/P2).
52
+
53
+ ## Allowed documentation
54
+
55
+ Agents may read **only**:
56
+
57
+ | Doc | When |
58
+ |-----|------|
59
+ | `README.md` | Quickstart, flags, journey |
60
+ | `GOLDEN_PATH.md` | Only if README points there or a step fails |
61
+ | Generated `<project>/README.md` | After scaffold |
62
+ | Generated `<project>/examples/README.md` | After scaffold |
63
+ | CLI `--help` output | Flag discovery |
64
+
65
+ **Forbidden:** `src/`, `tests/`, `generator.py`, conversation history, onboarding-validation reports from prior turns (unless orchestrator passes a **minimal** judge verdict for re-test).
66
+
67
+ ## Workflow
68
+
69
+ ```
70
+ Adoption team (parallel, docs-only, no context)
71
+
72
+ Adoption lead synthesizes verdict + findings
73
+
74
+ Any finding that implies a doc/CLI/generator fix?
75
+ NO → close with verdict
76
+ YES → onboarding-validation (Junior → Judge → [Product])
77
+
78
+ Product implements only GENUINE_UX_CONFUSION items
79
+
80
+ Re-run adoption-validation until ADOPT or ADOPT_WITH_FRICTION
81
+ ```
82
+
83
+ **Never skip onboarding-validation for UX fixes suggested by the adoption team.**
84
+
85
+ ## Phase 1 — Platform engineer
86
+
87
+ **Prompt pattern (spawn with `Task`, `subagent_type: shell` or `generalPurpose`):**
88
+
89
+ ```
90
+ You are a platform engineer on a critical team adopting agent-easy for the first time.
91
+ You have NO prior context and must NOT read source code under src/ or tests/.
92
+
93
+ Read ONLY README.md "Quickstart (no clone)" (and GOLDEN_PATH.md only if README sends you there).
94
+
95
+ Goal: scaffold a minimal MCP server and reach `make example` success.
96
+
97
+ Rules:
98
+ - Use a fresh temp directory (mktemp)
99
+ - Primary command: uvx agent-easy mcp <name> (if not on PyPI, report BLOCKER and use
100
+ uv run agent-easy mcp <name> from repo root ONLY as pre-publish fallback — tag as INFRA)
101
+ - Follow CLI printed next steps, then generated project README
102
+ - Do NOT read src/
103
+ - Report PASS/FAIL, commands, output snippets, P0/P1/P2 blockers, time estimate
104
+ ```
105
+
106
+ **Pass:** `make setup` + `make example` returns pong without source reads.
107
+
108
+ ## Phase 2 — Integrator
109
+
110
+ **Input:** Path to generated project from Phase 1 (orchestrator provides).
111
+
112
+ **Prompt pattern:**
113
+
114
+ ```
115
+ You are an integrator on the same critical adoption team. NO prior context. NO src/ reads.
116
+
117
+ Read ONLY the generated project's README.md and examples/README.md.
118
+
119
+ Goal: prove documented surfaces work:
120
+ 1. In-process: make example (if not already done)
121
+ 2. Ops REST: ./examples/smoke_ops.sh (if documented) — only while server running if docs say two terminals
122
+ 3. MCP HTTP: make run-http + make example-http — ONLY if project was generated with http transport
123
+
124
+ If stdio-only project: confirm docs do NOT falsely advertise HTTP; note if team expected HTTP from parent README.
125
+
126
+ Report PASS/FAIL per surface, confusion points, P0/P1/P2 blockers.
127
+ Do NOT modify source files.
128
+ ```
129
+
130
+ **Pass:** Every surface **documented for that project shape** works or is correctly absent.
131
+
132
+ ## Phase 3 — Adoption critic
133
+
134
+ **Input:** Platform + Integrator reports (orchestrator provides).
135
+
136
+ **Prompt pattern:**
137
+
138
+ ```
139
+ You are a staff engineer deciding whether your org adopts agent-easy vs FastMCP or an internal template.
140
+ You have NO prior context. You may read README.md, GOLDEN_PATH.md, and the two sub-agent reports only.
141
+
142
+ Deliver:
143
+ - Verdict: ADOPT | ADOPT_WITH_FRICTION | REJECT
144
+ - Top 3 adoption risks (plain language)
145
+ - Each finding: severity P0/P1/P2, classification:
146
+ NEEDS_ONBOARDING_VALIDATION — might require doc/CLI/generator fix
147
+ USER_ERROR — team should have read the doc
148
+ OUT_OF_SCOPE — valid feedback but not this product's promise
149
+ - Explicit: would you approve this as your org's MCP standard today? yes/no and why
150
+
151
+ Do NOT recommend rewriting core architecture to compensate for doc gaps.
152
+ ```
153
+
154
+ ## Phase 4 — Adoption lead (orchestrator)
155
+
156
+ Synthesize the three reports:
157
+
158
+ ```markdown
159
+ # Adoption Validation Report
160
+
161
+ ## Verdict
162
+ ADOPT | ADOPT_WITH_FRICTION | REJECT
163
+
164
+ ## Team summary
165
+ [2–3 sentences]
166
+
167
+ ## Flow matrix
168
+ | Flow | Platform | Integrator | Notes |
169
+ |------|----------|------------|-------|
170
+
171
+ ## Findings
172
+ | ID | Severity | Classification | Finding | Owner |
173
+ |----|----------|----------------|---------|-------|
174
+
175
+ ## Escalation to onboarding-validation
176
+ [List only NEEDS_ONBOARDING_VALIDATION items — one line each]
177
+ ```
178
+
179
+ ## Escalation gate (mandatory)
180
+
181
+ For each finding classified **NEEDS_ONBOARDING_VALIDATION**:
182
+
183
+ 1. **Stop** — do not implement from the adoption report alone
184
+ 2. **Run** [onboarding-validation](../onboarding-validation/SKILL.md):
185
+ - Junior reproduces the failure with docs only
186
+ - Judge classifies `GENUINE_UX_CONFUSION` vs `USER_ERROR`
187
+ - Product resolves only genuine items
188
+ 3. **Re-run adoption-validation** after fixes
189
+
190
+ If Judge marks **USER_ERROR**, update the adoption report to **reject** that finding — the team was wrong, not the product.
191
+
192
+ If Judge marks **GENUINE_UX_CONFUSION**, Product implements, then onboarding-validation judge PASS, then adoption-validation re-run.
193
+
194
+ ## Subagent dispatch
195
+
196
+ Use `Task` tool. **Do not pass conversation history** to sub-agents. Pass only:
197
+
198
+ - Allowed doc paths (absolute)
199
+ - Generated project path (after scaffold)
200
+ - Pre-publish note if `uvx` unavailable: `"PyPI not published; platform engineer may use uv run from <repo> as INFRA fallback"`
201
+
202
+ Suggested order:
203
+
204
+ 1. Platform engineer — foreground
205
+ 2. Integrator — after scaffold path known (foreground; background if long-running server)
206
+ 3. Adoption critic — after 1+2 complete
207
+ 4. Orchestrator writes report + escalation list
208
+
209
+ For HTTP flows, generate with:
210
+
211
+ ```bash
212
+ uvx agent-easy mcp adopt-http-test --transports stdio,http
213
+ ```
214
+
215
+ Run a **second** integrator pass on that project if parent README advertises HTTP.
216
+
217
+ ## Scenarios to cover
218
+
219
+ | Scenario | Generate command | Proves |
220
+ |----------|------------------|--------|
221
+ | Default quickstart | `agent-easy mcp my-service` | README hero path |
222
+ | Production-shaped | `--datasources neo4j --transports stdio,http --auth oidc` | Flagship example + secrets note |
223
+ | HTTP integrator | `--transports stdio,http` | MCP HTTP + ops distinction |
224
+
225
+ Minimum release bar: **default quickstart** scenario reaches **ADOPT** or **ADOPT_WITH_FRICTION** with zero P0 NEEDS_ONBOARDING_VALIDATION items open.
226
+
227
+ ## Quality gate after adoption PASS
228
+
229
+ When verdict is ADOPT or ADOPT_WITH_FRICTION and no open escalations:
230
+
231
+ ```bash
232
+ make sync-templates # if generator or templates changed during fix loop
233
+ make check
234
+ make test
235
+ ```
236
+
237
+ ## Relationship to onboarding-validation
238
+
239
+ | Skill | Question |
240
+ |-------|----------|
241
+ | **adoption-validation** | Would a **critical team** adopt this from docs? |
242
+ | **onboarding-validation** | Can a **junior** copy-paste each integration flow? |
243
+
244
+ Adoption is broader and stricter in tone. Onboarding is the **appeals court** for whether adoption findings deserve product changes.
245
+
246
+ ## Related skills
247
+
248
+ - **[skill-orchestrator](../skill-orchestrator/SKILL.md)** — runs adoption last on release pipelines; manages escalation back to onboarding
249
+
250
+ ## Anti-patterns
251
+
252
+ - Fixing docs/code directly from adoption critic without Judge confirmation
253
+ - Giving sub-agents repo context or prior chat ("we just changed the CLI…")
254
+ - Letting the team read `src/` when stuck — that hides doc gaps
255
+ - REJECT verdict → rewrite architecture instead of fixing docs/onboarding
256
+ - PASS adoption when `uvx` is documented but PyPI package is missing (tag INFRA P0, verdict at most ADOPT_WITH_FRICTION)
257
+ - Skipping integrator because platform engineer already ran `make example`
258
+
259
+ ## Example orchestrator close
260
+
261
+ ```
262
+ Adoption verdict: ADOPT_WITH_FRICTION
263
+ Escalations: 1 (profile override unclear — NEEDS_ONBOARDING_VALIDATION)
264
+ → Running onboarding-validation on item #1…
265
+ → Judge: GENUINE_UX_CONFUSION → Product adds README note → onboarding PASS
266
+ → Re-run adoption-validation → ADOPT
267
+ ```
@@ -0,0 +1,201 @@
1
+ ---
2
+ name: code-smell-review
3
+ description: >-
4
+ Sub-agent gate that reviews diff hunks for code smells, comment noise,
5
+ over-defensive fallbacks, and assertiveness gaps. Invoked by
6
+ skill-orchestrator after every code change — do not mark work complete
7
+ without orchestrator PASS. Also use when the user asks for a smell review
8
+ directly.
9
+ ---
10
+
11
+ # Code Smell Review
12
+
13
+ Structured sub-agent workflow: parent implements → **reviewer sub-agent** inspects **diff hunks only** → parent fixes → repeat until reviewer **PASS**.
14
+
15
+ The reviewer is isolated by design (fresh sub-agent, no conversation history). It reports findings; the parent applies fixes. **Do not mark work complete until the reviewer passes.**
16
+
17
+ ## When to Run
18
+
19
+ Run via **[skill-orchestrator](../skill-orchestrator/SKILL.md)** after every code change (default path).
20
+
21
+ Standalone (orchestrator bypass only if user explicitly opts out):
22
+
23
+ - User asks to "review for smells", "check comments", or "run smell gate"
24
+
25
+ ## Roles
26
+
27
+ | Agent | Role | Must NOT |
28
+ |-------|------|----------|
29
+ | **Parent** | Implement features, apply reviewer fixes | Skip the gate or dismiss findings without fixing |
30
+ | **Smell reviewer** | Inspect diff hunks, return PASS/FAIL + findings | Edit files, see conversation history, rationalize parent choices |
31
+
32
+ ## Workflow
33
+
34
+ ```
35
+ Parent implements → Smell reviewer (diff hunks) → [Parent fixes if FAIL] → repeat until PASS
36
+ ```
37
+
38
+ ### 1. Resolve diff scope
39
+
40
+ Use **diff hunks only** — added/changed/removed lines in the current change set:
41
+
42
+ ```bash
43
+ git diff HEAD # unstaged + staged vs last commit
44
+ git diff --cached # staged only (if relevant)
45
+ git diff origin/main...HEAD # branch vs base, when preparing a PR
46
+ ```
47
+
48
+ Pass the reviewer **only the diff output** (or equivalent patch). Do not include conversation rationale, task description, or "why I did this" unless a finding requires one line of file context to identify a symbol.
49
+
50
+ ### 2. Launch smell reviewer sub-agent
51
+
52
+ Use `Task` with `subagent_type: generalPurpose`. Prompt must state:
53
+
54
+ - **Read-only** — do not modify files
55
+ - **Input** — the diff hunks only
56
+ - **No bias** — do not assume the change is correct; flag real issues
57
+ - **Output** — structured PASS/FAIL report (template below)
58
+
59
+ Suggested model: mid-tier / fast reviewer model when available.
60
+
61
+ ### 3. Parent fixes findings
62
+
63
+ For each `FAIL` finding classified **actionable**:
64
+
65
+ - Fix in a separate pass (rename, delete comment, flatten nesting, remove fallback, etc.)
66
+ - Re-run the reviewer on the **updated diff**
67
+ - Repeat until **PASS**
68
+
69
+ Skip only findings explicitly marked `false_positive` with one-line justification in the reviewer report. Do not bulk-ignore categories.
70
+
71
+ ### 4. Close the task
72
+
73
+ After reviewer **PASS**, proceed with tests/lint as usual. The smell gate is a prerequisite to "done", not a substitute for `make check`.
74
+
75
+ ## Smell checklist
76
+
77
+ Review **every added/changed hunk** for:
78
+
79
+ ### Comments
80
+
81
+ - **Delete**: comments that narrate **what** the next lines do (`# increment counter`, `# return result`)
82
+ - **Delete**: change narration (`# added for ticket X`, `# as requested`, `# TODO: clean up later` with no concrete constraint)
83
+ - **Delete**: section-header comments (`# --- Setup ---`, `# ===== Helpers =====`)
84
+ - **Delete**: comments restating obvious control flow (`# if user exists`, `# loop through items`)
85
+ - **Keep**: non-obvious **why** — hidden constraints, subtle invariants, required workarounds, external API quirks
86
+ - **Keep**: public API docstrings on exported surfaces; inline noise is the primary target
87
+
88
+ **Test:** If deleting the comment loses no information a reader couldn't get from names and structure, flag it.
89
+
90
+ ### Naming
91
+
92
+ - Flag identifiers that **require** a comment to understand (`data2`, `temp`, `handle_stuff`)
93
+ - Prefer rename over comment
94
+
95
+ ### Complexity
96
+
97
+ - Deep nesting (3+ levels): ternaries, if/else chains, nested switches
98
+ - Functions doing too much (long blocks, multiple unrelated responsibilities)
99
+ - God objects / modules accumulating unrelated helpers
100
+
101
+ ### Duplication
102
+
103
+ - Copy-paste with slight variation that should unify
104
+ - Inline logic that duplicates an existing utility in the codebase (note the existing symbol if visible from the hunk's imports/calls)
105
+
106
+ ### Over-defensive code
107
+
108
+ - Redundant null/empty checks when types or callers already guarantee the value
109
+ - Excessive try/except that swallows errors or hides bugs
110
+ - Checks-before-use (existence probes) when operating and handling failure is clearer
111
+
112
+ ### Assertive over fallbacks
113
+
114
+ - **Flag**: silent fallbacks when a required resource, config, path, or dependency is missing (`get(..., default)`, `or ""`, `if x else fallback_value`, broad except + continue)
115
+ - **Prefer**: assert preconditions, raise explicit errors, fail fast with clear messages
116
+ - **Exception**: user-facing optional features with documented defaults — still flag if the fallback hides misconfiguration
117
+
118
+ ### AI slop patterns
119
+
120
+ - One-off helpers used once
121
+ - Unnecessary abstraction layers (wrapper classes, indirection with no second use)
122
+ - Verbose error strings that repeat the function name and obvious context
123
+ - Defensive comments apologizing for the code
124
+
125
+ ## Reviewer output template
126
+
127
+ ```markdown
128
+ # Code Smell Review
129
+
130
+ **Verdict:** PASS | FAIL
131
+ **Diff scope:** [command used, e.g. git diff HEAD]
132
+ **Hunks reviewed:** N
133
+
134
+ ## Findings
135
+
136
+ | # | Severity | Category | Location | Issue | Suggested fix |
137
+ |---|----------|----------|----------|-------|---------------|
138
+ | 1 | must_fix | comments | path:line | narrates obvious loop | delete comment |
139
+ | 2 | must_fix | fallbacks | path:line | `or "default"` hides missing config | raise ValueError with key name |
140
+
141
+ ## Summary
142
+
143
+ - must_fix: N
144
+ - suggestion: N
145
+ - false_positive: N (with justification)
146
+
147
+ ## Pass criteria
148
+
149
+ PASS only when **must_fix = 0** for the current diff.
150
+ ```
151
+
152
+ **Severity:**
153
+
154
+ | Level | Meaning |
155
+ |-------|---------|
156
+ | `must_fix` | Blocks PASS — parent must fix and re-run |
157
+ | `suggestion` | Does not block PASS; parent may fix or defer explicitly |
158
+ | `false_positive` | Reviewer self-correction with justification |
159
+
160
+ Default: comment noise, fallbacks, and assertiveness gaps are **`must_fix`**, not suggestions.
161
+
162
+ ## Subagent dispatch
163
+
164
+ ```
165
+ Task(subagent_type: generalPurpose, readonly via prompt)
166
+
167
+ Prompt:
168
+ You are the smell reviewer. Read-only. Do not edit files.
169
+
170
+ Input: the git diff below (hunks only). No conversation context.
171
+
172
+ Apply the checklist in code-smell-review skill:
173
+ - comment noise (what/change/section headers bad; why/docstrings ok)
174
+ - naming, complexity, duplication, over-defensive code
175
+ - assertive over fallbacks (no silent defaults for required things)
176
+ - AI slop patterns
177
+
178
+ Return the structured PASS/FAIL report. Be strict on must_fix items.
179
+ Do not praise the code. Do not explain your process.
180
+
181
+ <DIFF>
182
+ ...
183
+ </DIFF>
184
+ ```
185
+
186
+ Re-run after each fix pass with the fresh diff until PASS.
187
+
188
+ ## Anti-patterns
189
+
190
+ - Parent skipping the gate because "the change is small"
191
+ - Feeding the reviewer full files instead of diff hunks
192
+ - Including conversation history in the reviewer prompt ( biases toward PASS)
193
+ - Marking work done on FAIL with "user can fix later"
194
+ - Replacing a fallback with an empty string instead of raising
195
+ - Adding comments to explain bad names instead of renaming
196
+
197
+ ## Related skills
198
+
199
+ - **[skill-orchestrator](../skill-orchestrator/SKILL.md)** — runs this skill in the correct pipeline order before close
200
+ - **ce-simplify-code** — broader simplification (reuse, efficiency); run smell review first or after, not as a substitute
201
+ - **ce-code-review** — full PR review with security/correctness personas; smell gate is a pre-merge hygiene check on agent-written diffs
@@ -0,0 +1,162 @@
1
+ # Code Smell Review — Examples
2
+
3
+ Calibration examples for the smell reviewer. **Flag the bad; leave the good alone.**
4
+
5
+ ## Comments
6
+
7
+ ### Bad — narrates what
8
+
9
+ ```python
10
+ # Get the user from the database
11
+ user = db.get_user(user_id)
12
+
13
+ # Return early if not found
14
+ if user is None:
15
+ return None
16
+ ```
17
+
18
+ **Fix:** Delete both comments. Names and structure are enough.
19
+
20
+ ### Bad — change narration
21
+
22
+ ```python
23
+ # Added per review feedback — validate port range
24
+ if not 1 <= port <= 65535:
25
+ raise ValueError(f"port out of range: {port}")
26
+ ```
27
+
28
+ **Fix:** Delete the comment. The raise message is sufficient.
29
+
30
+ ### Bad — section header
31
+
32
+ ```python
33
+ # --- HTTP transport setup ---
34
+
35
+ def bind_http_server(host: str, port: int) -> None:
36
+ ...
37
+ ```
38
+
39
+ **Fix:** Delete the header. Use a function name or module structure instead.
40
+
41
+ ### Good — non-obvious why
42
+
43
+ ```python
44
+ # MCP streamable HTTP requires session id before tool calls (spec 2025-03).
45
+ await client.initialize()
46
+ ```
47
+
48
+ **Keep:** Documents an external constraint not visible from code alone.
49
+
50
+ ### Good — public docstring
51
+
52
+ ```python
53
+ def add_tool(package: str, name: str, *, overwrite: bool = False) -> Path:
54
+ """Register a new tool module and wire it into the package registry."""
55
+ ```
56
+
57
+ **Keep:** Public API surface; not inline noise.
58
+
59
+ ---
60
+
61
+ ## Assertive over fallbacks
62
+
63
+ ### Bad — silent default hides misconfiguration
64
+
65
+ ```python
66
+ def load_profile(name: str) -> dict:
67
+ path = os.environ.get("AGENT_EASY_PROFILE") or "local"
68
+ ...
69
+ ```
70
+
71
+ **Fix:** Require explicit config or raise:
72
+
73
+ ```python
74
+ def load_profile(name: str) -> dict:
75
+ path = os.environ["AGENT_EASY_PROFILE"] # or explicit arg with no env fallback
76
+ ...
77
+ ```
78
+
79
+ ### Bad — swallow and continue
80
+
81
+ ```python
82
+ try:
83
+ registry.register(tool)
84
+ except Exception:
85
+ pass # tool might already exist
86
+ ```
87
+
88
+ **Fix:** Catch the specific exception or check registration state; re-raise or raise a clear error.
89
+
90
+ ### OK — documented optional with explicit default
91
+
92
+ ```python
93
+ def create_server(*, port: int = 8000) -> Server:
94
+ """Start HTTP MCP on ``port`` (default 8000 for local dev)."""
95
+ ```
96
+
97
+ **Keep:** Default is part of the public contract, not a hidden fallback for missing config.
98
+
99
+ ---
100
+
101
+ ## Complexity & naming
102
+
103
+ ### Bad — name forces comment
104
+
105
+ ```python
106
+ def process(data: list[dict]) -> list[dict]:
107
+ # Filter active items and map to ids
108
+ return [x["id"] for x in data if x.get("active")]
109
+ ```
110
+
111
+ **Fix:** Rename and delete comment:
112
+
113
+ ```python
114
+ def active_item_ids(items: list[dict]) -> list[str]:
115
+ return [item["id"] for item in items if item["active"]]
116
+ ```
117
+
118
+ (Also flags defensive `.get("active")` if `active` is required — use direct access or validate upstream.)
119
+
120
+ ### Bad — deep nesting
121
+
122
+ ```python
123
+ result = (
124
+ fetch_a()
125
+ if cond_a
126
+ else fetch_b()
127
+ if cond_b
128
+ else fetch_c()
129
+ )
130
+ ```
131
+
132
+ **Fix:** Early returns or if/elif chain with named intermediate values.
133
+
134
+ ---
135
+
136
+ ## AI slop
137
+
138
+ ### Bad — unnecessary helper
139
+
140
+ ```python
141
+ def _normalize_name(name: str) -> str:
142
+ return name.strip().lower()
143
+
144
+ def register(name: str) -> None:
145
+ register_impl(_normalize_name(name))
146
+ ```
147
+
148
+ **Fix:** Inline if used once, or move to a shared util if the pattern repeats elsewhere.
149
+
150
+ ### Bad — verbose error
151
+
152
+ ```python
153
+ raise ValueError(
154
+ "register_tool failed because the tool name parameter was invalid or empty"
155
+ )
156
+ ```
157
+
158
+ **Fix:**
159
+
160
+ ```python
161
+ raise ValueError(f"tool name must be non-empty, got {name!r}")
162
+ ```