From pedantic-coder
This skill should be used when the user is organizing imports, writing require/use/include statements, fixing import ordering, dealing with circular dependencies, or when a file has disordered, ungrouped, or inconsistent imports. Covers import grouping, sorting, separation, and the rule that imports are the table of contents for a file.
npx claudepluginhub oborchers/fractional-cto --plugin pedantic-coderThis skill uses the workspace's default tool permissions.
The import block is the first thing a reader sees after the module docstring. It answers the most fundamental question about any file: what does this depend on? A disordered import block is like a book with a scrambled table of contents — it forces the reader to scan every line to understand the file's dependencies. This is not a cosmetic concern. It is a readability failure.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
The import block is the first thing a reader sees after the module docstring. It answers the most fundamental question about any file: what does this depend on? A disordered import block is like a book with a scrambled table of contents — it forces the reader to scan every line to understand the file's dependencies. This is not a cosmetic concern. It is a readability failure.
The rules are simple, universal, and non-negotiable: group by origin, separate groups with blank lines, alphabetize within groups, import only what you use, never import everything.
Every language has the same conceptual hierarchy. Adapt the specifics; preserve the structure.
Group 1: Standard library / built-in modules
(blank line)
Group 2: Third-party / external packages
(blank line)
Group 3: Internal / project-level modules
(blank line)
Group 4: Relative / sibling imports
Rules that apply everywhere:
Python's import conventions are well-established. Tools like isort and ruff enforce them automatically — but you must understand the rules to configure the tools correctly and to catch what they miss.
Grouping order:
# 1. __future__ imports (always first, always alone)
from __future__ import annotations
# 2. Standard library
import os
import sys
from collections import defaultdict
from pathlib import Path
# 3. Third-party packages
import httpx
import pydantic
from fastapi import FastAPI, HTTPException
from sqlalchemy import Column, Integer, String
# 4. Internal / project modules
from myapp.config import Settings
from myapp.database import get_session
from myapp.models import User
# 5. Relative / sibling imports
from .exceptions import NotFoundError
from .schemas import UserCreate, UserResponse
Critical Python rules:
from __future__ import annotations is always the very first import. No exceptions.import os (module import) vs from os import path (name import): prefer module imports for standard library to keep the namespace explicit. os.path.join() is clearer about origin than path.join().from module import * is banned. It pollutes the namespace, makes it impossible to trace where a name came from, and breaks static analysis.__all__ in __init__.py to declare the public API explicitly. Every name in __all__ must be deliberately chosen.ruff rule I (isort-compatible) or standalone isort with profile = "black".TypeScript imports have more variety (node builtins, npm packages, workspace packages, path aliases, relative paths) but the same grouping principle applies.
Grouping order:
// 1. Node built-in modules
import fs from "node:fs";
import path from "node:path";
// 2. External packages (npm)
import express from "express";
import { z } from "zod";
// 3. Organization-scoped packages
import { logger } from "@myorg/logger";
import { validateRequest } from "@myorg/middleware";
// 4. Internal path aliases (@/ or ~/)
import { db } from "@/database";
import { UserModel } from "@/models/user";
import { config } from "@/config";
// 5. Relative imports
import { NotFoundError } from "./errors";
import { userSchema } from "./schemas";
import type { UserCreateInput } from "./types";
Critical TypeScript rules:
node: prefix: import fs from "node:fs", not import fs from "fs". The prefix eliminates ambiguity with npm packages that shadow built-in names.type imports use import type { ... } — this is not optional when verbatimModuleSyntax is enabled, and it signals to the reader (and bundler) that the import is erased at runtime.import { everything } from "./index") are acceptable for re-export modules but dangerous when they pull in large dependency trees. If your barrel import causes circular dependencies or bloated bundles, import from the specific file.import/order rule or eslint-plugin-simple-import-sort.Go's import conventions are the strictest and the best-tooled. goimports handles formatting automatically, but you must still structure imports correctly for readability.
Grouping order:
import (
// 1. Standard library
"context"
"fmt"
"net/http"
"time"
// 2. External packages
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5"
"go.uber.org/zap"
// 3. Internal packages
"myapp/internal/config"
"myapp/internal/database"
"myapp/internal/models"
)
Critical Go rules:
goimports (or gofumpt which includes it) to auto-format. But verify it groups correctly — some versions do not separate internal from external.import . "testing") are banned outside of test files using frameworks that require them (and even then, use sparingly).import _ "database/sql") are only acceptable for side-effect registration (e.g., database drivers). Always add a comment explaining why: import _ "github.com/lib/pq" // register PostgreSQL driver.import pg "github.com/jackc/pgx/v5" when two packages have the same name.Inline imports (importing inside a function instead of at the top of the file) are a code smell by default. They break the "table of contents" contract — the reader cannot see all dependencies at a glance.
Acceptable ONLY in these cases:
Documented circular dependency. Two modules that must reference each other, where a top-level import creates a cycle. The inline import breaks the cycle. Always add a comment:
def get_user_orders(user_id: str) -> list:
# Inline import to break circular dependency: models -> services -> models
from myapp.services.orders import OrderService
return OrderService.find_by_user(user_id)
Conditional heavy import. A module that is expensive to load (e.g., ML model, large data file) and only needed in a rarely-executed code path:
def generate_report():
# Lazy import: pandas is only needed for reporting, not on every request
import pandas as pd
...
Optional dependency. A feature that works with or without a package:
try:
import orjson as json # Faster JSON if available
except ImportError:
import json
In all three cases, the comment explaining WHY is mandatory. An inline import without an explanation is a violation.
from module import * is banned. In every language. Without exception.
Why:
# BAD — where does Request come from? Flask? Django? A local module?
from flask import *
from myapp.models import *
# GOOD — every dependency is traceable
from flask import Flask, Request, jsonify
from myapp.models import User, Order
// BAD
export * from "./models";
export * from "./utils";
// If models and utils both export "validate", which one wins?
// GOOD — explicit re-exports
export { User, Order } from "./models";
export { formatDate, parseId } from "./utils";
Centralize public APIs through index files, but make them explicit.
# myapp/models/__init__.py
from .user import User
from .order import Order
from .product import Product
__all__ = ["Order", "Product", "User"] # Alphabetized. Always.
// models/index.ts
export { Order } from "./order";
export { Product } from "./product";
export { User } from "./user";
// Alphabetized. Explicit. No star re-exports.
Delete them. Immediately. Not after the feature is done. Not when the linter runs. Now.
An unused import is:
"But I might need it later" is not a reason. Version control exists. Import it again when you need it. The 3 seconds of re-typing are cheaper than the permanent tax of a false dependency.
Working implementations in examples/:
examples/import-ordering.md — Multi-language examples (Python, TypeScript, Go) showing properly organized imports with correct grouping, separation, alphabetization, and common violations fixed.When writing or reviewing import blocks:
from x import *, export * from)from __future__ is the very first import if presentnode: prefix; type-only imports use import typeimport _) have a comment explaining the side effect__init__.py / index.ts with explicit names, not star exports__all__ (Python) and export statements are alphabetized