Hugging Face Local Model Evals
huggingface/skills
Runs evaluations of Hugging Face Hub models on local hardware with inspect-ai or lighteval, and helps choose between vLLM, Transformers and accelerate backends.
A skill your agent uses when adding a new optimized kernel or operator to veomni/ops/.
$ npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ByteDance-Seed/VeOmni veomni-new-op --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ByteDance-Seed/VeOmni.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/veomni-new-op .claude/skills/veomni-new-op && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "veomni-new-op" agent skill from https://github.com/ByteDance-Seed/VeOmni/tree/main/.agents/skills/veomni-new-op into .claude/skills/veomni-new-op/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "veomni-new-op", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ByteDance-Seed/VeOmni/tree/main/.agents/skills/veomni-new-opType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ByteDance-Seed/VeOmni veomni-new-op --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ByteDance-Seed/VeOmni.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/veomni-new-op .agents/skills/veomni-new-op && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "veomni-new-op" agent skill from https://github.com/ByteDance-Seed/VeOmni/tree/main/.agents/skills/veomni-new-op into .agents/skills/veomni-new-op/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "veomni-new-op", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ByteDance-Seed/VeOmni veomni-new-op --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ByteDance-Seed/VeOmni.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/veomni-new-op .cursor/skills/veomni-new-op && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "veomni-new-op" agent skill from https://github.com/ByteDance-Seed/VeOmni/tree/main/.agents/skills/veomni-new-op into .cursor/skills/veomni-new-op/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "veomni-new-op", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ByteDance-Seed/VeOmni.git --path .agents/skills/veomni-new-op--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ByteDance-Seed/VeOmni veomni-new-op --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ByteDance-Seed/VeOmni.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/veomni-new-op .gemini/skills/veomni-new-op && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "veomni-new-op" agent skill from https://github.com/ByteDance-Seed/VeOmni/tree/main/.agents/skills/veomni-new-op into .gemini/skills/veomni-new-op/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "veomni-new-op", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ByteDance-Seed/VeOmni veomni-new-opInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ByteDance-Seed/VeOmni.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/veomni-new-op .github/skills/veomni-new-op && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "veomni-new-op" agent skill from https://github.com/ByteDance-Seed/VeOmni/tree/main/.agents/skills/veomni-new-op into .github/skills/veomni-new-op/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "veomni-new-op", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ByteDance-Seed/VeOmni veomni-new-op --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ByteDance-Seed/VeOmni.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/veomni-new-op .opencode/skills/veomni-new-op && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "veomni-new-op" agent skill from https://github.com/ByteDance-Seed/VeOmni/tree/main/.agents/skills/veomni-new-op into .opencode/skills/veomni-new-op/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "veomni-new-op", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
veomni-new-opA skill your agent uses when adding a new optimized kernel or operator to veomni/ops/.
Veomni New Op is an agent skill from ByteDance-Seed/VeOmni. Use this skill when adding a new optimized kernel or operator to veomni/ops/. Covers the full lifecycle: understanding VeOmni's ops architecture (KERNELREGISTRY + OpSlot dispatch, with a thin function-pointer shim for a few legacy global ops), implementing the kernel, registering it, adding tests, and documenting it. Trigger: 'add op', 'new kernel', 'add attention variant', 'new fused op', 'add triton kernel', 'optimize operator'.
Its SKILL.md is about 3.1k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in AI & LLM Engineering, covering GPU and accelerator computing. The repository describes itself as: VeOmni: Scaling Any Modality Model Training with Model-Centric Distributed Recipe Zoo. The licence is Apache-2.0.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 8791a71. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pytestmakeFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Veomni New Op loads about 3.1k tokens when it runs. Until then it costs about 112 tokens; SKILL.md has 1,202 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from ByteDance-Seed/VeOmni at commit 8791a71, republished under its Apache-2.0 licence (© ByteDance-Seed). 1,202 words, ~3,110 tokens.
.claude/skills/veomni-new-op/SKILL.md (or your agent's skills folder)..agents/knowledge/constraints.md — especially the "Hardware" section
(NPU guards, device-agnostic helpers) and "Module-level OpSlots are shared by
every model instance" under "Trainer Extensions".docs/design/kernel_selection.md and docs/design/unified_kernel_registry.md — understand the kernel lifecycle, the KERNEL_REGISTRY, and OpSlot dispatch.Most VeOmni ops in v5 are registry-driven: a kernel registers itself in
veomni.ops.kernel_registry.KERNEL_REGISTRY and is dispatched at model-build
time through OpSlot instances declared in the patchgen-generated modeling
files (see veomni/ops/dispatch.py and _bind_veomni_ops() in
veomni/models/auto.py).
veomni/ops/
├── __init__.py # apply_ops_patch / apply_ops_config entry points
├── kernel_registry.py # KERNEL_REGISTRY (the single source of truth)
├── dispatch.py # OpSlot + binding helpers
├── config/ # legacy OpSpec/BackendSpec registry: apply_global_ops()
│ # + apply_per_model_patches() for device_patch.py models
├── kernels/ # all registry-driven kernels
│ ├── attention/ # FA2/3/4 + sequence-parallel wrappers
│ ├── cross_entropy/ # eager + liger fused CE
│ ├── deepseek_sparse_attention/
│ ├── deepseek_v4/ # TileLang sparse attention / indexer
│ ├── load_balancing_loss/
│ ├── mhc/ # TileKernels DeepSeek V4 adapters
│ ├── moe/ # fused MoE (group_gemm / quack / npu_group_gemm)
│ ├── rms_norm/ # eager / liger / batch-invariant
│ ├── rotary/ # default / triton-deterministic
│ ├── swiglu/ # eager / liger
│ └── gated_delta_rule/
├── batch_invariant_ops/ # ATen-level interception for bitwise determinism
├── liger/ # Liger kernel adapters
└── platform/ # NPU-specific helpersThree mechanisms coexist. Pick the first one unless you have a concrete reason not to:
KERNEL_REGISTRY + OpSlot (preferred for new ops). Each kernel
registers itself under a (slot_name, variant) pair (e.g.
("cross_entropy_loss", "causal"), ("moe_experts", "standard")).
Patchgen-generated modeling code declares matching OpSlot instances; at
model-build time _bind_veomni_ops() walks the generated module, finds
each OpSlot, and binds it to the concrete registry entry chosen by
OpsImplementationConfig (config/registry.py).fused_moe_forward and load_balancing_loss still expose a thin pointer
that is rebound by apply_ops_config() so call sites in non-patchgen code
(DeepSeek MLA inference paths, NPU custom forwards) can keep importing the
public name without going through an OpSlot.device_patch.py via OpSpec/BackendSpec in
ops/config/registry.py. apply_per_model_patches(hf_module, model_name, targets={op: attr}) setattr-replaces attributes on an HF module. Used by the
models that have no patchgen-generated file (wan) or that need a runtime
device-specific swap after generation (deepseek_v3, deepseek_v4). Those
three device_patch.py files are its only callers. Do not extend this for
new kernels.Mechanism 1 covers any kernel living inside a patchgen-generated modeling file.
Use 2 only when the kernel must be callable from unpatched (or
non-Transformers) Python code, and 3 only when touching a model that already
ships a device_patch.py.
Determine op category:
(slot_name, variant) in KERNEL_REGISTRY and add a matching OpSlot in the relevant <model>_patch_gen_config.py. No global mutation; selection is driven by OpsImplementationConfig.fused_moe_forward, load_balancing_loss): expose a public function in veomni/ops/__init__.py and rebind it from apply_ops_config() based on the active OpsImplementationConfig. Only use this when a non-patchgen call site (NPU MLA forward, manual inference scripts, etc.) needs to import the kernel directly.is_torch_npu_available() guard.Decide selection mechanism: read docs/design/kernel_selection.md and docs/design/unified_kernel_registry.md to determine if you need:
OpsImplementationConfig (veomni/arguments/arguments_types.py)Determine binding timing:
_bind_veomni_ops() in veomni/models/auto.py when a model is constructed. New kernels just need to register themselves at import time.apply_ops_config() time: legacy global ops (rebound function pointers) are wired in veomni/ops/__init__.py::apply_ops_config(ops_config).Create the op directory under veomni/ops/kernels/<op_name>/.
Implement each kernel variant in its own file (e.g. triton_kernel.py, eager.py, npu_kernel.py). Each variant declares a concrete function with the kernel's canonical signature.
Register the kernel in veomni/ops/kernels/<op_name>/__init__.py. One
KERNEL_REGISTRY.register(KernelSpec(...)) call per implementation —
register() takes a single KernelSpec and returns None, so it is not a
decorator:
from veomni.ops.kernel_registry import KERNEL_REGISTRY, HardwareRequirement, KernelSpec
def _my_op_triton_factory():
from .triton_kernel import my_op_triton # imported only when selected
return my_op_triton
KERNEL_REGISTRY.register(
KernelSpec(
name="triton", # impl name the user selects in the config
op_name="my_op", # the logical op — matches the OpSlot
variant="standard", # op shape, when one op has several
factory=_my_op_triton_factory,
hardware=HardwareRequirement(device_type="gpu"),
description="Triton my_op",
)
)factory is a zero-argument callable returning the kernel, not the
kernel itself. Keeping it lazy is what stops an optional dependency (Liger,
Triton, torch_npu) from being imported just because the module was loaded.
hardware is enforced at resolve() time, so an unavailable kernel fails
with a clear error instead of at first use.
Mind the two axes: (op_name, variant) identifies the slot, name
identifies the implementation within it. Kernels in different variants
never collide.
Then declare a matching OpSlot in the patchgen config of every model that
uses it — the arguments are (op_name, variant), not an implementation:
from veomni.ops.dispatch import OpSlot
veomni_my_op = OpSlot("my_op", "standard")_bind_veomni_ops() calls slot.bind(impl_name) with the implementation
selected by OpsImplementationConfig. See
veomni/ops/kernels/rotary/__init__.py for a live example, and
veomni/ops/README.md for the op/variant/impl table.
Wire the config field (if the user needs to choose an implementation):
OpsImplementationConfig in veomni/arguments/arguments_types.py.register_op(OpSpec(name=..., config_field=..., scope=..., default=..., backends={...}))
from the same veomni/ops/kernels/<op_name>/__init__.py — the mapping
lives next to the kernel, not inside veomni/ops/config/registry.py,
which only defines OpSpec / BackendSpec / register_op. See
veomni/ops/kernels/rms_norm/__init__.py, which registers both an
OpSpec and its KernelSpecs.For legacy global ops (only when needed): add the public function to veomni/ops/__init__.py and rebind it from apply_ops_config(ops_config).
Async Ulysses split wrappers (only for rms_norm and rotary_pos_emb): compound Functions cannot call OpSlot. They use no-autograd (output, saved) / backward pairs in veomni/distributed/sequence_parallel/op_wrappers.py. A new backend or variant must either add a matching wrapper there, or be left off _SUPPORTED_IMPLEMENTATIONS / _SUPPORTED_VARIANTS so get_op_wrapper rejects it. KERNEL_REGISTRY coverage is not enough.
NPU support:
is_torch_npu_available().npu_kernel.py).Add unit tests to tests/ops/. The GPU job runs this directory
wholesale, so a new file needs no gpu_unit_tests.yml change. The NPU job
does not — it enumerates ops files by name, so if the kernel must run on
Ascend, add a line to npu_unit_tests.yml (see
.agents/knowledge/testing.md):
Add benchmark (optional but recommended for performance-critical ops):
veomni/ops/kernels/moe/_kernels/utils/benchmark_utils.py as referenceRun: pytest tests/ops/ -v
Update docs/design/kernel_selection.md:
Update .agents/knowledge/architecture.md if the op adds a new subdirectory to veomni/ops/.
make quality.KERNEL_REGISTRY.dump() and that the relevant OpSlot is rebound after build_foundation_model./veomni-review over the branch diff — a new kernel touches veomni/, so the gate applies.KERNEL_REGISTRY: the variant is invisible to _bind_veomni_ops() and OpSlot will fall through to its default — you'll silently exercise the wrong kernel.OpSlot to the patchgen config: registering a kernel alone has no effect — generated modeling code must declare an OpSlot for it to be picked up.is_torch_npu_available() guard crashes on GPU-only environments.build_foundation_model runs _bind_veomni_ops(). Kernels that depend on per-model config must be picked at that point — not at module-import time.rms_norm / rotary_pos_emb backend without an async wrapper: OpSlot will bind, but async Ulysses goes through op_wrappers.py, not the registry callable. Add a split wrapper or confirm get_op_wrapper rejects the new name; do not derive the supported set from KERNEL_REGISTRY.get_parallel_state().sp_enabled to check and dispatch.veomni/ops/__init__.py's __all__.© ByteDance-Seed, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .agents/skills/veomni-new-op of ByteDance-Seed/VeOmni.
Open the folder on GitHubat commit 8791a71
Veomni New Op next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Veomni New Op this skillByteDance-Seed/VeOmni | 2.2k | — | ~3.1k | Automated safety check: Pass | Apache-2.0 | |
| Hugging Face Local Model Evalshuggingface/skills | 11k | 2 repos | ~1.6k | Automated safety check: Pass | Apache-2.0 | |
| Liger Kernel Perflinkedin/Liger-Kernel | 6.7k | — | ~1.5k | Automated safety check: Pass | BSD-2-Clause | |
| Hugging Face LLM Trainerhuggingface/skills | 11k | 1 repos | ~7.2k | Automated safety check: Pass | Apache-2.0 | |
| MUSA GPU Training Optimizeropen-infra-skills/infra-skills | 141 | — | ~1.7k | Automated safety check: Pass | Apache-2.0 | |
| Cuda Kernel OptimizerKernelFlow-ops/cuda-optimized-skill | 214 | — | ~4.3k | Automated safety check: Pass | MIT |
huggingface/skills
Runs evaluations of Hugging Face Hub models on local hardware with inspect-ai or lighteval, and helps choose between vLLM, Transformers and accelerate backends.
linkedin/Liger-Kernel
Optimizes the performance of existing Liger Kernel Triton kernels.
huggingface/skills
Trains or fine-tunes language and vision models with TRL or Unsloth on Hugging Face Jobs cloud GPUs, then converts the results to GGUF.
open-infra-skills/infra-skills
Profiles, benchmarks and tunes AI training workloads on Moore Threads MUSA GPUs with a measurement-first process that keeps model behavior unchanged.
KernelFlow-ops/cuda-optimized-skill
Iteratively optimize a CUDA/CUTLASS/Triton kernel only when strict on-device compilation, correctness, timing, and NCU evidence gates pass.
inclusionAI/AReno
Diagnose failed, hung, slow, OOM, NaN, illegal-memory-access, NCCL, compilation, rollout, or training runs in AReno.
ByteDance-Seed/VeOmni
Create a pull request for the current branch. An agent skill from ByteDance-Seed/VeOmni.
ByteDance-Seed/VeOmni
A skill your agent uses for ANY bug, error, crash, wrong output, loss divergence, gradient explosion, test failure, CUDA error, distributed training hang, checkpoint load failure, or unexpected…
ByteDance-Seed/VeOmni
A skill your agent uses when adding support for a new model to VeOmni.
ByteDance-Seed/VeOmni
Author or refresh a VeOmni model's patchgen-generated modeling under generated/ — GPU and/or NPU config, dense or MoE, text / VLM / Omni.
ByteDance-Seed/VeOmni
A skill your agent uses for performance profiling and optimization.
ByteDance-Seed/VeOmni
Pre-PR code review gate. An agent skill from ByteDance-Seed/VeOmni.
Categories
A skill your agent uses when adding a new optimized kernel or operator to veomni/ops/. Veomni New Op is an agent skill from ByteDance-Seed/VeOmni. Use this skill when adding a new optimized kernel or operator to veomni/ops/.
Veomni New Op fits situations like: adding a new optimized kernel; operator to veomni/ops/.
Run `npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a claude-code`. Or copy the skill folder (.agents/skills/veomni-new-op in ByteDance-Seed/VeOmni) into .claude/skills/veomni-new-op in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a codex`. Or copy the skill folder (.agents/skills/veomni-new-op in ByteDance-Seed/VeOmni) into .agents/skills/veomni-new-op in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ByteDance-Seed/VeOmni --skill veomni-new-op -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/veomni-new-op, .gemini/skills/veomni-new-op, .github/skills/veomni-new-op and .opencode/skills/veomni-new-op in your project.
Going by SKILL.md and its folder, Veomni New Op needs the command-line tools its instructions call (pytest and make). Our summary lists: Python 3.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Veomni New Op is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.1k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Veomni New Op: Hugging Face Local Model Evals (huggingface/skills, 11k stars), Liger Kernel Perf (linkedin/Liger-Kernel, 6.7k stars), Hugging Face LLM Trainer (huggingface/skills, 11k stars) and MUSA GPU Training Optimizer (open-infra-skills/infra-skills, 141 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ByteDance-Seed (a GitHub organization) maintains it in ByteDance-Seed/VeOmni, which has 2,235 GitHub stars. The repository holds 10 skills in this directory. The repository was last updated on October 10, 2026.
Source: ByteDance-Seed/VeOmni on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.