ma-agents 2.20.3 → 2.22.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/.opencode/skills/.ma-agents.json +241 -0
- package/.opencode/skills/MANIFEST.yaml +254 -0
- package/.opencode/skills/ai-audit-trail/SKILL.md +23 -0
- package/.opencode/skills/auto-bug-detection/SKILL.md +169 -0
- package/.opencode/skills/cmake-best-practices/SKILL.md +64 -0
- package/.opencode/skills/cmake-best-practices/examples/cmake.md +59 -0
- package/.opencode/skills/code-documentation/SKILL.md +57 -0
- package/.opencode/skills/code-documentation/examples/cpp.md +29 -0
- package/.opencode/skills/code-documentation/examples/csharp.md +28 -0
- package/.opencode/skills/code-documentation/examples/javascript_typescript.md +28 -0
- package/.opencode/skills/code-documentation/examples/python.md +57 -0
- package/.opencode/skills/code-review/SKILL.md +43 -0
- package/.opencode/skills/commit-message/SKILL.md +79 -0
- package/.opencode/skills/cpp-best-practices/SKILL.md +234 -0
- package/.opencode/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
- package/.opencode/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
- package/.opencode/skills/cpp-concurrency-safety/SKILL.md +60 -0
- package/.opencode/skills/cpp-concurrency-safety/examples/concurrency.md +73 -0
- package/.opencode/skills/cpp-const-correctness/SKILL.md +63 -0
- package/.opencode/skills/cpp-const-correctness/examples/const_correctness.md +54 -0
- package/.opencode/skills/cpp-memory-handling/SKILL.md +42 -0
- package/.opencode/skills/cpp-memory-handling/examples/modern-cpp.md +49 -0
- package/.opencode/skills/cpp-memory-handling/examples/smart-pointers.md +46 -0
- package/.opencode/skills/cpp-modern-composition/SKILL.md +64 -0
- package/.opencode/skills/cpp-modern-composition/examples/composition.md +51 -0
- package/.opencode/skills/cpp-robust-interfaces/SKILL.md +55 -0
- package/.opencode/skills/cpp-robust-interfaces/examples/interfaces.md +56 -0
- package/.opencode/skills/create-hardened-docker-skill/SKILL.md +637 -0
- package/.opencode/skills/create-hardened-docker-skill/scripts/create-all.sh +489 -0
- package/.opencode/skills/csharp-best-practices/SKILL.md +278 -0
- package/.opencode/skills/docker-hardening-verification/SKILL.md +28 -0
- package/.opencode/skills/docker-hardening-verification/scripts/verify-hardening.sh +39 -0
- package/.opencode/skills/docker-image-signing/SKILL.md +28 -0
- package/.opencode/skills/docker-image-signing/scripts/sign-image.sh +33 -0
- package/.opencode/skills/document-revision-history/SKILL.md +104 -0
- package/.opencode/skills/git-workflow-skill/SKILL.md +194 -0
- package/.opencode/skills/git-workflow-skill/hooks/commit-msg +61 -0
- package/.opencode/skills/git-workflow-skill/hooks/pre-commit +38 -0
- package/.opencode/skills/git-workflow-skill/hooks/prepare-commit-msg +56 -0
- package/.opencode/skills/git-workflow-skill/scripts/finish-feature.sh +192 -0
- package/.opencode/skills/git-workflow-skill/scripts/install-hooks.sh +55 -0
- package/.opencode/skills/git-workflow-skill/scripts/start-feature.sh +110 -0
- package/.opencode/skills/git-workflow-skill/scripts/validate-workflow.sh +229 -0
- package/.opencode/skills/js-ts-dependency-mgmt/SKILL.md +49 -0
- package/.opencode/skills/js-ts-dependency-mgmt/examples/dependency_mgmt.md +60 -0
- package/.opencode/skills/js-ts-security-skill/SKILL.md +64 -0
- package/.opencode/skills/js-ts-security-skill/scripts/verify-security.sh +136 -0
- package/.opencode/skills/logging-best-practices/SKILL.md +50 -0
- package/.opencode/skills/logging-best-practices/examples/cpp.md +36 -0
- package/.opencode/skills/logging-best-practices/examples/csharp.md +49 -0
- package/.opencode/skills/logging-best-practices/examples/javascript.md +77 -0
- package/.opencode/skills/logging-best-practices/examples/python.md +57 -0
- package/.opencode/skills/logging-best-practices/references/logging-standards.md +29 -0
- package/.opencode/skills/open-presentation/SKILL.md +35 -0
- package/.opencode/skills/opentelemetry-best-practices/SKILL.md +34 -0
- package/.opencode/skills/opentelemetry-best-practices/examples/go.md +32 -0
- package/.opencode/skills/opentelemetry-best-practices/examples/javascript.md +58 -0
- package/.opencode/skills/opentelemetry-best-practices/examples/python.md +37 -0
- package/.opencode/skills/opentelemetry-best-practices/references/otel-standards.md +37 -0
- package/.opencode/skills/python-best-practices/SKILL.md +385 -0
- package/.opencode/skills/python-dependency-mgmt/SKILL.md +42 -0
- package/.opencode/skills/python-dependency-mgmt/examples/dependency_mgmt.md +67 -0
- package/.opencode/skills/python-security-skill/SKILL.md +56 -0
- package/.opencode/skills/python-security-skill/examples/security.md +56 -0
- package/.opencode/skills/self-signed-cert/SKILL.md +42 -0
- package/.opencode/skills/self-signed-cert/scripts/generate-cert.ps1 +45 -0
- package/.opencode/skills/self-signed-cert/scripts/generate-cert.sh +43 -0
- package/.opencode/skills/skill-creator/SKILL.md +196 -0
- package/.opencode/skills/skill-creator/references/output-patterns.md +82 -0
- package/.opencode/skills/skill-creator/references/workflows.md +28 -0
- package/.opencode/skills/skill-creator/scripts/init_skill.py +208 -0
- package/.opencode/skills/skill-creator/scripts/package_skill.py +99 -0
- package/.opencode/skills/skill-creator/scripts/quick_validate.py +113 -0
- package/.opencode/skills/story-status-lookup/SKILL.md +78 -0
- package/.opencode/skills/test-accompanied-development/SKILL.md +50 -0
- package/.opencode/skills/test-generator/SKILL.md +65 -0
- package/.opencode/skills/vercel-react-best-practices/SKILL.md +109 -0
- package/.opencode/skills/verify-hardened-docker-skill/SKILL.md +442 -0
- package/.opencode/skills/verify-hardened-docker-skill/scripts/verify-docker-hardening.sh +439 -0
- package/AiAudit.md +5 -0
- package/QUICK_START.md +11 -5
- package/README.md +52 -1
- package/bin/cli.js +31 -4
- package/docs/BMAD_AI_Development_Training.pptx +0 -0
- package/docs/technical-notes/context-persistence-research.md +434 -0
- package/docs/technical-notes/enforcement-hooks-research.md +415 -0
- package/lib/agents.js +34 -0
- package/lib/bmad-extension/agents/bmm-architect.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-bmad-master.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-cyber.customize.yaml +30 -0
- package/lib/bmad-extension/agents/bmm-dev.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-devops.customize.yaml +30 -0
- package/lib/bmad-extension/agents/bmm-mil498.customize.yaml +42 -0
- package/lib/bmad-extension/agents/bmm-pm.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-qa.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-sm.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-sre.customize.yaml +30 -0
- package/lib/bmad-extension/agents/bmm-tech-writer.customize.yaml +5 -0
- package/lib/bmad-extension/agents/bmm-ux-designer.customize.yaml +5 -0
- package/lib/bmad-extension/module-help.csv +7 -0
- package/lib/bmad-extension/module.yaml +3 -0
- package/lib/bmad-extension/workflows/add-sprint/workflow.md +112 -0
- package/lib/bmad-extension/workflows/add-to-sprint/workflow.md +206 -0
- package/lib/bmad-extension/workflows/create-bug-story/workflow.md +186 -0
- package/lib/bmad-extension/workflows/modify-sprint/workflow.md +250 -0
- package/lib/bmad-extension/workflows/project-context-expansion/workflow.md +229 -0
- package/lib/bmad-extension/workflows/sprint-status-view/workflow.md +193 -0
- package/lib/bmad.js +168 -36
- package/lib/hooks/claude-code/verify-manifest.js +56 -0
- package/lib/installer.js +282 -1
- package/lib/methodology/BMAD_AI_Development_Training.pptx +0 -0
- package/lib/methodology/version.json +7 -0
- package/lib/skill-authoring.js +732 -0
- package/lib/templates/project-context.template.md +47 -0
- package/opencode.json +8 -0
- package/package.json +2 -2
- package/skills/auto-bug-detection/SKILL.md +165 -0
- package/skills/auto-bug-detection/skill.json +8 -0
- package/skills/code-review/SKILL.md +40 -0
- package/skills/cpp-best-practices/SKILL.md +230 -0
- package/skills/cpp-best-practices/examples/modern-idioms.md +189 -0
- package/skills/cpp-best-practices/examples/naming-and-organization.md +102 -0
- package/skills/cpp-best-practices/skill.json +25 -0
- package/skills/csharp-best-practices/SKILL.md +274 -0
- package/skills/csharp-best-practices/skill.json +23 -0
- package/skills/git-workflow-skill/skill.json +1 -1
- package/skills/open-presentation/SKILL.md +31 -0
- package/skills/open-presentation/skill.json +11 -0
- package/skills/python-best-practices/SKILL.md +381 -0
- package/skills/python-best-practices/skill.json +26 -0
- package/skills/story-status-lookup/SKILL.md +74 -0
- package/skills/story-status-lookup/skill.json +8 -0
- package/test/agent-injection-strategy.test.js +13 -7
- package/test/bmad-extension.test.js +237 -0
- package/test/bmad-output-policy.test.js +119 -0
- package/test/build-bmad-args.test.js +361 -0
- package/test/create-agent.test.js +232 -0
- package/test/enforcement-hooks.test.js +324 -0
- package/test/generate-project-context.test.js +337 -0
- package/test/integration-verification.test.js +402 -0
- package/test/opencode-agent.test.js +150 -0
- package/test/opencode-json-error.test.js +260 -0
- package/test/opencode-json-injection.test.js +256 -0
- package/test/opencode-json-merge.test.js +299 -0
- package/test/skill-authoring.test.js +272 -0
- package/test/skill-customize-agent.test.js +253 -0
- package/test/skill-mandatory.test.js +235 -0
- package/test/skill-validation.test.js +378 -0
- package/test/yes-flag.test.js +1 -1
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# Python Best Practices
|
|
2
|
+
|
|
3
|
+
Coding standards for modern Python (3.10+). This skill covers language-level patterns, type hinting, async conventions, and packaging. For security and dependency hardening, see the cross-referenced skills at the end of this document.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Naming Conventions (PEP 8)
|
|
8
|
+
|
|
9
|
+
**Rule:** Use consistent naming to maximize readability and tooling compatibility.
|
|
10
|
+
|
|
11
|
+
| Element | Convention | Example |
|
|
12
|
+
|---------|-----------|---------|
|
|
13
|
+
| Module / package | `snake_case` | `order_service`, `user_auth` |
|
|
14
|
+
| Function / method | `snake_case` | `get_customer()`, `parse_response()` |
|
|
15
|
+
| Variable | `snake_case` | `customer_count`, `is_active` |
|
|
16
|
+
| Class | `PascalCase` | `CustomerService`, `OrderItem` |
|
|
17
|
+
| Exception | `PascalCase` + `Error`/`Exception` | `NotFoundError`, `ValidationException` |
|
|
18
|
+
| Constant | `UPPER_SNAKE_CASE` | `MAX_RETRY_COUNT`, `DEFAULT_TIMEOUT` |
|
|
19
|
+
| Type alias | `PascalCase` | `CustomerList`, `JsonPayload` |
|
|
20
|
+
| Private identifier | leading `_` | `_internal_helper()`, `_cache` |
|
|
21
|
+
| Dunder / magic | leading and trailing `__` | `__init__`, `__repr__` |
|
|
22
|
+
|
|
23
|
+
- Do not abbreviate names unless the abbreviation is universally understood in the domain (`url`, `id`, `db`).
|
|
24
|
+
- Avoid single-letter names except for short-lived loop indices (`i`, `j`) or mathematical variables.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Code Organization
|
|
29
|
+
|
|
30
|
+
**Rule:** Keep modules focused; make boundaries explicit via `__all__`.
|
|
31
|
+
|
|
32
|
+
- One logical concept per module; group related modules into packages with `__init__.py`.
|
|
33
|
+
- Declare `__all__` in any module intended for public consumption to control the exported API.
|
|
34
|
+
- Standard import order (enforced by `ruff`): stdlib → third-party → local. One blank line between each group.
|
|
35
|
+
- Use absolute imports; avoid relative imports except within a tightly coupled sub-package.
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
# __init__.py — explicit public surface
|
|
39
|
+
from .service import CustomerService
|
|
40
|
+
from .models import Customer, Address
|
|
41
|
+
|
|
42
|
+
__all__ = ["CustomerService", "Customer", "Address"]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3. Type Hinting (3.10+)
|
|
48
|
+
|
|
49
|
+
**Rule:** Annotate all public function signatures and module-level variables. Use modern syntax.
|
|
50
|
+
|
|
51
|
+
### 3.1 Modern Syntax Table
|
|
52
|
+
|
|
53
|
+
| Pattern | Pre-3.10 (avoid) | Modern 3.10+ (use) |
|
|
54
|
+
|---------|-----------------|-------------------|
|
|
55
|
+
| Union types | `Union[str, int]` | `str \| int` |
|
|
56
|
+
| Optional | `Optional[str]` | `str \| None` |
|
|
57
|
+
| List | `List[str]` | `list[str]` |
|
|
58
|
+
| Dict | `Dict[str, int]` | `dict[str, int]` |
|
|
59
|
+
| Tuple | `Tuple[str, ...]` | `tuple[str, ...]` |
|
|
60
|
+
| Set | `Set[int]` | `set[int]` |
|
|
61
|
+
| Type alias (3.12+) | `MyType = list[str]` | `type MyType = list[str]` |
|
|
62
|
+
| Callable | `Callable[[int], str]` | `Callable[[int], str]` (unchanged) |
|
|
63
|
+
|
|
64
|
+
### 3.2 Advanced Typing Constructs
|
|
65
|
+
|
|
66
|
+
- **`TypeAlias`** (3.10): use for readability when the alias is used in multiple places but you cannot yet use the `type` statement.
|
|
67
|
+
- **`TypeVar`**: constrain generic functions to a family of types.
|
|
68
|
+
- **`ParamSpec`** (3.10): preserve parameter types in higher-order functions and decorators.
|
|
69
|
+
- **`Protocol`**: define structural (duck-typed) interfaces; prefer over ABC for external or loosely coupled types.
|
|
70
|
+
- **`TypeGuard`** (3.10): narrow types in user-defined type guard functions.
|
|
71
|
+
- **`Self`** (3.11): annotate methods that return the instance's own type (replaces `TypeVar("T", bound="MyClass")`).
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from typing import TypeVar, ParamSpec, Protocol, TypeGuard
|
|
75
|
+
from typing import Self # 3.11+
|
|
76
|
+
|
|
77
|
+
T = TypeVar("T")
|
|
78
|
+
P = ParamSpec("P")
|
|
79
|
+
|
|
80
|
+
class Comparable(Protocol):
|
|
81
|
+
def __lt__(self, other: Self) -> bool: ...
|
|
82
|
+
|
|
83
|
+
def is_string_list(val: list[object]) -> TypeGuard[list[str]]:
|
|
84
|
+
return all(isinstance(x, str) for x in val)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3.3 Variable Annotations
|
|
88
|
+
|
|
89
|
+
Annotate module-level and class-level variables; omit annotations for obvious local assignments.
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Module-level
|
|
93
|
+
MAX_CONNECTIONS: int = 100
|
|
94
|
+
_cache: dict[str, bytes] = {}
|
|
95
|
+
|
|
96
|
+
# Class-level (with __slots__ for memory efficiency)
|
|
97
|
+
class Point:
|
|
98
|
+
__slots__ = ("x", "y")
|
|
99
|
+
x: float
|
|
100
|
+
y: float
|
|
101
|
+
|
|
102
|
+
def __init__(self, x: float, y: float) -> None:
|
|
103
|
+
self.x = x
|
|
104
|
+
self.y = y
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 4. Modern Python Patterns
|
|
110
|
+
|
|
111
|
+
### 4.1 Structural Pattern Matching (3.10)
|
|
112
|
+
|
|
113
|
+
Use `match/case` to replace complex `if/elif` chains on structured data.
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
def handle_event(event: dict) -> str:
|
|
117
|
+
match event:
|
|
118
|
+
case {"type": "click", "button": button}:
|
|
119
|
+
return f"Clicked {button}"
|
|
120
|
+
case {"type": "keypress", "key": key} if key.isalpha():
|
|
121
|
+
return f"Key pressed: {key}"
|
|
122
|
+
case {"type": "resize", "width": w, "height": h}:
|
|
123
|
+
return f"Resized to {w}x{h}"
|
|
124
|
+
case _:
|
|
125
|
+
return "Unknown event"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Prefer `match/case` over `isinstance` chains when dispatching on data shape; avoid it for simple boolean conditions.
|
|
129
|
+
|
|
130
|
+
### 4.2 Exception Groups and `except*` (3.11)
|
|
131
|
+
|
|
132
|
+
`ExceptionGroup` allows multiple unrelated exceptions to propagate together; `except*` handles them selectively.
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
import asyncio
|
|
136
|
+
|
|
137
|
+
async def gather_tasks() -> None:
|
|
138
|
+
async with asyncio.TaskGroup() as tg:
|
|
139
|
+
tg.create_task(fetch_user())
|
|
140
|
+
tg.create_task(fetch_orders())
|
|
141
|
+
# TaskGroup raises ExceptionGroup if any task fails
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
await gather_tasks()
|
|
145
|
+
except* ValueError as eg:
|
|
146
|
+
for exc in eg.exceptions:
|
|
147
|
+
print(f"Validation error: {exc}")
|
|
148
|
+
except* IOError as eg:
|
|
149
|
+
for exc in eg.exceptions:
|
|
150
|
+
print(f"IO error: {exc}")
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 4.3 F-String Improvements (3.12)
|
|
154
|
+
|
|
155
|
+
3.12 removes restrictions on f-string content: nested quotes, backslashes, and complex expressions are now valid.
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
# 3.12: nested quotes and backslashes inside f-strings
|
|
159
|
+
name = "world"
|
|
160
|
+
msg = f"Hello, {name!r}"
|
|
161
|
+
path = f"{'\\'.join(['a', 'b', 'c'])}" # backslash inside f-string (3.12+)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 4.4 Walrus Operator (`:=`)
|
|
165
|
+
|
|
166
|
+
Use assignment expressions to eliminate redundant calls in comprehensions and loops.
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
# With walrus — single call
|
|
170
|
+
if result := compute_expensive():
|
|
171
|
+
process(result)
|
|
172
|
+
|
|
173
|
+
# In comprehension — filter and use in one expression
|
|
174
|
+
filtered = [cleaned for raw in records if (cleaned := clean(raw))]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Use sparingly; prefer clarity over brevity when the expression becomes hard to read.
|
|
178
|
+
|
|
179
|
+
### 4.5 `__slots__` Usage
|
|
180
|
+
|
|
181
|
+
Declare `__slots__` on data-heavy classes to reduce per-instance memory by 30-50%.
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
class Vector:
|
|
185
|
+
__slots__ = ("x", "y", "z")
|
|
186
|
+
|
|
187
|
+
def __init__(self, x: float, y: float, z: float) -> None:
|
|
188
|
+
self.x, self.y, self.z = x, y, z
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Do not use `__slots__` on classes intended to be subclassed without explicit slot coordination.
|
|
192
|
+
|
|
193
|
+
### 4.6 Dataclasses vs attrs vs Pydantic
|
|
194
|
+
|
|
195
|
+
| Tool | When to use |
|
|
196
|
+
|------|-------------|
|
|
197
|
+
| `dataclasses` (stdlib) | Simple data containers; no validation; no serialization needed |
|
|
198
|
+
| `attrs` | More control than dataclasses; validators, converters, `__slots__` automation |
|
|
199
|
+
| `Pydantic v2` | External data (API requests, config files); runtime validation and JSON serialization |
|
|
200
|
+
|
|
201
|
+
- Use `@dataclass(frozen=True, slots=True)` for immutable value objects.
|
|
202
|
+
- Use Pydantic `BaseModel` at system boundaries (HTTP, config); avoid deep inside the domain layer.
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
from dataclasses import dataclass
|
|
206
|
+
|
|
207
|
+
@dataclass(frozen=True, slots=True)
|
|
208
|
+
class Money:
|
|
209
|
+
amount: int # in cents
|
|
210
|
+
currency: str
|
|
211
|
+
|
|
212
|
+
def __post_init__(self) -> None:
|
|
213
|
+
if self.amount < 0:
|
|
214
|
+
raise ValueError("Amount must be non-negative")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 4.7 Modern Stdlib Additions
|
|
218
|
+
|
|
219
|
+
**`StrEnum` (3.11+):** Combine enum membership with string behavior — no need for `.value` in comparisons or string formatting.
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
from enum import StrEnum
|
|
223
|
+
|
|
224
|
+
class Color(StrEnum):
|
|
225
|
+
RED = "red"
|
|
226
|
+
GREEN = "green"
|
|
227
|
+
BLUE = "blue"
|
|
228
|
+
|
|
229
|
+
assert Color.RED == "red" # True — no .value needed
|
|
230
|
+
print(f"Color: {Color.GREEN}") # "Color: green"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**`tomllib` (3.11+ standard library):** Read TOML files without third-party dependencies; write via `tomli_w` or `tomllib` write support in 3.13+.
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
import tomllib
|
|
237
|
+
|
|
238
|
+
with open("pyproject.toml", "rb") as f: # must open in binary mode
|
|
239
|
+
config = tomllib.load(f)
|
|
240
|
+
|
|
241
|
+
version = config["project"]["version"]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**`@override` decorator (3.12+, `typing`):** Explicitly mark methods that override a base-class method; type checkers flag mismatches (wrong signature, missing base method).
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
from typing import override
|
|
248
|
+
|
|
249
|
+
class Base:
|
|
250
|
+
def process(self, data: str) -> str:
|
|
251
|
+
return data
|
|
252
|
+
|
|
253
|
+
class Child(Base):
|
|
254
|
+
@override
|
|
255
|
+
def process(self, data: str) -> str: # type checker verifies this overrides Base.process
|
|
256
|
+
return data.strip()
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Use `@override` on every intentional override; it serves as both documentation and a static-analysis safety net.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## 5. Async Patterns
|
|
264
|
+
|
|
265
|
+
**Rule:** Use `asyncio` conventions consistently; never mix sync-blocking calls into async code paths.
|
|
266
|
+
|
|
267
|
+
- Prefer `async def` for I/O-bound functions; use `asyncio.to_thread()` to run blocking code in a thread pool.
|
|
268
|
+
- Use `async for` and `async with` for async iteration and context management.
|
|
269
|
+
- Use `asyncio.TaskGroup` (3.11) over `asyncio.gather` for structured concurrency with proper error propagation.
|
|
270
|
+
- Never call `asyncio.sleep(0)` in a busy loop — use proper awaitable primitives.
|
|
271
|
+
- Avoid mixing `asyncio.run()` inside an already-running event loop; use `asyncio.get_event_loop().run_until_complete()` only in legacy contexts.
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
import asyncio
|
|
275
|
+
from pathlib import Path
|
|
276
|
+
|
|
277
|
+
async def fetch_all(urls: list[str]) -> list[bytes]:
|
|
278
|
+
async with asyncio.TaskGroup() as tg:
|
|
279
|
+
tasks = [tg.create_task(fetch(url)) for url in urls]
|
|
280
|
+
return [t.result() for t in tasks]
|
|
281
|
+
|
|
282
|
+
async def read_file_async(path: str) -> str:
|
|
283
|
+
# Run blocking I/O in a thread pool — pass callable, not result
|
|
284
|
+
return await asyncio.to_thread(Path(path).read_text)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## 6. Packaging Best Practices
|
|
290
|
+
|
|
291
|
+
**Rule:** Use `pyproject.toml` as the single configuration file; use `src/` layout.
|
|
292
|
+
|
|
293
|
+
### 6.1 Project Layout
|
|
294
|
+
|
|
295
|
+
```
|
|
296
|
+
my-project/
|
|
297
|
+
src/
|
|
298
|
+
my_package/
|
|
299
|
+
__init__.py
|
|
300
|
+
service.py
|
|
301
|
+
tests/
|
|
302
|
+
test_service.py
|
|
303
|
+
pyproject.toml
|
|
304
|
+
README.md
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
The `src/` layout prevents accidental imports of the development tree; tests always import the installed package.
|
|
308
|
+
|
|
309
|
+
### 6.2 pyproject.toml (PEP 621)
|
|
310
|
+
|
|
311
|
+
```toml
|
|
312
|
+
[build-system]
|
|
313
|
+
requires = ["hatchling"]
|
|
314
|
+
build-backend = "hatchling.build"
|
|
315
|
+
|
|
316
|
+
[project]
|
|
317
|
+
name = "my-package"
|
|
318
|
+
version = "1.0.0"
|
|
319
|
+
requires-python = ">=3.10"
|
|
320
|
+
dependencies = [
|
|
321
|
+
"httpx>=0.27",
|
|
322
|
+
"pydantic>=2.0",
|
|
323
|
+
]
|
|
324
|
+
|
|
325
|
+
[project.optional-dependencies]
|
|
326
|
+
dev = ["pytest>=8", "ruff", "mypy"]
|
|
327
|
+
|
|
328
|
+
[tool.ruff]
|
|
329
|
+
line-length = 100
|
|
330
|
+
target-version = "py310"
|
|
331
|
+
|
|
332
|
+
[tool.mypy]
|
|
333
|
+
python_version = "3.10"
|
|
334
|
+
strict = true
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 6.3 Recommended Toolchain
|
|
338
|
+
|
|
339
|
+
| Tool | Purpose | Replaces |
|
|
340
|
+
|------|---------|---------|
|
|
341
|
+
| `uv` | Package manager and virtual env (Rust-based, fast) | `pip` + `venv` + `pip-tools` |
|
|
342
|
+
| `ruff` | Linting and formatting | `flake8` + `black` + `isort` |
|
|
343
|
+
| `mypy` or `pyright` | Static type checking | — |
|
|
344
|
+
| `pytest` | Testing framework | `unittest` |
|
|
345
|
+
| `hatchling` | Build backend | `setuptools` |
|
|
346
|
+
|
|
347
|
+
- Use `uv sync` to install from lockfile; `uv add <dep>` to add dependencies with automatic lockfile update.
|
|
348
|
+
- Run `ruff check . --fix` and `ruff format .` in CI to enforce formatting and linting.
|
|
349
|
+
- Enable `mypy --strict` or equivalent `pyright` settings in CI.
|
|
350
|
+
|
|
351
|
+
### 6.4 Virtual Environments
|
|
352
|
+
|
|
353
|
+
Use `uv venv` to create isolated environments; name the directory `.venv` (the conventional default recognized by editors and CI tools).
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
uv venv # creates .venv/ in the current directory
|
|
357
|
+
source .venv/bin/activate # Linux/macOS
|
|
358
|
+
.venv\Scripts\activate # Windows
|
|
359
|
+
uv sync # install dependencies from lockfile into .venv
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
- Commit the `uv.lock` lockfile; add `.venv/` to `.gitignore`.
|
|
363
|
+
- Prefer `uv run <command>` in CI to avoid activating the environment explicitly.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## 7. Python Version Awareness (3.13 forward-looking)
|
|
368
|
+
|
|
369
|
+
**Python 3.13 (awareness only — not yet required):**
|
|
370
|
+
|
|
371
|
+
- **Free-threaded mode** (`--disable-gil` / `python3.13t`): removes the GIL, enabling true multi-core parallelism in CPython. Do not design code around GIL removal yet; avoid shared mutable state as a general practice.
|
|
372
|
+
- **Improved error messages**: Python 3.13 continues the trend of actionable `TypeError`/`NameError` messages — write tests that do not over-assert on exception message strings.
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Cross-References
|
|
377
|
+
|
|
378
|
+
This skill covers broad Python coding standards. For deeper coverage of specialized domains, refer to:
|
|
379
|
+
|
|
380
|
+
> For Python security best practices (OWASP 2025 aligned), see the `python-security-skill`.
|
|
381
|
+
> For dependency security, supply chain protection, and lockfile management, see the `python-dependency-mgmt` skill.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Python Best Practices",
|
|
3
|
+
"description": "Comprehensive Python coding standards covering PEP 8 conventions, type hinting (3.10+), modern patterns (match/case, exception groups), async, and packaging best practices. Cross-references security-focused Python skills.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"category": "language",
|
|
6
|
+
"author": "ma-agents",
|
|
7
|
+
"tags": [
|
|
8
|
+
"python",
|
|
9
|
+
"coding-standards",
|
|
10
|
+
"best-practices",
|
|
11
|
+
"pep8",
|
|
12
|
+
"type-hints",
|
|
13
|
+
"python3.10",
|
|
14
|
+
"python3.11",
|
|
15
|
+
"python3.12"
|
|
16
|
+
],
|
|
17
|
+
"applies_when": [
|
|
18
|
+
"writing python code",
|
|
19
|
+
"modifying python code",
|
|
20
|
+
"creating new python files or modules",
|
|
21
|
+
"reviewing python code style or conventions",
|
|
22
|
+
"refactoring python code",
|
|
23
|
+
"setting up a python project"
|
|
24
|
+
],
|
|
25
|
+
"always_load": false
|
|
26
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Story Status Lookup
|
|
2
|
+
|
|
3
|
+
Look up the current status of a story to determine whether its code is **delivered** or **work-in-progress**.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
Used by other skills (notably `auto-bug-detection`) to classify code before deciding whether to flag defects.
|
|
8
|
+
Do not flag bugs in WIP code. Do flag bugs in delivered code.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Backend Configuration
|
|
13
|
+
|
|
14
|
+
Before performing a lookup, check the project context for the configured sprint management backend.
|
|
15
|
+
|
|
16
|
+
**Where to look (in priority order):**
|
|
17
|
+
1. `project-context.md` in the project root — look for a `sprint_management` field
|
|
18
|
+
2. The root directives file (`CLAUDE.md`, `.cursor/rules`, or equivalent for the active agent)
|
|
19
|
+
3. If neither defines a backend, **default to `file-system`**
|
|
20
|
+
|
|
21
|
+
| `sprint_management` value | Backend |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `file-system` or not set | Read `sprint-status.yaml` (see below) |
|
|
24
|
+
| `jira` | *(Future — see Jira section below)* |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## File-System Backend
|
|
29
|
+
|
|
30
|
+
**Status file:** `_bmad-output/implementation-artifacts/sprint-status.yaml`
|
|
31
|
+
|
|
32
|
+
### Step 1 — Identify the story slug
|
|
33
|
+
|
|
34
|
+
Derive the story slug from the available context, in this order of preference:
|
|
35
|
+
|
|
36
|
+
1. The story file name currently in scope (e.g. `11-1-auto-bug-detection-skill.md` → slug is `11-1-auto-bug-detection-skill`)
|
|
37
|
+
2. The git branch name — strip prefixes (`feature/`, `fix/`, `chore/`) and normalize: lowercase, replace spaces and underscores with hyphens, remove non-alphanumeric characters except hyphens
|
|
38
|
+
3. Any explicit story reference in the current task description
|
|
39
|
+
|
|
40
|
+
### Step 2 — Look up the slug
|
|
41
|
+
|
|
42
|
+
Find the slug as a key under `development_status` in `sprint-status.yaml`.
|
|
43
|
+
|
|
44
|
+
### Step 3 — Map status to delivered / WIP
|
|
45
|
+
|
|
46
|
+
| Status value | Classification | Action |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `done` | **Delivered** | Flag bugs |
|
|
49
|
+
| `review` | **Delivered** | Flag bugs — dev work is complete, code is awaiting review |
|
|
50
|
+
| `in-progress` | WIP | Do not flag |
|
|
51
|
+
| `ready-for-dev` | WIP | Do not flag |
|
|
52
|
+
| `backlog` | WIP | Do not flag |
|
|
53
|
+
| `on-hold` | WIP | Do not flag |
|
|
54
|
+
|
|
55
|
+
### Fallback rule
|
|
56
|
+
|
|
57
|
+
If any of the following are true, **classify as WIP and do not flag**:
|
|
58
|
+
- The story slug cannot be determined from context
|
|
59
|
+
- The slug is not found in `sprint-status.yaml`
|
|
60
|
+
- The status file does not exist
|
|
61
|
+
|
|
62
|
+
Never guess or assume delivered status. When in doubt, WIP.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Future: Jira Backend
|
|
67
|
+
|
|
68
|
+
When `sprint_management: jira` is set in the project context, this extension point applies:
|
|
69
|
+
|
|
70
|
+
- Jira base URL, project key, and credentials will be defined in the project context or environment config
|
|
71
|
+
- Query the Jira issue status API for the relevant issue key
|
|
72
|
+
- Map the Jira workflow status to delivered/WIP using a status mapping defined in the project context
|
|
73
|
+
|
|
74
|
+
**This backend is not yet implemented.** When Jira support is added, update this skill with the lookup procedure and status mapping. The file-system backend remains the default fallback if Jira is unreachable.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "story-status-lookup",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Looks up the current status of a story to classify code as delivered or work-in-progress. Supports file-system backend now; Jira backend reserved for future configuration.",
|
|
5
|
+
"category": "workflow",
|
|
6
|
+
"tags": ["story-status", "sprint-management", "bug-detection"],
|
|
7
|
+
"always_load": true
|
|
8
|
+
}
|
|
@@ -65,15 +65,15 @@ test('3.3: installer.js contains NO agent-name-specific logic', () => {
|
|
|
65
65
|
|
|
66
66
|
console.log('\nTask 4 — Registry completeness');
|
|
67
67
|
|
|
68
|
-
const EXPECTED_IDE = ['claude-code', 'gemini', 'copilot', 'kilocode', 'cline', 'cursor', 'antigravity'];
|
|
68
|
+
const EXPECTED_IDE = ['claude-code', 'gemini', 'copilot', 'kilocode', 'cline', 'cursor', 'antigravity', 'opencode'];
|
|
69
69
|
const EXPECTED_BMAD = ['bmm-sre', 'bmm-devops', 'bmm-cyber', 'bmm-mil498'];
|
|
70
70
|
const EXPECTED_ALL = [...EXPECTED_IDE, ...EXPECTED_BMAD];
|
|
71
71
|
|
|
72
|
-
test('4.1: registry has
|
|
73
|
-
assert.
|
|
72
|
+
test('4.1: registry has at least 12 agents (8+ IDE + 4 BMAD)', () => {
|
|
73
|
+
assert.ok(allAgents.length >= 12, `Expected at least 12 agents, got ${allAgents.length}`);
|
|
74
74
|
const ideCount = allAgents.filter(a => a.category === 'ide').length;
|
|
75
75
|
const bmadCount = allAgents.filter(a => a.category === 'bmad').length;
|
|
76
|
-
assert.
|
|
76
|
+
assert.ok(ideCount >= 8, `Expected at least 8 IDE agents, got ${ideCount}`);
|
|
77
77
|
assert.strictEqual(bmadCount, 4, `Expected 4 BMAD agents, got ${bmadCount}`);
|
|
78
78
|
});
|
|
79
79
|
|
|
@@ -83,13 +83,18 @@ test('4.2: every agent has well-shaped injectionStrategy property', () => {
|
|
|
83
83
|
`Agent '${agent.id}' is missing injectionStrategy`);
|
|
84
84
|
assert.strictEqual(typeof agent.injectionStrategy.position, 'string',
|
|
85
85
|
`Agent '${agent.id}' injectionStrategy.position should be a string`);
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
// skipPatterns is only required for non-json-merge strategies
|
|
87
|
+
if (agent.injectionStrategy.position !== 'json-merge') {
|
|
88
|
+
assert.ok(Array.isArray(agent.injectionStrategy.skipPatterns),
|
|
89
|
+
`Agent '${agent.id}' injectionStrategy.skipPatterns should be an array, got ${typeof agent.injectionStrategy.skipPatterns}`);
|
|
90
|
+
}
|
|
88
91
|
}
|
|
89
92
|
});
|
|
90
93
|
|
|
91
94
|
test('4.3: all agents with .md instruction files have skipPatterns: [---]', () => {
|
|
92
95
|
for (const agent of allAgents) {
|
|
96
|
+
// json-merge agents use a different injection mechanism; skip this check for them
|
|
97
|
+
if (agent.injectionStrategy.position === 'json-merge') continue;
|
|
93
98
|
const hasMdFiles = agent.instructionFiles.some(f => f.endsWith('.md'));
|
|
94
99
|
if (hasMdFiles) {
|
|
95
100
|
assert.ok(agent.injectionStrategy.skipPatterns,
|
|
@@ -100,8 +105,9 @@ test('4.3: all agents with .md instruction files have skipPatterns: [---]', () =
|
|
|
100
105
|
}
|
|
101
106
|
});
|
|
102
107
|
|
|
103
|
-
test('4.3b:
|
|
108
|
+
test('4.3b: non-json-merge agents have position: top', () => {
|
|
104
109
|
for (const agent of allAgents) {
|
|
110
|
+
if (agent.injectionStrategy.position === 'json-merge') continue;
|
|
105
111
|
assert.strictEqual(agent.injectionStrategy.position, 'top',
|
|
106
112
|
`Agent '${agent.id}' should have position: 'top'`);
|
|
107
113
|
}
|