Agent skill

Frappe Ops Frontend Build

by Impertio-Studio in Impertio-Studio/Frappe_Claude_Skill_Package

A skill your agent uses when configuring frontend asset bundling, migrating from build.json (v14) to esbuild (v15+), or troubleshooting SCSS/CSS compilation.

MITAuto-check passedFrontend & Design

Install Frappe Ops Frontend Build

skills CLI
$ npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-ops-frontend-build -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install Impertio-Studio/Frappe_Claude_Skill_Package frappe-ops-frontend-build --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/Impertio-Studio/Frappe_Claude_Skill_Package.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/source/ops/frappe-ops-frontend-build .claude/skills/frappe-ops-frontend-build && rm -rf skills-src

Use ~/.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/

Facts

Skill name
frappe-ops-frontend-build
GitHub stars
189
Token cost
~2.7k tokens
SKILL.md length
654 words
Files
4 (incl. references)
Skills in repo
61
Repo updated
First seen
Licence
MIT

At a glance

A skill your agent uses when configuring frontend asset bundling, migrating from build.json (v14) to esbuild (v15+), or troubleshooting SCSS/CSS compilation.

  • Works in 5 steps: bench build scans each app's public/… → Files matching *.bundle.* are treated as… → esbuild compiles, bundles, and… → …
  • Configuring frontend asset bundling
  • SKILL.md covers Quick Reference: Build Commands, Decision Tree: Build System…, Build Pipeline Overview and Bundle Entry Points [v15+], plus 5 more sections
  • Calls yarn

What it does

Frappe Ops Frontend Build is an agent skill from Impertio-Studio/Frappe_Claude_Skill_Package. Use when configuring frontend asset bundling, migrating from build.json (v14) to esbuild (v15+), or troubleshooting SCSS/CSS compilation. Prevents build failures from mixing v14 and v15 build systems and misconfigured asset pipelines. Covers esbuild configuration (v15+), build.json (v14), asset bundling, SCSS compilation, bundle.js setup, bench build flags. Keywords: esbuild, build.json, frontend build, SCSS, CSS, asset bundling, bench build, bundle.js, webpack, build error, assets not loading, CSS not updating…

Its SKILL.md is about 2.7k tokens, which your agent loads only when the skill is triggered. The skill folder holds 4 other files, including reference files (for example `references/anti-patterns.md` and `references/examples.md`). Compatibility notes: Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16.

It sits in Frontend & Design, covering CSS and styling. It works with webpack and Vue.js. The repository describes itself as: 60 deterministic Claude AI skills for Frappe Framework & ERPNext v14-v16 development and operations. The licence is MIT.

