Install
$ agentstack add skill-xobotyi-cc-foundry-python ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ● Filesystem access Used
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Python
Readability counts. Explicit is better than implicit. If your code needs a comment to explain its control flow, restructure it.
Python 3.14+ is the baseline. Use modern syntax unconditionally — no backward compatibility with older Python versions unless the project explicitly requires it.
References
- [
${CLAUDE_SKILL_DIR}/references/typing.md] — Type annotation patterns, generics, overloads, TypeVar, variance:
full annotation examples, generic class patterns, Protocol implementation, TypeVar usage
- [
${CLAUDE_SKILL_DIR}/references/packaging.md] — Project layout, pyproject.toml, uv, dependency management:
pyproject.toml templates, uv workflows, src layout, dependency groups, build backends
- [
${CLAUDE_SKILL_DIR}/references/modules.md] — Module system, imports, namespace packages,__init__.py: import
resolution order, circular import fixes, lazy imports, namespace packages
- [
${CLAUDE_SKILL_DIR}/references/concurrency.md] — asyncio, TaskGroup, cancellation, timeouts, threading interop:
TaskGroup error handling, timeout scopes, cancellation semantics, to_thread, eager task factory
Naming
- Variables, functions, methods — snake_case:
user_name,fetch_data - Classes, type aliases — PascalCase:
UserService,HttpClient - Constants — UPPERSNAKECASE:
MAX_RETRIES,API_BASE_URL - Modules, packages — snake_case, short:
user_store,auth - Private attributes/methods —
_prefix:_internal_cache,_validate() - Name-mangled attributes —
__prefix:__secret(rarely needed) - Type variables — PascalCase, short:
T,KT,VT,ResponseT - Protocols — PascalCase,
-able/-iblesuffix:Renderable,Serializable
- Descriptive names.
user_countnotn. Short names (i,x) only in tiny scopes (comprehensions, simple
lambdas).
- No redundant context.
car.makenotcar.car_make. - Boolean names:
is_/has_/can_/should_prefix:is_valid,has_access. - Dunder methods are reserved for the data model. Never invent custom dunder names.
- Avoid single-character names outside loop indices, comprehension variables, and well-established conventions (
f
for file, e for exception, k/v for key/value).
Type Annotations
Python 3.14+ uses modern annotation syntax natively. No from __future__ import annotations needed — all annotations are evaluated lazily by default.
Core Rules
- Annotate all public API boundaries — function signatures, class attributes, module-level variables. Internal code
often needs fewer annotations; types flow from context.
- Use built-in generics:
list[str],dict[str, int],tuple[int, ...],set[float]. Never importList,
Dict, Tuple, Set from typing.
- Union with
|:str | None,int | float. NeverOptional[X]orUnion[X, Y]. typestatement for aliases:type Vector = list[float]. NotTypeAliasannotation.Nonereturn: annotate-> Noneon functions that return nothing. Omit return type only on__init__.- Avoid
Any— it disables type checking. Useobjectwhen you mean "any type but still type-safe." UseAnyonly
at true interop boundaries with untyped code.
Generics
typeparameter syntax (3.12+):class Stack[T]:anddef first[T](items: list[T]) -> T:instead ofTypeVar
declarations.
- Constrained type parameters:
def process[T: (str, bytes)](data: T) -> T:for a finite set of allowed types. - Bounded type parameters:
def sort[T: Comparable](items: list[T]) -> list[T]:for upper-bound constraints. - Variance is inferred from usage in 3.12+ generics. No manual
covariant/contravariantflags needed.
Protocols (Structural Typing)
- Prefer protocols over ABCs when you don't control the implementing types or when structural compatibility is
sufficient.
@runtime_checkableonly when you needisinstance()checks — it adds overhead and only validates method
presence, not signatures.
- Keep protocols small — one to three methods. A protocol with many methods is a sign you need an ABC or a concrete
base class.
from typing import Protocol, runtime_checkable
@runtime_checkable
class Renderable(Protocol):
def render(self) -> str: ...
Callable Types
collections.abc.Callablefor callable annotations:Callable[[int, str], bool].ParamSpecfor decorators that preserve signatures:
def decorator[**P, R](fn: Callable[P, R]) -> Callable[P, R]:.
- Use
Protocolfor complex callable signatures with keyword arguments or overloads.
TypeGuard and TypeIs
TypeIs(3.13+) for narrowing that refines the input type:
def is_str_list(val: list[object]) -> TypeIs[list[str]]:.
TypeGuardfor narrowing where the output type is unrelated to input:
def is_valid_config(data: object) -> TypeGuard[Config]:.
See ${CLAUDE_SKILL_DIR}/references/typing.md for full annotation patterns, generics, overloads, and variance.
Data Classes and Structured Data
dataclasses
- Use
@dataclassfor data containers — classes that primarily hold data with minimal behavior. frozen=Truefor immutable data:@dataclass(frozen=True). Default to frozen unless mutation is required.slots=Truefor memory efficiency and attribute safety:@dataclass(slots=True, frozen=True).kw_only=Truewhen constructors have more than 3 fields — prevents positional argument ordering bugs.field(default_factory=list)for mutable defaults. Never use mutable default arguments.- Post-init processing:
__post_init__for derived fields and validation.
@dataclass(frozen=True, slots=True, kw_only=True)
class User:
name: str
email: str
roles: list[str] = field(default_factory=list)
When NOT to Use dataclasses
- Simple value containers with 1-2 fields: use
NamedTupleor plain tuples. - Config/settings with validation: use Pydantic or attrs with validators.
- Persistence/ORM models: use the ORM's model base class.
NamedTuple
- Use
classsyntax over functional form:class Point(NamedTuple): x: float; y: float. - NamedTuples are immutable and iterable — useful as dict keys and in destructuring.
Enums
- Use
enum.Enumfor categorical constants. Never use bare strings or ints as pseudo-enums. enum.StrEnumwhen the enum must interoperate with string APIs (JSON, config keys).enum.IntEnumonly when integer interop is mandatory (legacy protocols). PreferEnumotherwise.@enum.uniqueto prevent duplicate values.- Access by value:
Color(1). Access by name:Color["RED"]. Iteration:for c in Color:. - Never subclass enums with members. Enums with members are final.
from enum import StrEnum, unique
@unique
class Status(StrEnum):
ACTIVE = "active"
INACTIVE = "inactive"
SUSPENDED = "suspended"
Pattern Matching
match/case (3.10+) is the preferred dispatch mechanism for structural patterns.
- Use match for structural dispatch — matching on type, shape, or destructured values. Don't use match as a
substitute for simple if/elif chains on a single value.
- Always include a wildcard
case _:arm unless the match is provably exhaustive. - Guard clauses with
if:case Point(x, y) if x > 0:. - Use
|for alternatives:case "quit" | "exit" | "q":. - Capture with walrus:
case {"error": str() as msg}:captures while matching type. - Class patterns require
__match_args__or keyword patterns:case Point(x=0, y=y):.
match command:
case {"action": "move", "direction": str() as direction}:
move(direction)
case {"action": "attack", "target": str() as target}:
attack(target)
case _:
raise ValueError(f"Unknown command: {command}")
Functions
- Early return. Guard clauses first, happy path flat. Reduce nesting.
- One function, one job. If the name contains "and", split it.
- Type-annotate all parameters and return types on public functions.
- Default arguments: immutable values only. Use
None+ conditional for mutable defaults:
def f(items: list[int] | None = None): then items = items or [] in body. Never def f(items: list[int] = []):.
*to force keyword-only arguments after positional params:def connect(host: str, *, port: int = 443):./to force positional-only for parameters that callers shouldn't name:def sqrt(x: float, /) -> float:.- Prefer returning values over mutating arguments. Functions should be referentially transparent when possible.
Nonemeans absent, not error. ReturnT | Nonefor optional results. Raise exceptions for errors.
Decorators
- Preserve signatures with
functools.wraps:
``python def retry[**P, R](fn: Callable[P, R]) -> Callable[P, R]: @functools.wraps(fn) def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: ... return wrapper ``
- Decorator order matters. Decorators apply bottom-up.
@staticmethodand@classmethodmust be outermost (topmost
in source).
- Parametric decorators return a decorator:
@retry(attempts=3)meansretryreturns the actual decorator
function.
- Don't over-abstract with decorators. If the decorator hides important control flow (error handling, transaction
management), make it explicit instead.
Context Managers
contextlib.contextmanagerfor simple resource management:
``python @contextmanager def managed_connection(url: str) -> Iterator[Connection]: conn = Connection(url) try: yield conn finally: conn.close() ``
- Class-based context managers when state management is complex — implement
__enter__and__exit__. contextlib.suppress(ExceptionType)instead of emptyexcept: pass.contextlib.closing(thing)for objects with.close()but no__exit__.contextlib.asynccontextmanagerfor async resource management.- Always use
withfor files, locks, database connections, and any resource that needs deterministic cleanup.
Generators and Iterators
- Generators for lazy sequences. Use
yieldto produce values on demand instead of building full lists in memory. - Generator expressions over list comprehensions when the result is iterated only once:
sum(x * x for x in range(1000)).
yield fromto delegate to sub-generators — preserves.send(),.throw(),.close()protocol.itertoolsfor composition:chain,islice,groupby,batched(3.12+),pairwise(3.10+).- Annotate generators:
def gen() -> Iterator[int]:for simple generators,
Generator[YieldType, SendType, ReturnType] when using .send().
- Never exhaust a generator twice. Generators are single-pass. If you need multiple passes, materialize to a list or
use itertools.tee.
Comprehensions
- List/dict/set comprehensions for simple transforms:
[x.name for x in users if x.active]. - One level of nesting maximum. Two nested
forclauses are the absolute limit. Beyond that, extract to a function. - Don't use comprehensions for side effects.
[print(x) for x in items]is wrong — use aforloop. - Walrus operator in comprehensions for compute-once-filter-and-use:
[y for x in data if (y := transform(x)) is not None].
- Dict comprehensions for key transformations:
{k.lower(): v for k, v in headers.items()}.
Exception Handling
- Be specific. Catch the narrowest exception type:
except ValueError:notexcept Exception:. - Never bare
except:. It catchesSystemExit,KeyboardInterrupt, andGeneratorExit. At minimum use
except Exception:.
except* ExceptionGroup(3.11+) for handling multiple concurrent exceptions fromTaskGroupand similar.- Wrap with context.
raise AppError("context") from errchains the original cause. - Don't use exceptions for flow control.
if key in dict:nottry: dict[key] except KeyError:(unless the miss is
rare and lookup is expensive).
- Custom exceptions inherit from a project-specific base that extends
Exception:
``python class AppError(Exception): ... class NotFoundError(AppError): ... class ValidationError(AppError): ... ``
- Error strings: lowercase, no trailing punctuation. They compose in chains:
"parse config: invalid format". elseclause runs only when no exception was raised — use for code that should execute on success but isn't part
of the try body.
finallyfor unconditional cleanup — prefer context managers when possible.- Exception groups (3.11+): use
ExceptionGroupto bundle multiple errors. Handle withexcept*which matches by
type and re-raises unhandled exceptions.
- Add notes with
.add_note()(3.11+) to attach context without creating new exception types.
Strings
- f-strings for interpolation. Never
%formatting or.format()in new code. - f-string expressions must be simple. No function calls with multiple arguments, no nested f-strings, no complex
expressions. Extract to a variable first.
str.removeprefix()/str.removesuffix()(3.9+) over slicing.- Triple-quoted strings for multiline. Use
textwrap.dedentwhen indentation matters. "".join(parts)for building strings in loops — never+=in a loop.- Raw strings
r"..."for regex patterns and Windows paths.
Pathlib
pathlib.Pathfor all filesystem operations. Neveros.pathin new code./operator for path joining:base / "subdir" / "file.txt".- Common operations:
path.exists(),path.is_file(),path.is_dir(),path.read_text(),path.write_text(),
path.mkdir(parents=True, exist_ok=True), path.iterdir(), path.glob("*.py"), path.rglob("**/*.py").
path.resolve()for absolute paths.path.relative_to(base)for relative paths.- Accept
str | Pathin public APIs, convert toPathinternally.
Imports
- Absolute imports by default:
from mypackage.utils import helper. - Relative imports only within packages for tightly coupled modules:
from .models import User. - Import grouping (separated by blank lines):
- Standard library (
import os,from pathlib import Path) - Third-party (
import httpx,from pydantic import BaseModel) - Local (
from myapp.models import User)
- Import specific names:
from collections import defaultdictnotimport collections(unless you use many names
from the module).
- Never
from module import *— pollutes namespace, breaks type checkers, hides dependencies. if TYPE_CHECKING:block for imports used only in annotations — avoids circular imports and runtime overhead. In
3.14+ with lazy annotations, this is less necessary but still useful for avoiding circular import side effects.
- Lazy imports in function bodies when a top-level import would create a circular dependency or when the import is
expensive and rarely needed.
Classes
Slots
- Always use
__slots__on classes that will have many instances — prevents__dict__creation, saves memory,
catches typos in attribute names.
@dataclass(slots=True)adds slots automatically.- Slots and inheritance: every class in the hierarchy must declare
__slots__. Missing slots on a parent
reintroduces __dict__.
Dunder Methods
__repr__on every class — must be unambiguous:def __repr__(self) -> str: return f"User(name={self.name!r})".__str__only when a human-readable form differs from repr.__eq__and__hash__— if you define__eq__, define__hash__too (or set__hash__ = Noneto make
unhashable). Mutable objects should not be hashable.
__bool__— define when truthiness of instances has meaningful sem
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: xobotyi
- Source: xobotyi/cc-foundry
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.