# Developer Experience

> Audit and improve developer-facing documentation, language tooling, editor support, formatting, linting, test granularity, test doubles, and contributor commands while preserving runtime behavior. Use when a repository needs clearer onboarding, reliable language-server or type-checker feedback, less noisy or faster lint checks, a balanced unit-to-external test strategy, consistent local and CI workflows, or a measured developer-experience cleanup.

- Skill: `iyoda/developer-experience` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add iyoda/developer-experience`
- Raw SKILL.md: https://api.skillmd.com/api/skills/iyoda/developer-experience/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: iyoda (https://skillmd.com/u/iyoda)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/iyoda/developer-experience

---


# Developer Experience

Improve the path from checkout to a trustworthy change. Treat documentation, language
support, linting, formatting, and test commands as one developer-facing product, but
change each concern only when repository evidence justifies it.

## Operating rules

- Read the applicable `AGENTS.md`, `README`, contribution guide, build files, CI files,
  and package configuration before editing.
- Preserve user changes and keep the diff small, reviewable, and reversible.
- Prefer existing commands, utilities, and configuration. Do not add a dependency or
  replace a tool without an explicit request and a concrete benefit.
- Do not weaken a check by hiding files, lowering severity, or adding broad ignores just
  to make the suite green. Every exclusion needs a scope, reason, and owner.
- Keep developer-experience changes separate from production behavior changes. If a
  configuration change affects runtime, packaging, generated artifacts, or deployment,
  lock the behavior with a regression test before changing it.
- Preserve environment boundaries. Record which interpreter, runtime, package manager,
  service, or external credential a command needs; never imply that a command is
  hermetic when it is not.

## Workflow

### 1. Establish the baseline

1. Inspect `git status` and avoid unrelated or pre-existing edits.
2. Map the repository with `rg --files`, then locate `AGENTS.md`, README files, build
   entrypoints, CI workflows, package manifests, editor settings, formatter configs,
   linter configs, type-checker configs, and test configuration.
3. Identify supported languages, runtime versions, package managers, and environment
   splits. Record the shortest working commands for install, lint, type check, tests,
   and a smoke check.
4. Run the narrowest relevant baseline checks. Capture duration, warnings, failures,
   missing-tool errors, and whether output is actionable.
5. Write a short cleanup plan before modifying code or configuration. Rank findings by
   developer impact: blocked onboarding, misleading instructions, broken diagnostics,
   noisy checks, slow checks, then cosmetic consistency.

### 2. Repair developer-facing documentation

For each maintained guide, make the happy path executable:

- State prerequisites, supported versions, environment selection, and the expected
  result of each important command.
- Give one canonical command for common work. Explain alternatives only when they
  represent a real runtime or safety boundary.
- Keep command names, paths, environment variables, service names, and terminology
  consistent with the implementation. Search for stale paths, retired identifiers,
  duplicate rules, and references to missing plans or tools.
- Put failure recovery next to the command that can fail. Distinguish local failures,
  optional integrations, credential-gated operations, and production actions.
- Prefer concise task-oriented prose. Use headings that answer contributor questions:
  what it does, when to use it, what it needs, and how to verify it.
- When multiple human languages are present, choose the repository's primary language
  from existing contribution practice. Translate explanations consistently while
  preserving code symbols, command names, error text, and protocol vocabulary. Do not
  translate identifiers or invent parallel terminology.
- Remove prose that merely restates implementation, historical plans, or obsolete
  policy. Keep historical decisions in Git history or an explicitly maintained archive.

### 3. Improve language and editor support

Audit language support as a diagnostic pipeline, not as a list of fashionable tools:

1. Identify the language server, formatter, type checker, import resolver, and test
   adapter already used by contributors or CI.
2. Check that each tool targets the supported language/runtime version and resolves the
   same source roots, generated files, optional dependencies, and sibling packages as
   the test runner.
3. Prefer one clear tool per responsibility. Remove conflicting settings and duplicate
   editor instructions before introducing new configuration.
4. Separate syntax, style, type, and runtime checks. A type checker must not be used as
   a substitute for tests, and a formatter must not silently alter generated or vendored
   files.
5. Verify diagnostics on representative valid and invalid examples. Confirm that the
   failure points to an actionable file and line, exits non-zero, and does not require
   unavailable services unless the check is explicitly integration-only.
6. Document editor setup only to the degree needed for a contributor to reproduce the
   repository's supported checks. Avoid editor-specific rules that contradict CI.

For Python repositories, inspect `pyproject.toml`, `pytest` configuration, virtualenv or
conda entrypoints, `PYTHONPATH`, and package import boundaries together. Test each
interpreter-specific command rather than assuming bare `python` is equivalent to a
project-managed interpreter.

### 4. Make linting useful

- Establish a baseline before changing rules: runtime, warning count, failure count,
  files covered, and whether the output is stable.
- Classify findings as correctness, maintainability, security, portability, or style.
  Prioritize checks that catch defects or shorten review; defer subjective style noise.
- Keep fast, deterministic checks suitable for every local change separate from slow,
  integration, network, generated-code, or environment-dependent checks.
- Scope exclusions narrowly to generated, vendored, archived, or intentionally special
  files. Explain non-obvious exclusions in the config or adjacent documentation.
- Use the repository's existing formatter and import ordering rules. Avoid a mass
  reformat when a targeted change can solve the problem.
- Check that lint output is readable locally and machine-readable in CI, with stable
  exit codes and a command contributors can run without hidden wrapper state.
- If a new check is justified, add it in the smallest enforceable mode, document its
  invocation, and prove that it catches a representative defect without unacceptable
  false positives or runtime cost.

### 5. Choose test granularity and doubles

Choose the smallest test that crosses the failure boundary being changed, then add a
higher-level test only when it protects wiring or behavior that lower-level tests cannot
observe:

- Use unit tests for pure transformations, state machines, validation, and error
  decisions. Keep them fast, deterministic, and independent of network, clocks, random
  seeds, processes, and persistent services unless those are the behavior under test.
- Use component or contract tests for module boundaries, serialization, CLI protocols,
  persistence adapters, and dependency wiring. Verify the boundary contract rather than
  repeating every internal branch already covered by unit tests.
- Use integration tests with real local or ephemeral dependencies when correctness
  depends on SQL behavior, filesystem semantics, serialization libraries, process
  boundaries, or framework configuration. Prefer a small number of high-signal cases to
  a large collection of mocked integration scenarios.
- Use external tests for live APIs, credentials, broker or cloud behavior, and other
  environment-dependent contracts. Mark them explicitly, gate them with the repository's
  required environment variable or test marker, set timeouts and cleanup, redact secrets,
  and make prerequisite failures obvious. Never let a missing external service silently
  fall back to a fake while reporting success.

Select test doubles by the behavior they preserve:

- Prefer a real collaborator when it is cheap, deterministic, and stable.
- Use a fake when a deterministic in-memory or local substitute can preserve the public
  contract and exercise meaningful behavior.
- Use a stub to provide a narrow input, return value, or failure. Keep the assertion on
  the resulting behavior rather than the stub's implementation.
- Use a spy only for an observable side effect or protocol that is itself part of the
  contract. Assert semantic events, not incidental call order or private helper calls.
- Use a mock sparingly, mainly when an interaction contract, failure timing, or expensive
  boundary cannot be tested otherwise. Do not mock internal methods of the subject under
  test or every collaborator in a test that claims to cover integration.

Balance the suite by tracking defect detection, runtime, flakiness, setup cost, and
maintenance cost. Keep deterministic unit and selected contract checks on every change;
run local integration checks before merge; reserve network, credential, broker, and other
external checks for explicit pre-release, scheduled, or manually authorized runs. Delete
or consolidate duplicate tests when a higher-fidelity test protects the same contract,
but retain a lower-level test when it gives materially faster and clearer diagnosis.

### 6. Implement and verify

Make one smell-focused pass at a time. Update documentation and configuration together
when one describes the other, and add or adjust regression tests for behavior-sensitive
changes. Then run, in order:

1. The changed documentation or command-contract tests.
2. The targeted formatter, linter, language-server, or type-checker checks.
3. The relevant fast test subset and smoke check.
4. The repository's documented full gate when practical.
5. `git diff --check` and searches for stale commands, paths, identifiers, and duplicate
   guidance in the active tree.

Read the outputs; do not infer success from exit codes alone when a tool can skip files
or emit warnings. Report exact commands, interpreter/tool versions when relevant,
duration changes, remaining environment-dependent checks, and any validation gap.

## Deliverable shape

Return a compact evidence-based report containing:

- baseline friction and ranked findings;
- files and behavior changed, including deleted or consolidated guidance;
- the canonical contributor commands after the change;
- validation commands and results, including before/after timing when optimization was
  requested;
- remaining risks, unsupported environments, and intentionally deferred improvements.

Do not claim that a repository has full language or lint support merely because a config
file exists. Claim support only after the command runs against the intended source set
and produces actionable diagnostics.