When your agent uses it

  • Configuring frontend asset bundling
  • Migrating from build.json (v1
  • Troubleshooting SCSS/CSS compilation

Example prompts

  • “/frappe-ops-frontend-build”

Requirements

  • Python 3
  • Compatibility (from SKILL.md): Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16.

Workflow steps

5 steps, taken from the first numbered list in SKILL.md.

  1. bench build scans each app's public/ directory recursively
  2. Files matching *.bundle.* are treated as entry points
  3. esbuild compiles, bundles, and optionally minifies each entry point
  4. Output goes to assets/dist/[app]/js/ or assets/dist/[app]/css/
  5. Filenames include content hashes for cache-busting: main.bundle.HASH.js

What it can do on your machine

Read from SKILL.md and the folder at commit 36cfa80. It shows what the files ask for, not the result of running them.

  • Tool permissions

    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.

  • Runs code

    Shell commands in SKILL.md call:

    • yarn

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use yarn, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

  • Compatibility

    Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16.

    From compatibility in the SKILL.md frontmatter.

Context cost

Frappe Ops Frontend Build loads about 2.7k tokens when it runs, and up to ~5k if it reads all its reference files. Until then it costs about 145 tokens; SKILL.md has 654 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~145
When it runs · the whole SKILL.md, loaded when a task matches
~2.7k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~5k

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.

Safety

Auto-check passed

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.

SKILL.md

The full file from Impertio-Studio/Frappe_Claude_Skill_Package at commit 36cfa80, republished under its MIT licence (© Impertio-Studio). 654 words, ~2,671 tokens.

Download SKILL.mdSave it as .claude/skills/frappe-ops-frontend-build/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.
name
frappe-ops-frontend-build
description
Use when configuring frontend asset bundling, migrating from build.json (v14) to esbuild (v15+), or troubleshooting SCSS/CSS compilation. Prevents build failures from mixing v14 and v15 build systems and misconfigured asset pipelines. Covers esbuild configuration (v15+), build.json (v14), asset bundling, SCSS compilation, bundle.js setup, bench build flags. Keywords: esbuild, build.json, frontend build, SCSS, CSS, asset bundling, bench build, bundle.js, webpack, build error, assets not loading, CSS not updating, JS not compiling, bench build fails..
compatibility
Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16.
license
MIT
metadata.author
OpenAEC-Foundation
metadata.version
2.0

Frontend Build System

Complete reference for Frappe's frontend asset bundling pipeline, from build configuration to production optimization.

Versions: v14 (build.json) / v15+ (esbuild)


Quick Reference: Build Commands

TaskCommand
Build all appsbench build
Build specific appbench build --app myapp
Build multiple appsbench build --apps frappe,erpnext
Production build (minified)bench build --production
Force rebuildbench build --force
Watch mode (auto-rebuild)bench watch
Hard link assetsbench build --hard-link

Decision Tree: Build System Selection

Which build system?
├── Frappe v14?
│   └── build.json — Concatenation-based bundling
├── Frappe v15+?
│   └── esbuild — ES module bundling with *.bundle.* convention
└── Migrating v14 → v15?
    └── Replace build.json with *.bundle.* files in public/

Build Pipeline Overview

v15+ (esbuild): Current System

The v15+ build system uses esbuild for fast ES module bundling. It automatically discovers bundle entry points by scanning the public/ directory for files matching *.bundle.{js|ts|css|scss|sass|less|styl}.

How it works:

  1. bench build scans each app's public/ directory recursively
  2. Files matching *.bundle.* are treated as entry points
  3. esbuild compiles, bundles, and optionally minifies each entry point
  4. Output goes to assets/dist/[app]/js/ or assets/dist/[app]/css/
  5. Filenames include content hashes for cache-busting: main.bundle.HASH.js

Supported file types:

  • .js — ES6 modules with import/export
  • .ts — TypeScript
  • .vue — Vue single-file components
  • .css — Standard CSS
  • .scss / .sass — SASS/SCSS stylesheets
  • .less — Less stylesheets
  • .styl — Stylus stylesheets
v14 (build.json): Legacy System

The v14 system uses build.json in the app root to define concatenation rules.

json
{
  "js/myapp.min.js": [
    "public/js/file1.js",
    "public/js/file2.js"
  ],
  "css/myapp.min.css": [
    "public/css/style1.css",
    "public/css/style2.css"
  ]
}

NEVER use build.json in v15+ — it is ignored by the esbuild pipeline.


Bundle Entry Points [v15+]

Creating a Bundle

Place files in your app's public/ directory with the .bundle. naming convention:

myapp/
└── public/
    ├── js/
    │   └── myapp.bundle.js       # → dist/myapp/js/myapp.bundle.HASH.js
    ├── css/
    │   └── myapp.bundle.scss     # → dist/myapp/css/myapp.bundle.HASH.css
    └── components/
        └── widget.bundle.js      # → dist/myapp/js/widget.bundle.HASH.js
Bundle File Content
javascript
// myapp/public/js/myapp.bundle.js
import { createApp } from "vue";
import MyComponent from "./components/MyComponent.vue";

// ES6 imports are resolved by esbuild
import "../css/myapp.bundle.scss";

// npm packages (installed via yarn) can be imported directly
import dayjs from "dayjs";

createApp(MyComponent).mount("#myapp-root");
Output Mapping
InputOutput
public/js/main.bundle.jsassets/dist/[app]/js/main.bundle.[hash].js
public/css/style.bundle.scssassets/dist/[app]/css/style.bundle.[hash].css
public/deep/nested/file.bundle.tsassets/dist/[app]/js/file.bundle.[hash].js

hooks.py Asset Inclusion

Desk Assets (Backend Interface)
python
# hooks.py — loads in /app (Desk)
app_include_js = "myapp.bundle.js"
app_include_css = "myapp.bundle.css"

# Multiple files
app_include_js = ["myapp.bundle.js", "extra.bundle.js"]
app_include_css = ["myapp.bundle.css", "extra.bundle.css"]
Portal Assets (Public Website)
python
# hooks.py — loads on web pages (portal)
web_include_js = "myapp-web.bundle.js"
web_include_css = "myapp-web.bundle.css"
Page-Specific Assets
python
# hooks.py — loads on specific Desk pages
page_js = {"page_name": "public/js/custom_page.js"}
Web Form Assets (Standard Web Forms Only)
python
# hooks.py — loads on specific Web Forms
webform_include_js = {"ToDo": "public/js/custom_todo.js"}
webform_include_css = {"ToDo": "public/css/custom_todo.css"}
Critical Rules
  • ALWAYS use the bundle filename (not the full path) in hooks.py for v15+
  • NEVER include the hash in hooks.py — Frappe resolves the hashed filename automatically
  • ALWAYS rebuild after changing hooks.py: bench build --app myapp
  • Multiple apps can define the same hooks — assets accumulate across all installed apps

Including Assets in Templates

Jinja Helpers
html
<!-- Include script with correct hash -->
{{ include_script("myapp.bundle.js") }}

<!-- Include stylesheet with correct hash -->
{{ include_style("myapp.bundle.css") }}

<!-- Get path string only (no HTML tag) -->
<script src="{{ bundled_asset('myapp.bundle.js') }}"></script>
Lazy Loading in Desk
javascript
// Load asset on demand (returns Promise)
frappe.require("myapp.bundle.js", () => {
    // Asset loaded, initialize component
    myapp.init();
});

// Multiple assets
frappe.require(["widget.bundle.js", "widget.bundle.css"], () => {
    // Both loaded
});

SCSS/CSS Compilation

SCSS Bundle Example
scss
// myapp/public/css/myapp.bundle.scss

// Import Frappe variables (available in all apps)
@import "frappe/public/scss/variables";

// Import partials (NOT bundles — no .bundle. in name)
@import "./components/header";
@import "./components/sidebar";

.myapp-container {
  padding: var(--padding-lg);
  background: var(--bg-color);
}
Partial Files

Partials (files starting with _ or without .bundle. in the name) are NOT compiled as entry points. They are only included via @import:

public/css/
├── myapp.bundle.scss        # Entry point — compiled
├── _variables.scss          # Partial — imported only
└── components/
    ├── _header.scss         # Partial — imported only
    └── _sidebar.scss        # Partial — imported only

Development Workflow

Watch Mode [v15+]
bash
# Auto-rebuild on file changes
bench watch
  • Watches all apps' public/ directories for changes
  • Rebuilds only affected bundles (incremental)
  • Desk auto-reloads when assets change (if live_reload is enabled)
Enabling Live Reload
bash
# Via config
bench set-config -g live_reload true

# Via environment variable
export LIVE_RELOAD=1
Development vs Production Build
FeatureDevelopment (bench build)Production (bench build --production)
MinificationNoYes
Source mapsYesNo
Bundle sizeLargerOptimized
Build speedFastSlower

Show full SKILL.md (249 more words)Show less

Frappe UI (Vue.js) Custom Pages [v15+]

Setting Up a Vue Page
javascript
// myapp/public/js/mypage.bundle.js
import { createApp } from "vue";
import { FrappeUI } from "frappe-ui";
import App from "./App.vue";

const app = createApp(App);
app.use(FrappeUI);
app.mount("#myapp-page");
Registering the Page
python
# Create a Page DocType or use www/ for web pages
# The bundle loads via hooks.py or include_script()
npm Dependencies
bash
# Install from app directory
cd apps/myapp
yarn add vue frappe-ui dayjs

Dependencies are resolved by esbuild from node_modules/ during build.


Common Build Errors and Fixes

Error: "Could not resolve module"
ERROR: Could not resolve "some-package"

Fix: Install the missing npm package:

bash
cd apps/myapp && yarn add some-package
Error: "No bundle entry points found"

Fix: Ensure files use the *.bundle.* naming convention and are in the public/ directory.

Error: Stale Assets After Deployment

Fix: Force rebuild with cache clear:

bash
bench build --force
bench clear-cache
Error: CSS Not Updating

Fix: Check that SCSS files import correctly and the entry point has .bundle. in the name:

bash
bench build --app myapp --force
Error: "build.json" Ignored in v15

Fix: Migrate to *.bundle.* entry points. build.json is a v14-only feature.


Asset Optimization for Production

Pre-Deployment Checklist
  1. Build with production flag: bench build --production
  2. Verify bundle sizes: Check assets/dist/ for unexpectedly large files
  3. Use lazy loading: Split rarely-used features into separate bundles loaded via frappe.require()
  4. Minimize hook includes: Only include essential assets in app_include_js/css
  5. Use CSS variables: Leverage Frappe's built-in CSS custom properties instead of duplicating styles
Bundle Splitting Strategy
public/
├── js/
│   ├── myapp.bundle.js          # Core — loaded on every page via hooks
│   ├── report-widget.bundle.js  # Lazy — loaded only on report pages
│   └── chart-tools.bundle.js    # Lazy — loaded only when charts needed
└── css/
    ├── myapp.bundle.scss        # Core — loaded on every page via hooks
    └── print.bundle.scss        # Lazy — loaded only for print views

Version Differences

Featurev14v15+
Build systembuild.jsonesbuild
Entry point conventionDefined in JSON*.bundle.* auto-discovery
TypeScript supportNoYes
Vue SFC supportNoYes
SCSS compilationVia build pipelineVia esbuild
Watch modebench watchbench watch (faster)
Live reloadManualAutomatic (configurable)
Source mapsLimitedFull support
Tree shakingNoYes
npm importsRequires manual bundlingDirect ES6 imports

Reference Files

FileContents
examples.mdComplete build configuration examples
anti-patterns.mdCommon build mistakes and fixes

© Impertio-Studio, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 3 other files (references) in skills/source/ops/frappe-ops-frontend-build of Impertio-Studio/Frappe_Claude_Skill_Package.

  • SKILL.md
  • references/.gitkeep
  • references/anti-patterns.md
  • references/examples.md

Open the folder on GitHubat commit 36cfa80

Compare with similar skills

Frappe Ops Frontend Build 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.

Frappe Ops Frontend Build compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Frappe Ops Frontend Build this skillImpertio-Studio/Frappe_Claude_Skill_Package189—~2.7kAutomated safety check: PassMIT
Orchardcore Asset ManagerOrchardCMS/OrchardCore8.2k—~1.5kAutomated safety check: PassBSD-3-Clause
Dokan Frontend Devgetdokan/dokan288—~1.9kAutomated safety check: PassNone
Tailwindcss Developmentanonaddy/anonaddy4.9k10 repos~865Automated safety check: PassMIT
Kill AI Slopyetone/kill-ai-slop1.3k—~1.4kAutomated safety check: PassApache-2.0
Design StyleCastor6/tactus3761 repos~2.1kAutomated safety check: PassApache-2.0

Similar skills

  • Orchardcore Asset Manager

    OrchardCMS/OrchardCore

    Builds, watches, and manages frontend assets in OrchardCore.

    8.2k GitHub stars~1.5k tokensUpdated yesterday
    Frontend & DesignAuto-check passed
  • Dokan Frontend Dev

    getdokan/dokan

    Add or modify Dokan frontend code (React, TypeScript, Vue, Tailwind).

    288 GitHub stars~1.9k tokensUpdated yesterday
    Frontend & DesignAuto-check passed
  • Tailwindcss Development

    anonaddy/anonaddy

    Always invoke when the user's message includes 'tailwind' in any form.

    4.9k GitHub starsUsed in 10 repos~865 tokens
    Frontend & DesignAuto-check passed
  • Kill AI Slop

    yetone/kill-ai-slop

    Find and remove AI slop — the generic, machine-default visual and copy tics of vibe-coded products — from a web project.

    1.3k GitHub stars~1.4k tokensUpdated 26 days ago
    Frontend & DesignAuto-check passed
  • Design Style

    Castor6/tactus

    A skill your agent uses whenever the user asks to build, create, design, develop, improve, or style any frontend interface or visual element.

    376 GitHub starsUsed in 1 repo~2.1k tokens
    Frontend & DesignAuto-check passed
  • Cross-platform UI styling for MarkerOn Tauri app (macOS WKWebView vs Windows WebView2).

    1.2k GitHub stars~2k tokensUpdated 3 days ago
    Frontend & DesignAuto-check passed

More from Impertio-Studio/Frappe_Claude_Skill_Package

All 61 skills in this repo
  • Frappe Ops Website Deploy

    Impertio-Studio/Frappe_Claude_Skill_Package

    Deploy HTML/CSS websites to ERPNext/Frappe (v15/v16) as Web Pages via the REST API.

    189 GitHub stars~2.5k tokensUpdated 23 days ago
    Auto-check passed
  • Frappe Agent Architect

    Impertio-Studio/Frappe_Claude_Skill_Package

    A skill your agent uses when designing multi-app Frappe architectures, deciding whether to split functionality into separate apps, or implementing cross-app communication patterns.

    189 GitHub stars~2.8k tokensUpdated 23 days ago
    Auto-check passed
  • Frappe Agent Debugger

    Impertio-Studio/Frappe_Claude_Skill_Package

    A skill your agent uses when debugging Frappe errors, using bench console for live inspection, analyzing tracebacks, or reading Frappe log files.

    189 GitHub stars~2.9k tokensUpdated 23 days ago
    Auto-check passed
  • Frappe Agent Interpreter

    Impertio-Studio/Frappe_Claude_Skill_Package

    A skill your agent uses when receiving vague or unclear ERPNext/Frappe development requests that need interpretation.

    189 GitHub stars~3.2k tokensUpdated 23 days ago
    Auto-check passed
  • Frappe Agent Migrator

    Impertio-Studio/Frappe_Claude_Skill_Package

    A skill your agent uses when migrating a Frappe app between major versions, detecting breaking API changes, or resolving post-migration errors.

    189 GitHub stars~2.8k tokensUpdated 23 days ago
    Auto-check: notes
  • Frappe Agent Validator

    Impertio-Studio/Frappe_Claude_Skill_Package

    A skill your agent uses when reviewing or validating Frappe/ERPNext code against best practices and common pitfalls.

    189 GitHub stars~2.8k tokensUpdated 23 days ago
    Auto-check passed

Works with

Questions about Frappe Ops Frontend Build

What does Frappe Ops Frontend Build do?

A skill your agent uses when configuring frontend asset bundling, migrating from build.json (v14) to esbuild (v15+), or troubleshooting SCSS/CSS compilation. Frappe Ops Frontend Build is an agent skill from Impertio-Studio/Frappe_Claude_Skill_Package.json (v14) to esbuild (v15+), or troubleshooting SCSS/CSS compilation.

When should I use Frappe Ops Frontend Build?

Frappe Ops Frontend Build fits situations like: configuring frontend asset bundling; migrating from build.json (v1; troubleshooting SCSS/CSS compilation.

How do I install Frappe Ops Frontend Build in Claude Code?

Run `npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-ops-frontend-build -a claude-code`. Or copy the skill folder (skills/source/ops/frappe-ops-frontend-build in Impertio-Studio/Frappe_Claude_Skill_Package) into .claude/skills/frappe-ops-frontend-build in your project. Claude Code loads it when a task matches its description.

How do I install Frappe Ops Frontend Build in Codex?

Run `npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-ops-frontend-build -a codex`. Or copy the skill folder (skills/source/ops/frappe-ops-frontend-build in Impertio-Studio/Frappe_Claude_Skill_Package) into .agents/skills/frappe-ops-frontend-build in your project. Codex loads it when a task matches its description.

Can I use Frappe Ops Frontend Build in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-ops-frontend-build -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/frappe-ops-frontend-build, .gemini/skills/frappe-ops-frontend-build, .github/skills/frappe-ops-frontend-build and .opencode/skills/frappe-ops-frontend-build in your project.

What does Frappe Ops Frontend Build need to run?

Going by SKILL.md and its folder, Frappe Ops Frontend Build needs the command-line tools its instructions call (yarn). Our summary lists: Python 3. Compatibility (from SKILL.md): Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16..

Does Frappe Ops Frontend Build access the network?

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.

Is Frappe Ops Frontend Build safe to install?

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.

What licence does Frappe Ops Frontend Build use?

Frappe Ops Frontend Build is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Frappe Ops Frontend Build use?

About 2.7k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 2.3k tokens, read only when the agent opens those files.

What are the alternatives to Frappe Ops Frontend Build?

Skills that share tags, products or a category with Frappe Ops Frontend Build: Orchardcore Asset Manager (OrchardCMS/OrchardCore, 8.2k stars), Dokan Frontend Dev (getdokan/dokan, 288 stars), Tailwindcss Development (anonaddy/anonaddy, 4.9k stars) and Kill AI Slop (yetone/kill-ai-slop, 1.3k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Frappe Ops Frontend Build?

Impertio-Studio (a GitHub organization) maintains it in Impertio-Studio/Frappe_Claude_Skill_Package, which has 189 GitHub stars. The repository holds 61 skills in this directory. The repository was last updated on September 17, 2026.

Source: Impertio-Studio/Frappe_Claude_Skill_Package on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.