Python Rules
softspark/ai-toolkit
Python coding rules: style, patterns, security, testing. An agent skill from softspark/ai-toolkit.
A skill your agent uses when the task is Python itself, in any framework or none: PEP 695 generics, mypy --strict typing, dataclass/Protocol/TypedDict/Enum choices, asyncio.TaskGroup, stdlib idioms…
$ npx skills add ericrisco/rsc-harness --skill python -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ericrisco/rsc-harness python --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/python .claude/skills/python && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "python" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/python into .claude/skills/python/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "python", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ericrisco/rsc-harness/tree/main/skills/pythonType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ericrisco/rsc-harness --skill python -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ericrisco/rsc-harness python --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/python .agents/skills/python && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "python" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/python into .agents/skills/python/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "python", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill python -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ericrisco/rsc-harness python --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/python .cursor/skills/python && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "python" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/python into .cursor/skills/python/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "python", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ericrisco/rsc-harness.git --path skills/python--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ericrisco/rsc-harness --skill python -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ericrisco/rsc-harness python --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/python .gemini/skills/python && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "python" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/python into .gemini/skills/python/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "python", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ericrisco/rsc-harness pythonInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ericrisco/rsc-harness --skill python -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/python .github/skills/python && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "python" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/python into .github/skills/python/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "python", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill python -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ericrisco/rsc-harness python --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/python .opencode/skills/python && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "python" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/python into .opencode/skills/python/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "python", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
pythonA skill your agent uses when the task is Python itself, in any framework or none: PEP 695 generics, mypy --strict typing, dataclass/Protocol/TypedDict/Enum choices, asyncio.TaskGroup, stdlib idioms…
Python is an agent skill from ericrisco/rsc-harness. Use when the task is Python itself, in any framework or none: PEP 695 generics, mypy --strict typing, dataclass/Protocol/TypedDict/Enum choices, asyncio.TaskGroup, stdlib idioms, src/ layout + pyproject.toml with uv, ruff+mypy+pytest gate. NOT a FastAPI/ASGI service (that is fastapi), NOT a deep pytest suite (that is testing-py).
Its SKILL.md is about 3.8k tokens, which your agent loads only when the skill is triggered. The skill folder holds 9 other files, including scripts and reference files (for example `evals/README.md`, `evals/cases.yaml` and `references/async.md`).
It sits in Backend & APIs, covering Type safety, Backend development and Unit testing. It works with Python, pytest, FastAPI and Ruff. The repository describes itself as: Your agent invents things because it has no memory, and can't touch your database because it has no arms. rsc is the meta-harness that gives it both, plus the trade to know the… The licence is MIT.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 92fde8f. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/ (Shell), which the agent can run.
Shell commands in SKILL.md call:
uvruffmypypytestFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use uv, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Python loads about 3.8k tokens when it runs, and up to ~7.9k if it reads all its reference files. Until then it costs about 85 tokens; SKILL.md has 1,356 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from ericrisco/rsc-harness at commit 92fde8f, republished under its MIT licence (© ericrisco). 1,356 words, ~3,793 tokens.
.claude/skills/python/SKILL.md (or your agent's skills folder). This skill also uses 6 other files; get the full folder from GitHub.Write, review, modernize, type, and package Python that reads like a typed,
flat-control-flow, stdlib-first program whose dependencies and tooling all live in one
pyproject.toml. Types are part of the design, not decoration; the stdlib is large and you
reach for it before a dependency; correctness is ruff + a type checker + pytest in one gate.
Targets Python 3.12+ (floor) / 3.14 (current, released 7 Oct 2025): PEP 695 inline
type parameters (class Box[T]:, type Alias = ...), asyncio.TaskGroup, and — in 3.14 —
deferred annotation evaluation by default (PEP 649/749, no more from __future__ import annotations), PEP 750 template strings (t"..."), and compression.zstd. Tooling pins:
uv 0.11 (project + package manager), ruff 0.15 (lint + format), mypy 1.20
--strict (or Astral's ty, still preview — default to mypy), pytest 8.
fastapi. That skill owns the service shape; this one owns the
language it is written in.testing-py (this skill keeps only the baseline: a few tests
so verify.sh has something to run, then hands off).secure-coding (this skill keeps Python-specific safety: no
eval/pickle of untrusted data, subprocess without shell=True, secrets over random).deployment
(this skill ships only a uv-based CI note).go, typescript, rust, etc. Django ORM/models/migrations -> django.Python typing, async language semantics, and uv packaging live here, not in a separate skill — this skill is the canonical authority for the language substrate under any Python program.
Apply on every Python edit:
--strict.return/raise early; keep the happy path
unindented — arrow code hides the logic.pathlib, itertools, functools, dataclasses,
collections cover most needs; a new dep is a maintenance liability you must justify.@dataclass(frozen=True, slots=True) for value objects; mutate
only where you must — shared mutable state is the bug you debug at 2am.ruff check + ruff format --check + mypy --strict +
pytest — green locally via scripts/verify.sh before you call it done.Type the boundary; run mypy --strict so untyped code and implicit Any are errors, not
silent gaps. Use PEP 695 inline syntax for all new generic code — no explicit TypeVar
objects:
# Good (3.12+): inline type parameter and the `type` alias statement.
def first[T](xs: list[T]) -> T:
return xs[0]
class Box[T]: ...
type UserId = int # `type` statement: a real alias, lazily evaluated
# Bad (legacy): `T = TypeVar("T")` then a Generic[T] — fine in old code, don't write it new.Core choices: Protocol (structural, no inheritance) over an ABC when you only need "has these
methods"; X | None (not Optional[X]); Literal/Enum for closed value sets; Final for
constants; Self for fluent returns; @overload for signature families. Narrow with
isinstance, assert, or an is None guard — mypy follows the flow. In 3.14 annotations
are lazy by default (PEP 649/749), so forward references resolve without from __future__ import annotations.
Full PEP 695 bounds/constraints/variance, Protocol vs ABC, TypedDict
Required/NotRequired, ParamSpec/TypeVarTuple, TypeGuard/TypeIs, cast, and common
--strict errors with fixes -> references/typing.md.
Pick the carrier by what the data is, not by habit:
| Need | Use | Why |
|---|---|---|
| Immutable value object, typed fields, methods | @dataclass(frozen=True, slots=True) | Hashable, no __dict__ overhead, real types |
| Small fixed tuple, positional + named, immutable | NamedTuple | Tuple semantics + field names; cheap |
| Shape of an external/JSON dict, no runtime class | TypedDict | Types a plain dict without wrapping it |
| Closed set of named constants | Enum / StrEnum / IntEnum | One source of truth; Literal-friendly |
| Mutable bag of related state with behavior | plain class / @dataclass | When you genuinely need mutation |
| Runtime-validated I/O model (parse untrusted data) | Pydantic -> fastapi | Validation is a service concern, not language |
from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class Point:
x: float
y: float
def translated(self, dx: float, dy: float) -> "Point":
return Point(self.x + dx, self.y + dy) # returns a new value, never mutatesFrozen-slots dataclass when you want methods + hashability + clear types; NamedTuple when
the thing genuinely is a small tuple you also unpack positionally.
Reach into the stdlib before adding a dependency.
pathlib for all filesystem paths: Path("data") / name, p.read_text(),
p.glob("*.json"), p.with_suffix(".bak") — typed and composable, never os.path.join.collections: defaultdict(list), Counter(words), deque(maxlen=100) for ring buffers.itertools: chain, groupby, islice, batched (3.12+) instead of hand-rolled loops.functools: @cache / @lru_cache for pure memoization, @cached_property, partial.contextlib: @contextmanager, ExitStack for dynamic resource sets, suppress(FileNotFoundError).logging, never print in a library: print writes to a caller's stdout you do not own;
logging.getLogger(__name__) lets them configure it.Prefer comprehensions over map/filter+lambda; prefer a generator ((... for ...)) when
you only iterate once. Use match for structural dispatch over a chain of isinstance:
from functools import cache
from pathlib import Path
@cache
def config_dir() -> Path: # computed once, memoized
return Path.home() / ".config" / "myapp"
def area(shape: object) -> float:
match shape: # structural dispatch, captures by attribute/key
case {"kind": "circle", "r": float(r)}:
return 3.14159 * r * r
case _:
raise TypeError(f"unknown shape: {shape!r}")f-strings for formatting; note 3.14's PEP 750 t"..." template strings yield a Template
(not a str) for safe custom interpolation (e.g. escaping) — use them when an f-string would
inject untrusted text. Full cookbook (itertools/functools/collections recipes, match
patterns, dataclass field/default_factory/__post_init__, Enum/StrEnum/IntFlag) ->
references/stdlib.md.
Define a small exception hierarchy rooted in one base so callers can catch broadly or
narrowly; chain causes with raise ... from; never write a bare except:.
class AppError(Exception): ...
class NotFoundError(AppError): ...
def load(path: Path) -> str:
try:
return path.read_text()
except FileNotFoundError as e:
raise NotFoundError(f"missing {path}") from e # preserves the cause chainUse except* to handle an ExceptionGroup (what a TaskGroup raises) by member type.
Prefer EAFP (try the operation, handle the failure) over LBYL race-prone pre-checks.
Always release resources with with (a context manager), not manual try/finally close.
Use asyncio.run(main()) as the single entry point. asyncio.TaskGroup (3.11+) over bare
gather — it is the structured-concurrency primitive: a child failure cancels its siblings
and surfaces as an ExceptionGroup, and no task outlives the block.
import asyncio
# Bad: gather leaks the other tasks on first failure and loses structure.
async def fetch_all_bad(ids: list[int]) -> list[bytes]:
return await asyncio.gather(*(fetch(i) for i in ids))
# Good: TaskGroup — sibling cancellation on error, bounded lifetime, real grouping.
async def fetch_all(ids: list[int]) -> list[bytes]:
async with asyncio.TaskGroup() as tg:
tasks = [tg.create_task(fetch(i)) for i in ids]
return [t.result() for t in tasks] # block exited => all done or raisedBound every wait with async with asyncio.timeout(5.0):. On CancelledError, clean up and
re-raise — swallowing it breaks cancellation for the whole tree. Async is for IO-bound
concurrency only; CPU-bound work blocks the loop — push it to asyncio.to_thread / a
ProcessPoolExecutor (or 3.14's free-threaded build). HTTP servers belong to
fastapi, not here. Runtime model, ExceptionGroup/except*, queues
with backpressure, cancellation discipline, and sync<->async bridging ->
references/async.md.
Use a src/ layout so tests import the installed package, not the source tree by accident:
myapp/
src/myapp/__init__.py
src/myapp/core.py
tests/test_core.py
pyproject.toml
uv.lock # committed
scripts/verify.shpyproject.toml is the single config — PEP 621 metadata, dependency groups, and tool config.
Never hand-edit a requirements.txt; uv add writes the dep and updates uv.lock, which you commit.
[project]
name = "myapp"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["httpx>=0.27"]
[project.scripts]
myapp = "myapp.core:main" # console entry point
[dependency-groups]
dev = ["ruff>=0.15", "mypy>=1.13", "pytest>=8"]
[build-system]
requires = ["uv_build>=0.11"]
build-backend = "uv_build" # uv's own backend, stable since July 2025
[tool.ruff]
line-length = 100
[tool.mypy]
strict = trueCore uv verbs (each updates uv.lock, which you commit):
uv init --package myapp # scaffold pyproject.toml + src/ + .venv
uv add httpx # add a runtime dep
uv add --dev ruff mypy pytest # add to the dev group
uv sync --frozen # install exactly from the lockfile (CI + fresh clones)
uv run pytest -q # run inside the managed venv
uv python install 3.14 # pin/install an interpreterOne local gate, mirroring CI: ruff check --fix ., ruff format ., mypy --strict src
(or ty check), pytest -q. scripts/verify.sh runs all of them, skips a missing tool/dir
with a warning, and exits non-zero on any real failure — run ./scripts/verify.sh from the
project root before declaring done. CI is astral-sh/setup-uv + uv sync --frozen + the same
four commands; full pipeline -> deployment.
Carry just enough to make verify.sh meaningful — plain test_* functions, assert,
pytest.raises, one parametrize, tmp_path for files:
import pytest
from myapp.core import head
@pytest.mark.parametrize("xs, expected", [(["a", "b"], "a"), (["x"], "x")])
def test_head_returns_first(xs: list[str], expected: str) -> None:
assert head(xs) == expected
def test_head_rejects_empty() -> None:
with pytest.raises(ValueError):
head([])
def test_writes_file(tmp_path) -> None:
(tmp_path / "f.txt").write_text("hi")
assert (tmp_path / "f.txt").read_text() == "hi"Deep fixtures, mocking, coverage gates, and property-based testing belong to testing-py —
stop at the baseline and hand off.
Generic threat modeling and authz live in secure-coding; these Python-specific controls stay here:
# Bad # Good
eval(user_input) ast.literal_eval(user_input) # never eval/exec input
pickle.loads(network_bytes) json.loads(network_bytes) # never unpickle untrusted data
subprocess.run(cmd, shell=True) subprocess.run(["ls", path]) # list args, no shell=True
random.random() # tokens secrets.token_urlsafe(32) # secrets, not random, for secretsKeep deps locked (uv.lock) and audited (pip-audit / uv resolution); read secrets from
env or a secret manager, never hardcode or log them.
| Tempting move | Reality / do instead |
|---|---|
"def f(xs=[]) is fine, it's empty" | One list shared across all calls; use = None then xs = xs or []. |
"bare except: to be safe" | Swallows KeyboardInterrupt/bugs; catch a specific type. |
"from module import *" | Pollutes the namespace, breaks tooling; import names explicitly. |
"print() to debug this library" | Writes to a stdout you don't own; use logging.getLogger(__name__). |
"os.path.join is what I know" | pathlib.Path is typed and composable; use /. |
| "I'll add types later" | Untyped public API defeats --strict; type the boundary now. |
"edit requirements.txt by hand" | Drifts from the lock; uv add / uv remove and commit uv.lock. |
"asyncio.gather is simpler" | Leaks siblings on failure; TaskGroup for structured concurrency. |
"swallow CancelledError, it's noise" | Breaks cancellation for the whole tree; clean up and re-raise. |
"time.sleep inside this coroutine" | Blocks the event loop; await asyncio.sleep(...). |
"pickle.loads the cache, it's ours" | Any untrusted byte = code execution; use json. |
"explicit TypeVar everywhere" | New code uses PEP 695 def f[T] / class C[T] / type X. |
In a project that has the harness wiki, record this project's Python
conventions in 02-DOCS/wiki/stack/python.md and index it in 02-DOCS/wiki/index.md — the
interpreter floor, src/ layout, uv workflow, ruff/mypy config, async-vs-sync stance, and
data-modeling defaults. Read it first on every use and bump its Updated date when a convention
changes. This is recorded, not gated: never block the task on it, and skip silently when there
is no 02-DOCS/ layer.
© ericrisco, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 6 other files (scripts, references) in skills/python of ericrisco/rsc-harness.
Open the folder on GitHubat commit 92fde8f
Python next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Python this skillericrisco/rsc-harness | 156 | — | ~3.8k | Automated safety check: Pass | MIT | |
| Python Rulessoftspark/ai-toolkit | 179 | — | ~2.9k | Automated safety check: Pass | Apache-2.0 | |
| Run And Verifyaropan/clist | 439 | — | ~461 | Automated safety check: Pass | Apache-2.0 | |
| Kedro Babysitkedro-org/kedro | 11k | — | ~4k | Automated safety check: Pass | Custom licence | |
| Mastering Python SkillSpillwaveSolutions/agent-brain | 120 | — | ~1.4k | Automated safety check: Notes | MIT | |
| Modern Pythonantoinebou12/uml-mcp | 105 | — | ~1k | Automated safety check: Pass | MIT |
softspark/ai-toolkit
Python coding rules: style, patterns, security, testing. An agent skill from softspark/ai-toolkit.
aropan/clist
Choose and run focused checks after changing CLIST Python code: Django tests, standalone pytest tests, offline parser fixtures, Ruff, or a relevant management-command check.
kedro-org/kedro
Run Kedro's local lint / format / type-check / tests on changed files (uses the project's pre-commit hooks, ruff, mypy, pytest, lint-imports, detect-secrets, Make targets — in the right venv), or…
SpillwaveSolutions/agent-brain
Modern Python coaching covering language foundations through advanced production patterns.
antoinebou12/uml-mcp
Modern Python tooling and best practices using uv, ruff, ty, and pytest.
maksimzayats/specx
Add strict Python project tooling for a specx service. An agent skill from maksimzayats/specx.
ericrisco/rsc-harness
A skill your agent uses when designing or analyzing a controlled experiment — falsifiable hypothesis, sample size from an MDE, reading significance/CI/power, CUPED, or rescuing tests that won't go…
ericrisco/rsc-harness
A skill your agent uses when making a web UI conform to WCAG 2.2 Level AA — axe-core or Lighthouse a11y violations, keyboard operability, focus management, ARIA roles/names/live regions, contrast…
ericrisco/rsc-harness
A skill your agent uses when running or fixing paid acquisition on Google or Meta — campaign structure (Performance Max, Demand Gen, Search, Advantage+), platform-fit creative, budget/scaling rules…
ericrisco/rsc-harness
A skill your agent uses when measuring whether an LLM or agent system actually got better and gating merges on it: golden sets, fixing an inflated LLM-as-judge, scoring RAG (faithfulness, contextual…
ericrisco/rsc-harness
A skill your agent uses when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with…
ericrisco/rsc-harness
A skill your agent uses when instrumenting product or web analytics — GA4/PostHog SDK wiring, event taxonomy, funnels, double-counted events, consent gating, PII scrubbing.
Categories
A skill your agent uses when the task is Python itself, in any framework or none: PEP 695 generics, mypy --strict typing, dataclass/Protocol/TypedDict/Enum choices, asyncio.TaskGroup, stdlib idioms…. Python is an agent skill from ericrisco/rsc-harness.toml with uv, ruff+mypy+pytest gate.
Python fits situations like: the task is Python itself; in any framework; none: PEP 695 generics; mypy --strict typing.
Run `npx skills add ericrisco/rsc-harness --skill python -a claude-code`. Or copy the skill folder (skills/python in ericrisco/rsc-harness) into .claude/skills/python in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ericrisco/rsc-harness --skill python -a codex`. Or copy the skill folder (skills/python in ericrisco/rsc-harness) into .agents/skills/python in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ericrisco/rsc-harness --skill python -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/python, .gemini/skills/python, .github/skills/python and .opencode/skills/python in your project.
Going by SKILL.md and its folder, Python needs a shell for the scripts in its folder and the command-line tools its instructions call (uv, ruff, mypy and pytest). Our summary lists: Python 3; A Bash shell.
SKILL.md contains no URLs. Its commands use uv, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Python is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.8k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 4.2k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with Python: Python Rules (softspark/ai-toolkit, 179 stars), Run And Verify (aropan/clist, 439 stars), Kedro Babysit (kedro-org/kedro, 11k stars) and Mastering Python Skill (SpillwaveSolutions/agent-brain, 120 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ericrisco (a GitHub user) maintains it in ericrisco/rsc-harness, which has 156 GitHub stars. The repository holds 229 skills in this directory. The repository was last updated on October 6, 2026.
Source: ericrisco/rsc-harness on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.