Python’s os module provides a portable interface to the operating system. import os. environ: os.environ["HOME"]; os.environ.get("PORT", "8080"); os.environ["KEY"] = "val". getenv: os.getenv("KEY", default). path.join: os.path.join("/base", "sub", "file.txt"). path.split: os.path.split("/a/b/c.txt") → (“a/b”, “c.txt”). path.basename: os.path.basename("/a/b/c.txt") → “c.txt”. path.dirname: os.path.dirname("/a/b/c.txt") → “/a/b”. path.splitext: os.path.splitext("file.tar.gz") → (“file.tar”, “.gz”). path.abspath: os.path.abspath("."). path.realpath: follows symlinks. path.expanduser: os.path.expanduser("~/file"). path.exists / isfile / isdir / islink. getcwd: os.getcwd(). chdir: os.chdir(path). makedirs: os.makedirs(path, exist_ok=True). listdir: os.listdir(".") → list of names. scandir: with os.scandir(".") as it: for e in it: e.name, e.stat(). walk: for root, dirs, files in os.walk("/path"):. stat: st = os.stat(path); st.st_size, st.st_mtime, st.st_mode. rename: os.rename(src, dst). replace: os.replace(src, dst) — atomic. remove: os.remove(path). rmdir: os.rmdir(path). symlink: os.symlink(target, link). readlink: os.readlink(link). cpu_count: os.cpu_count(). getpid / getppid: os.getpid(). urandom: os.urandom(32) — crypto-secure bytes. Claude Code generates env loaders, file walkers, directory scanners, and deployment helpers.
CLAUDE.md for os
## os Stack
- Stdlib: import os; from pathlib import Path (prefer Path for new code)
- Env: os.getenv("KEY", "default") | os.environ["KEY"]
- Path: os.path.join(base, sub) — or Path(base) / sub
- Check: os.path.exists/isfile/isdir(path)
- Dir: os.makedirs(path, exist_ok=True)
- Walk: for root, dirs, files in os.walk(top):
- Rand: os.urandom(32) — crypto-safe bytes
os System Interface Pipeline
# app/osutil.py — env, path, walk, scandir, stat, process, urandom
from __future__ import annotations
import os
import stat
from pathlib import Path
from typing import Any, Callable, Iterator
# ─────────────────────────────────────────────────────────────────────────────
# 1. Environment helpers
# ─────────────────────────────────────────────────────────────────────────────
def require_env(key: str) -> str:
"""
Return env var value; raise EnvironmentError if missing.
Example:
secret = require_env("DATABASE_URL")
"""
val = os.environ.get(key)
if val is None:
raise EnvironmentError(f"Required environment variable {key!r} is not set")
return val
def load_env_subset(keys: list[str], defaults: dict[str, str] | None = None) -> dict[str, str]:
"""
Return a dict of specific env vars, using defaults for missing ones.
Example:
cfg = load_env_subset(["HOST", "PORT", "DEBUG"], defaults={"PORT": "8080"})
"""
defaults = defaults or {}
return {k: os.environ.get(k, defaults.get(k, "")) for k in keys}
def with_env(extra: dict[str, str]) -> dict[str, str]:
"""
Return os.environ merged with extra vars — suitable for subprocess env.
Example:
env = with_env({"NODE_ENV": "production", "PORT": "9000"})
subprocess.run(cmd, env=env)
"""
return {**os.environ, **extra}
# ─────────────────────────────────────────────────────────────────────────────
# 2. Path helpers (os.path style, for legacy/compatibility code)
# ─────────────────────────────────────────────────────────────────────────────
def join(*parts: str) -> str:
"""
Join path parts using os.path.join.
Example:
p = join("/var/data", "uploads", "img.png")
"""
return os.path.join(*parts)
def ensure_dir(path: str | Path, mode: int = 0o755) -> str:
"""
Create path and all parents if they don't exist. Return path.
Example:
ensure_dir("output/reports")
ensure_dir("/tmp/myapp/cache")
"""
os.makedirs(str(path), mode=mode, exist_ok=True)
return str(path)
def file_extension(path: str | Path) -> str:
"""
Return the final file extension (e.g. ".py"), lowercase.
Example:
file_extension("app.tar.gz") # ".gz"
file_extension("Makefile") # ""
"""
return os.path.splitext(str(path))[1].lower()
def stem(path: str | Path) -> str:
"""
Return filename without the last extension.
Example:
stem("report.2024.csv") # "report.2024"
"""
return os.path.splitext(os.path.basename(str(path)))[0]
def home_dir() -> str:
"""Return the current user's home directory."""
return os.path.expanduser("~")
# ─────────────────────────────────────────────────────────────────────────────
# 3. Directory scanning and walking
# ─────────────────────────────────────────────────────────────────────────────
def list_files(
directory: str | Path,
pattern: str | None = None,
recursive: bool = False,
) -> list[str]:
"""
List files in directory (absolute paths). Optionally filter by extension prefix.
Example:
py_files = list_files("src", pattern=".py", recursive=True)
all_files = list_files("dist")
"""
root = str(directory)
results = []
if recursive:
for dirpath, _, filenames in os.walk(root):
for f in filenames:
full = os.path.join(dirpath, f)
if pattern is None or f.endswith(pattern):
results.append(full)
else:
with os.scandir(root) as it:
for entry in it:
if entry.is_file(follow_symlinks=False):
if pattern is None or entry.name.endswith(pattern):
results.append(entry.path)
return sorted(results)
def walk_files(
root: str | Path,
extensions: set[str] | None = None,
skip_dirs: set[str] | None = None,
) -> Iterator[str]:
"""
Recursively walk a directory, yielding file paths.
Example:
for path in walk_files("src", extensions={".py", ".pyi"}, skip_dirs={"__pycache__"}):
process(path)
"""
skip = skip_dirs or set()
for dirpath, dirnames, filenames in os.walk(str(root)):
dirnames[:] = [d for d in dirnames if d not in skip]
for f in filenames:
if extensions is None or os.path.splitext(f)[1].lower() in extensions:
yield os.path.join(dirpath, f)
def dir_tree(root: str | Path, max_depth: int = 3, indent: int = 0) -> str:
"""
Return a text representation of a directory tree.
Example:
print(dir_tree("src", max_depth=2))
"""
root = str(root)
name = os.path.basename(root) or root
lines = [" " * indent + name + "/"]
if max_depth > 0 and os.path.isdir(root):
try:
entries = sorted(os.listdir(root))
except PermissionError:
return "\n".join(lines)
for entry in entries[:20]: # limit display
full = os.path.join(root, entry)
if os.path.isdir(full):
lines.append(dir_tree(full, max_depth - 1, indent + 1))
else:
lines.append(" " * (indent + 1) + entry)
return "\n".join(lines)
# ─────────────────────────────────────────────────────────────────────────────
# 4. File metadata and stat
# ─────────────────────────────────────────────────────────────────────────────
def file_info(path: str | Path) -> dict[str, Any]:
"""
Return a dict of file metadata.
Example:
info = file_info("app.py")
info["size_bytes"]
info["mtime"]
"""
p = str(path)
st = os.stat(p)
return {
"path": os.path.abspath(p),
"name": os.path.basename(p),
"size_bytes": st.st_size,
"mtime": st.st_mtime,
"is_file": os.path.isfile(p),
"is_dir": os.path.isdir(p),
"is_symlink": os.path.islink(p),
"readable": os.access(p, os.R_OK),
"writable": os.access(p, os.W_OK),
"executable": os.access(p, os.X_OK),
}
def newest_file(directory: str | Path, pattern: str | None = None) -> str | None:
"""
Return the most recently modified file in directory or None.
Example:
latest = newest_file("logs", ".log")
"""
files = list_files(directory, pattern=pattern)
return max(files, key=os.path.getmtime, default=None)
def total_size(path: str | Path) -> int:
"""
Return total bytes of all files under path (recursive).
Example:
mb = total_size("data") / 1_048_576
"""
total = 0
for _, _, filenames in os.walk(str(path)):
for f in filenames:
try:
total += os.path.getsize(os.path.join(_, f))
except OSError:
pass
return total
# ─────────────────────────────────────────────────────────────────────────────
# 5. Process and system info
# ─────────────────────────────────────────────────────────────────────────────
def process_info() -> dict[str, Any]:
"""
Return current process metadata.
Example:
info = process_info()
print(f"PID={info['pid']} on {info['cpu_count']} CPUs")
"""
return {
"pid": os.getpid(),
"ppid": os.getppid(),
"cwd": os.getcwd(),
"cpu_count": os.cpu_count(),
"uid": os.getuid() if hasattr(os, "getuid") else None,
"gid": os.getgid() if hasattr(os, "getgid") else None,
}
def secure_random(n: int = 32) -> bytes:
"""
Return n cryptographically secure random bytes from the OS.
Equivalent to os.urandom but with a clearer name.
Example:
key = secure_random(32) # 256-bit key
salt = secure_random(16) # 128-bit salt
nonce = secure_random(12) # AES-GCM nonce
"""
return os.urandom(n)
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
import tempfile
print("=== os demo ===")
print("\n--- require_env / load_env_subset ---")
os.environ["DEMO_HOST"] = "localhost"
os.environ["DEMO_PORT"] = "8080"
cfg = load_env_subset(["DEMO_HOST", "DEMO_PORT", "DEMO_DEBUG"], defaults={"DEMO_DEBUG": "false"})
print(f" cfg: {cfg}")
print("\n--- path helpers ---")
p = join("/var", "data", "uploads", "img.png")
print(f" join: {p!r}")
print(f" extension: {file_extension(p)!r}")
print(f" stem: {stem(p)!r}")
print(f" home: {home_dir()!r}")
print("\n--- directory scanning ---")
with tempfile.TemporaryDirectory() as td:
# Create test tree
ensure_dir(os.path.join(td, "src", "app"))
ensure_dir(os.path.join(td, "src", "__pycache__"))
for name in ["main.py", "utils.py", "README.md"]:
open(os.path.join(td, "src", name), "w").close()
for name in ["models.py", "cache.cpython-312.pyc"]:
open(os.path.join(td, "src", "app", name), "w").close()
py_files = list_files(os.path.join(td, "src"), pattern=".py", recursive=True)
print(f" .py files: {[os.path.basename(f) for f in py_files]}")
walked = list(walk_files(td, extensions={".py"}, skip_dirs={"__pycache__"}))
print(f" walk (skip pycache): {[os.path.basename(f) for f in walked]}")
print("\n--- dir_tree ---")
print(dir_tree(os.path.join(td, "src"), max_depth=2))
print("\n--- file_info ---")
main = os.path.join(td, "src", "main.py")
info = file_info(main)
print(f" name={info['name']!r} size={info['size_bytes']} readable={info['readable']}")
print("\n--- total_size ---")
sz = total_size(td)
print(f" total: {sz} bytes")
print("\n--- process_info ---")
info = process_info()
print(f" pid={info['pid']} cpu_count={info['cpu_count']} cwd={info['cwd']!r}")
print("\n--- secure_random ---")
key = secure_random(32)
print(f" 32 random bytes: {key.hex()[:24]}...")
print("\n=== done ===")
For the pathlib alternative — pathlib.Path (also stdlib) provides an object-oriented API for all the path operations in os.path with p / "sub" joining, p.read_text(), p.glob("*.py"), and .rglob() for recursive search — use pathlib.Path for new code dealing with files and directories (it’s now the recommended stdlib approach), os and os.path for code interoperating with legacy APIs, subprocess environments (env=), process attributes (os.getpid(), os.cpu_count()), and os.urandom() which have no pathlib equivalent. For the environs alternative — environs (PyPI) provides typed environment variable parsing: env.str("HOST"), env.int("PORT"), env.bool("DEBUG"), env.list("ALLOWED_HOSTS") with automatic casting and validation; os.environ.get() returns raw strings requiring manual casting — use environs or python-decouple in twelve-factor applications where strongly typed env var parsing with validation is critical, os.getenv in scripts, utilities, and library code where pulling a raw string value is sufficient. The Claude Skills 360 bundle includes os skill sets covering require_env()/load_env_subset()/with_env() environment helpers, join()/ensure_dir()/file_extension()/stem()/home_dir() path utilities, list_files()/walk_files()/dir_tree() directory scanning, file_info()/newest_file()/total_size() metadata helpers, and process_info()/secure_random() system utilities. Start with the free tier to try system interface automation and os pipeline code generation.