一键导入
coding-ethos-agent-workflow
Use when an agent needs to choose the correct coding-ethos MCP, cerun, managed lint, code-intel, or remediation path before acting.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when an agent needs to choose the correct coding-ethos MCP, cerun, managed lint, code-intel, or remediation path before acting.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when implementing, reviewing, refactoring, simplifying, debugging, or planning code changes that need explicit assumptions, minimal scope, surgical edits, and verifiable success criteria.
Use when an agent needs to run lint, formatting, type checks, or policy-backed diagnostics. Prefer the MCP managed_lint tool, then the ./bin/lint wrapper, instead of invoking raw Ruff, mypy, uvx, host linters, or package-manager shortcuts.
Use when captured linters, generated tool configs, managed binaries, config drift, missing tools, package-relative path resolution, or host tool usage causes lint or hook failures.
Use when git commands, commit hooks, admin-approved commits, protected hook paths, raw git bypass attempts, or commit attribution failures appear in agent or developer workflows.
Use when Ruff, mypy, pyright, pylint, Bandit, SQLFluff, Tombi, or another managed checker reports findings that need structural code-quality remediation rather than suppressions or config weakening.
| name | coding-ethos-agent-workflow |
| description | Use when an agent needs to choose the correct coding-ethos MCP, cerun, managed lint, code-intel, or remediation path before acting. |
| metadata | {"source":"coding_ethos.yml","generated_by":"coding-ethos","ethos_principles":["one-path-for-critical-operations","evidence-based-engineering-and-decision-quality","radical-visibility","security-by-design"]} |
Use this skill as the default operating map for coding-ethos-enabled repos. It tells agents which first-class surface to use instead of falling back to raw shell, raw Git, host linters, or whole-repo reads.
one-path-for-critical-operations: Keep one explicit, validated path for critical operations.evidence-based-engineering-and-decision-quality: Understand, plan, execute, and validate with evidence; measure before
optimizing and make trade-offs explicit.radical-visibility: Log important decisions with context and instrument the system with metrics.security-by-design: Design for least privilege, validation, and safe defaults from the start.Start with MCP orientation and preflight tools, then execute through cerun or managed_lint only when the policy path says it is appropriate.
When there are multiple ways to accomplish a critical operation, bugs hide in the less-traveled path.
Directive: Keep one explicit, validated path for critical operations.
Quick ref:
When there are multiple ways to accomplish a critical operation, bugs hide in the less-traveled path. We enforce a single, canonical path for operations that matter.
We strictly ban boolean parameters that fundamentally change what a function does.
A parameter like persist: bool = True creates two different
functions
masquerading as one. Callers must understand not just what the
function
does, but which version they're invoking. This is a recipe for
confusion
and bugs.
The Anti-Pattern (Forbidden):
# ❌ WRONG: Boolean switch creates two code paths
async def onboard_dataframe(
self,
entity_id: str,
dataframe: DataFrame,
*,
persist: bool = True, # This creates a fork in behavior
) -> ProcessingResult:
result = self._compute_schema_and_stats(dataframe)
if persist: # One code path: compute AND store
await self._store_metadata(entity_id, result)
await self._store_statistics(entity_id, result)
return result # Other code path: compute only
Why This Is Dangerous:
persist=True bypassed ULID generation because it wasn't the
canonical
persistence path.If an operation can be decomposed, decompose it. If persistence must happen, it happens through ONE designated service.
# ✅ CORRECT: Function does ONE thing
async def onboard_dataframe(
self,
entity_id: str,
dataframe: DataFrame,
) -> ProcessingResult:
"""Compute schema and statistics for a dataframe.
This function ONLY computes. It does NOT persist.
Persistence is handled by EntityMetadataService.ingest_dataset().
"""
return ProcessingResult(
schema=self._infer_schema(dataframe),
profile=self._compute_statistics(dataframe),
)
# ✅ CORRECT: Orchestration layer calls the ONE persistence path
async def ingest(self, request: IngestionRequest) -> IngestionResponse:
onboarding_result = await onboarding_service.onboard_dataframe(...)
# THE canonical path for persistence—generates ULID, stores everything
await dataset_service.ingest_dataset(entity_id, metadata_payload)
Watch for these warning signs:
persist, save, commit, execute, dry_run,
skip_*if/else blocksRepos must define one documented way to run quality gates locally.
If a repo documents make check, pre-commit run --all-files, or
another
validation entrypoint, use that path.
Do not substitute a hand-picked subset and then claim the work is validated.
Alternate commands may exist for debugging, but only the canonical gate proves readiness.
A dry_run parameter is acceptable ONLY at the outermost API boundary
(CLI
commands, REST endpoints) where the user explicitly requests a
preview. It
must:
# ✅ ACCEPTABLE: CLI dry-run for user preview
@cli.command()
def ingest(path: Path, dry_run: bool = False):
"""Ingest a dataset. Use --dry-run to preview without persisting."""
result = service.ingest(path, dry_run=dry_run)
# dry_run affects the FINAL write, not internal behavior
def process(data, save: bool = True) — modal persistencedef validate(schema, strict: bool = False) — if strictness
matters,
make two functionsdef fetch(url, cache: bool = True) — caching is infrastructure,
not a
per-call decisionpersist, commit, or store boolean
parametersFor any critical operation, ask: "Is there exactly ONE way to do this correctly?" If the answer involves "it depends on a boolean parameter," the design is wrong. Split the function, or designate a single orchestration point.
Good engineering decisions are grounded in evidence, explicit trade-offs, and calibrated risk.
Directive: Understand, plan, execute, and validate with evidence; measure before optimizing and make trade-offs explicit.
Quick ref:
We do not treat engineering judgment as intuition dressed up as confidence. Good decisions are grounded in evidence, explicit trade-offs, and calibrated risk.
Core directive: Evidence > assumptions. Runnable behavior, tests, metrics, and credible primary sources outrank speculation and unsupported prose. Documentation remains a contract, but prose cannot excuse behavior the system does not actually implement.
Communication directive: Efficiency > verbosity. Be concise when possible, but not at the cost of correctness, evidence, or important nuance.
The default execution loop is:
Efficiency matters, so independent reads and checks should be batched where possible. Context also matters: preserve enough local understanding to avoid redundant work or contradictory edits across sessions and operations.
Every change has ripple effects. Evaluate the immediate local win against architecture-wide consequences, long-term maintenance cost, and the options you may close off by acting too narrowly.
When making a decision, ask:
Prefer designs that keep future choices open unless the stronger constraint is itself a deliberate requirement.
Optimization without measurement is guesswork. Performance claims, reliability claims, and architecture claims should be backed by evidence that can be inspected or reproduced.
The expected pattern is:
If the evidence is weak, say so directly and reduce the claim strength accordingly.
Risk management is not fear-driven paralysis; it is disciplined foresight. Anticipate the likely failure modes before they become production incidents, security regressions, or migration traps.
For meaningful changes:
Security risk, data-loss risk, migration risk, and operator-confusion risk should be considered explicitly, not absorbed into a vague notion of "complexity."
Evaluate changes through four quality lenses:
Prefer preventive measures and automated enforcement whenever practical; they catch issues earlier and more consistently than manual heroics. When a design decision affects end users or operators, human welfare and autonomy matter: do not trade away safety, clarity, or informed control for superficial convenience.
We believe that if an event wasn't logged, it didn't happen.
Directive: Log important decisions with context and instrument the system with metrics.
Quick ref:
We believe that if an event wasn't logged, it didn't happen. Logging is not a debugging tool to be added later; it is a primary feature of the system.
Because we rely on dependency injection and protocols, control flow can be complex. Detailed logging allows us to reconstruct the execution path of any request post-mortem.
Logs tell us what happened. Metrics tell us how often and how fast. Both are mandatory.
status, operation, component.The Correct Way:
from app.observability.tracing import (
increment_counter,
record_histogram,
traced,
)
@traced("ingestion.process_file", {"component": "ingestion"})
async def process_file(self, path: Path) -> ProcessResult:
start = time.perf_counter()
try:
result = await self._do_process(path)
increment_counter("app.files_processed_total", {"status": "success"})
return result
finally:
duration_ms = (time.perf_counter() - start) * 1000
record_histogram("app.process_duration_ms", duration_ms)
If you cannot answer "How many times did X happen last hour?" or "What is the p99 latency of Y?"—your code is incomplete.
Security is not a feature to be added later—it is a property of the design.
Directive: Design for least privilege, validation, and safe defaults from the start.
Quick ref:
Security is not a feature to be added later—it is a property of the design. We build security in from the start.
Secrets, credentials, and API keys must never appear in source code, configuration files, or commit history.
.env
files)The Anti-Pattern (Forbidden):
# ❌ WRONG: Hardcoded secrets
API_KEY = "sk-abc123..." # NEVER
DATABASE_URL = "postgresql://admin:password123@prod-db/..." # NEVER
# ❌ WRONG: "Example" secrets that become real
API_KEY = os.getenv("API_KEY", "sk-test-key-for-development") # Still wrong
The Correct Way:
# ✅ CORRECT: Secrets from environment, no defaults
API_KEY = os.environ["API_KEY"] # Fails if not set - good
# ✅ CORRECT: Explicit configuration validation
@dataclass
class Config:
api_key: str = field(default_factory=lambda: os.environ["API_KEY"])
def __post_init__(self) -> None:
if not self.api_key:
raise ConfigurationError(
"API_KEY environment variable is required"
)
SQL injection is a solved problem. We solve it by using parameterized queries exclusively.
The Anti-Pattern (Forbidden):
# ❌ CATASTROPHIC: String formatting SQL
query = f"SELECT * FROM users WHERE id = {user_id}" # SQL injection
query = "SELECT * FROM users WHERE name = '%s'" % name # SQL injection
The Correct Way:
# ✅ CORRECT: Parameterized queries
query = "SELECT * FROM users WHERE id = $1"
result = await conn.fetch(query, user_id)
# ✅ CORRECT: Using query builder with parameterization
query = select(users).where(users.c.id == bindparam("user_id"))
result = await conn.execute(query, {"user_id": user_id})
All external input is untrusted. Validate at the boundary, then trust internally.
Operations that could harm production must detect and refuse production environments.
# ✅ CORRECT: Production safety guard
async def reset_database(conn: Connection) -> None:
"""Reset database to clean state. NEVER runs in production."""
db_name = await conn.fetchval("SELECT current_database()")
if "prod" in db_name.lower(): # Add your production DB name check here
raise SecurityError(
f"Refusing to reset production database: {db_name}",
database=db_name,
)
await conn.execute("DROP SCHEMA public CASCADE")
Repos should automatically detect obvious security regressions before commit and in CI.
Secret scanning, unsafe query detection, boundary validation, and environment-safety guards should be machine-enforced where the repo can express them.
If a repo ships security hooks, they are part of the build contract and must not be bypassed casually.
The Rule: Security is not optional. It is validated, enforced, and designed into every component. If a security measure can be bypassed, it's not a security measure—it's a suggestion.
When explaining a fix, name the ETHOS principle, the concrete code change, and the verification evidence. Do not recommend weakening lint config or adding suppressions unless the ETHOS policy explicitly allows it.