modules/tool-skills/tests/fixtures/skills/python-standards/SKILL.md
Python coding standards for Amplifier including type hints, async patterns, error handling, and formatting. Use when writing Python code for Amplifier modules.
npx skillsauth add microsoft/amplifier-bundle-skills python-standardsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
ALL functions must have complete type hints:
from typing import Any
async def process_data(items: list[str], config: dict[str, Any]) -> dict[str, Any]:
"""Process data items with configuration."""
results = {}
for item in items:
results[item] = await transform(item, config)
return results
Include type hints for self:
class MyClass:
def __init__(self: "MyClass", name: str) -> None:
self.name = name
async def process(self: "MyClass") -> str:
return f"Processing {self.name}"
All I/O operations must be async:
# Good
async def read_file(path: Path) -> str:
content = path.read_text() # For now, sync is OK
return content
# Better (when using async libraries)
async def read_file(path: Path) -> str:
async with aiofiles.open(path) as f:
return await f.read()
Use asyncio.gather for parallel operations:
async def process_files(files: list[Path]) -> list[dict]:
tasks = [process_file(f) for f in files]
return await asyncio.gather(*tasks)
Return errors, don't raise:
from amplifier_core import ToolResult
async def execute(self: "MyTool", input: dict[str, Any]) -> ToolResult:
"""Execute tool operation."""
try:
result = await self._process(input)
return ToolResult(success=True, output=result)
except ValueError as e:
logger.error(f"Validation error: {e}")
return ToolResult(success=False, error={"message": str(e)})
Provide clear error messages:
# Good
return ToolResult(
success=False,
error={"message": f"File not found: {path}"}
)
# Bad
return ToolResult(
success=False,
error={"message": "Error"}
)
Line length: 120 characters
Import organization:
# Standard library
import asyncio
import logging
from pathlib import Path
from typing import Any
# Third-party
import yaml
from pydantic import BaseModel
# Local/Amplifier
from amplifier_core import ModuleCoordinator, ToolResult
Files must end with newline - Add blank line at EOF
Use ruff for formatting:
uv run ruff format .
uv run ruff check . --fix
Use uv for dependency management:
# Add dependency
cd amplifier-module-tool-mytool
uv add package-name
# Add dev dependency
uv add --dev pytest ruff pyright
Never manually edit pyproject.toml dependencies - Use uv add
Test behavior at protocol level:
import pytest
from amplifier_core.testing import TestCoordinator
@pytest.mark.asyncio
async def test_tool_basic():
"""Test basic tool functionality."""
coordinator = TestCoordinator()
# Mount module
await mount(coordinator, {"timeout": 10})
# Get and test
tool = coordinator.get("tools", "my-tool")
result = await tool.execute({"param": "value"})
assert result.success
assert "expected" in result.output
Test pyramid: 60% unit, 30% integration, 10% end-to-end
# Bad
content = requests.get(url).text
# Good
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
content = await response.text()
# Bad
tool._internal_state = new_value
# Good
await tool.execute({"operation": "update", "value": new_value})
# Bad
async def mount(coordinator, config):
tool = MyTool()
await tool.initialize_database() # Heavy logic
await coordinator.mount("tools", tool)
# Good
async def mount(coordinator, config):
tool = MyTool(config) # Light initialization only
await coordinator.mount("tools", tool)
# Heavy logic happens in execute(), not mount()
make check before committingtools
Plan a batch of independent work into isolated lanes, get your approval, then run each lane as its own autonomous /goal session — one git worktree, one branch, one tmux session each — and verify and merge the results yourself. Use when work decomposes into pieces that can run at the same time: "run these in parallel", "goal-batch", "launch lanes for these", "work these N tasks simultaneously", "batch these as goals". Nothing launches until you have seen the lane split and said go. This is NOT fire-and-forget: the orchestrating session re-runs the full test suite itself after every merge and never accepts a lane's own claim that it finished. NOT for bounded edits that each end in their own PR — use mass-change for that. Requires git, tmux, the amplifier CLI on PATH, and the goalify and monitor skills.
development
Hard-won patterns for probing, building, troubleshooting, and iterating against Microsoft Graph API endpoints -- especially from a browser SPA using delegated MSAL.js auth calling Graph directly with no backend (lessons generalize to any Graph integration). Covers the throwaway-probe-file methodology for de-risking before building, OData/query quirks, permission and admin-consent sequencing, recordings/transcripts access patterns (SharePoint REST, not Graph), CSP requirements for a pure-browser SPA, retry/pagination/backoff patterns, and the MSAL/EasyAuth auth-redirect-loop debugging saga. Use when integrating with Microsoft Graph, Teams APIs, MSAL.js, or EasyAuth; when hitting an unexpected Graph error (400/403/429), a silent missing-scope failure, an auth redirect loop, or a CSP violation that only appears in production; or when deciding how to validate a new Graph capability before committing it to a codebase.
tools
Use when building an Amplifier-powered workflow or automation tool and deciding how to expose it — as standalone .dot attractor pipelines (incl. inside the Resolve dot-graph resolver), an importable Python lib, agent-callable tool modules, or a CLI. Covers the four leverage levels, the DRY rule that keeps logic in ONE home, the judgment for which levels a real consumer actually needs (and when adding a level is just ceremony), and the maximally-DRY attractor-only specialization where the .dot pipeline is the sole logic home.
tools
Diagnose issues in the current Amplifier session — misconfigured tools, failing operations, unexpected behavior. Use when something isn't working right.