App Store Release Flow
rorkai/app-store-connect-cli-skills
Orchestrates App Store releases with the asc CLI: staging a version, uploading or building, publishing and submitting for review, with dry-run and confirmation gates.
A skill your agent uses when an iOS app already on TestFlight needs to ship to the App Store — preparing the screenshots and the description/metadata, then using the existing fastlane setup to…
$ npx skills add jianshuo/claude-skills --skill wjs-publishing-appstore -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install jianshuo/claude-skills wjs-publishing-appstore --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/jianshuo/claude-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/wjs-publishing-appstore .claude/skills/wjs-publishing-appstore && 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 "wjs-publishing-appstore" agent skill from https://github.com/jianshuo/claude-skills/tree/main/wjs-publishing-appstore into .claude/skills/wjs-publishing-appstore/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wjs-publishing-appstore", 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/jianshuo/claude-skills/tree/main/wjs-publishing-appstoreType 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 jianshuo/claude-skills --skill wjs-publishing-appstore -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install jianshuo/claude-skills wjs-publishing-appstore --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jianshuo/claude-skills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/wjs-publishing-appstore .agents/skills/wjs-publishing-appstore && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "wjs-publishing-appstore" agent skill from https://github.com/jianshuo/claude-skills/tree/main/wjs-publishing-appstore into .agents/skills/wjs-publishing-appstore/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wjs-publishing-appstore", 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 jianshuo/claude-skills --skill wjs-publishing-appstore -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install jianshuo/claude-skills wjs-publishing-appstore --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jianshuo/claude-skills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/wjs-publishing-appstore .cursor/skills/wjs-publishing-appstore && 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 "wjs-publishing-appstore" agent skill from https://github.com/jianshuo/claude-skills/tree/main/wjs-publishing-appstore into .cursor/skills/wjs-publishing-appstore/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wjs-publishing-appstore", 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/jianshuo/claude-skills.git --path wjs-publishing-appstore--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 jianshuo/claude-skills --skill wjs-publishing-appstore -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install jianshuo/claude-skills wjs-publishing-appstore --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jianshuo/claude-skills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/wjs-publishing-appstore .gemini/skills/wjs-publishing-appstore && 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 "wjs-publishing-appstore" agent skill from https://github.com/jianshuo/claude-skills/tree/main/wjs-publishing-appstore into .gemini/skills/wjs-publishing-appstore/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wjs-publishing-appstore", 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 jianshuo/claude-skills wjs-publishing-appstoreInstalls 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 jianshuo/claude-skills --skill wjs-publishing-appstore -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/jianshuo/claude-skills.git skills-src && mkdir -p .github/skills && cp -r skills-src/wjs-publishing-appstore .github/skills/wjs-publishing-appstore && 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 "wjs-publishing-appstore" agent skill from https://github.com/jianshuo/claude-skills/tree/main/wjs-publishing-appstore into .github/skills/wjs-publishing-appstore/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wjs-publishing-appstore", 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 jianshuo/claude-skills --skill wjs-publishing-appstore -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install jianshuo/claude-skills wjs-publishing-appstore --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/jianshuo/claude-skills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/wjs-publishing-appstore .opencode/skills/wjs-publishing-appstore && 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 "wjs-publishing-appstore" agent skill from https://github.com/jianshuo/claude-skills/tree/main/wjs-publishing-appstore into .opencode/skills/wjs-publishing-appstore/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "wjs-publishing-appstore", 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.
wjs-publishing-appstoreA skill your agent uses when an iOS app already on TestFlight needs to ship to the App Store — preparing the screenshots and the description/metadata, then using the existing fastlane setup to…
Wjs Publishing Appstore is an agent skill from jianshuo/claude-skills. Use when an iOS app already on TestFlight needs to ship to the App Store — preparing the screenshots and the description/metadata, then using the existing fastlane setup to submit for review. Triggers — 「提交 App Store」「上架」「app store 审核」「准备截图和文案」「submit for review」「/wjs-publishing-appstore」.
Its SKILL.md is about 2.6k tokens, which your agent loads only when the skill is triggered. The skill folder holds 4 other files, including scripts (for example `scripts/scaffold-metadata.sh` and `scripts/shoot.sh`).
It sits in Mobile, covering App store release. It works with App Store Connect and iOS. The repository describes itself as: 13 Claude Code skills for video production (transcribe / translate / dub / multicam / subtitles / reframe) + WeChat publishing. Compatible with Claude Code, OpenAI Codex CLI… The licence is MIT.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit b2690f5. 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.
Ships 3 files in scripts/ (Shell and Ruby), which the agent can run.
Shell commands in SKILL.md call:
bundlegitxcrunFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use git, which can reach the network depending on how they are called.
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.
Wjs Publishing Appstore loads about 2.6k tokens when it runs. Until then it costs about 79 tokens; SKILL.md has 1,252 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); the scripts in this folder are not scanned.
The full file from jianshuo/claude-skills at commit b2690f5, republished under its MIT licence (© jianshuo). 1,252 words, ~2,625 tokens.
.claude/skills/wjs-publishing-appstore/SKILL.md (or your agent's skills folder). This skill also uses 3 other files; get the full folder from GitHub.Take an iOS app that's already building to TestFlight and ship it to the App Store: prepare the screenshots + description/metadata, then use the existing fastlane to submit for review.
This is the App Store counterpart to wjs-publishing-testflight, which is a
prerequisite — that skill owns build / signing (match) / CI / the beta
lane. This skill assumes that's done and only adds the listing + a deliberate
release lane. Reference implementations: VoiceDrop, Cathier.
git push → main → beta lane → TestFlight (unchanged, automatic)
fastlane release → release lane → metadata + screenshots → submit for reviewSubmitting to review is high-stakes, so it is never triggered by a push — it
is the explicit fastlane release command you run on purpose.
wjs-publishing-testflight already set up: match appstore certs, the
ASC_API_* secrets, a working beta lane, and at least one build already
uploaded to TestFlight (this also creates the App Store Connect app record).wjs-publishing-testflight — do not re-list secrets
here (this skill auto-publishes to a public repo).bundle exec fastlane produce -u jianshuo@hotmail.com -a <BUNDLE_ID> --app_name "<Name>".scripts/scaffold-metadata.sh # from this skill; run at the repo rootCreates fastlane/metadata/{zh-Hans,en-US}/*.txt + review_information/ +
top-level category/copyright, seeded with editable VoiceDrop copy. Re-running
never overwrites existing files.
Edit every .txt. Watch the limits: name 30 · subtitle 30 · keywords 100
(comma-separated, no spaces) · promotional_text 170 · description 4000. Fill in
review_information/ (phone, and a demo account only if login is required) and
the privacy URL.
The App Store name is globally unique. A short common name ("VoiceDrop")
is almost certainly already taken by another account — the submit then dies at
upload_to_app_store with "The app name you entered is already being used."
This is the display name only; the home-screen name (CFBundleDisplayName)
is separate and can stay whatever you like. Pick a distinct string (e.g. add a
word or a Chinese suffix — "VoiceDrop 口述"); longer = safer. It's per-locale and
changeable in a later version, so it's not permanent.
scripts/shoot.sh # default: iPhone 16 Pro Max (6.9"), zh-Hans
LOCALE=en-US scripts/shoot.sh # second localeEdit drive_screens() in shoot.sh to hit each marketing screen (3–6, named
01_*, 02_*…). It boots a sim, builds, installs, captures into
fastlane/screenshots/<locale>/. FRAME=1 adds frameit framing.
Required size: only the 6.9" display (1320×2868) is mandatory and it
covers iPhone-only apps. Add a 13" iPad pass only if
TARGETED_DEVICE_FAMILY includes iPad (VoiceDrop is iPhone-only → one size).
Mic-permission gotcha: if the app requests microphone/record permission, iOS
shows a dialog xcrun simctl privacy grant microphone does not suppress (a
real iOS 26 sim limitation). Open Simulator.app, tap 允许/Allow once — the
grant persists for the install, so re-running shoot.sh then captures a clean
frame. (simctl has no tap; don't try to click it from the script — synthetic
clicks via osascript need macOS Accessibility permission the runner lacks.)
Other iOS 26 sim screenshot gotchas:
DebugRoot), and seed its data via the app's own
token (a sim regenerates its synchronizable-Keychain identity on every
reinstall — no iCloud account — so injected data under an old identity won't
show; on a real device the identity persists).TabView labels near the Dynamic Island
even for a bare two-tab TabView — a sim-only Liquid Glass artifact, not in
your app. Don't chase it; verify on device.release lanePaste scripts/release_lane.rb into the existing fastlane/Fastfile inside
platform :ios do … end. It uploads metadata + screenshots (the TestFlight lane
sets skip_metadata/skip_screenshots: true; this lane sets them false),
then submit_for_review: true with the encryption/IDFA compliance answers,
guarded by guard_not_in_review.
# dry-run the listing without submitting (writes an HTML preview, no upload):
bundle exec fastlane deliver --skip_binary_upload true --submit_for_review false --force false
# real submit (uses the build already on TestFlight for this version):
bundle exec fastlane release skip_build:true # reuse the TestFlight build
bundle exec fastlane release # or build a fresh one firstRun locally, or via the CI workflow_dispatch if your build.yml routes a
appstore choice to fastlane release (see wjs-publishing-testflight Step 3).
Robust two-step ship (what actually worked): git push → the beta lane
builds and uploads to TestFlight and waits for Apple to finish processing →
then dispatch appstore → fastlane release skip_build:true reuses that
already-processed build. Building a fresh binary inside the release lane risks
submitting before the build is processed. CI checks out main, so metadata +
screenshots must be committed to main before you dispatch.
Un-ignore the screenshots. The TestFlight-only setup often has
fastlane/screenshots/ in .gitignore (that flow uses skip_screenshots). This
lane uploads them, so they must be committed — remove that ignore line (keep
ignoring only frameit extras) or CI uploads nothing.
These live in the ASC web console, not in fastlane metadata, and fastlane
will refuse the submit until they're set. Do all of them once before the first
fastlane release — they're sticky (later versions don't need them redone).
A submit that hits these fails at the very last step: the metadata + screenshots
have already uploaded, so just fix the console items and re-dispatch — nothing is
re-uploaded. The real error block lists all the missing attributes at once
(violenceCartoonOrFantasy, ageAssurance, contentRightsDeclaration, "App is
not eligible for submission until pricing has been set" …).
ageAssurance, parentalControls,
messagingAndChat, healthOrWellnessTopics, …) that fastlane's rating config
does not fully cover — so do it in the web console, not via fastlane.export_compliance_uses_encryption: false); no console action.guard_not_in_review (and Apple) will block a re-submit while the version is
Waiting for Review. To swap in a newer build, fix copy, or add a screenshot:
in ASC open the version → "Remove this version from review" (back to editable)
→ then re-dispatch fastlane release skip_build:true. The new build is selected,
metadata + screenshots re-upload, and it resubmits.
Screenshots must match the binary (guideline 2.3.3). Don't put a screenshot of a feature the in-review build lacks — either ship that feature in the build you're submitting, or hold the screenshot for the version that has it.
fastlane/metadata/** has no ...FILL_ME... / empty required fieldsfastlane/screenshots/<locale>/ has ≥1 6.9" PNG per locale, named NN_*fastlane deliver preview (Step 5 dry-run) renders the listing cleanlyfastlane release → "Submitted X for App Store review"; a release/X tag exists| Symptom | Fix |
|---|---|
Could not find app … on App Store Connect | App record missing → fastlane produce (Step / Prereqs). |
| "The app name you entered is already being used" | The name is globally taken → pick a unique display name (Step 2). |
| Submit fails "missing screenshots" / CI uploaded none | No 6.9" screenshot, wrong size, or fastlane/screenshots/ still gitignored (un-ignore it). |
Missing violence… / ageAssurance / contentRightsDeclaration / "pricing has been set" | First-submission console items unset → fill age rating, pricing=Free, content rights, App Privacy in the ASC web console once. |
Another version is in review / guard_not_in_review tripped | To update an in-review version, "Remove this version from review" in ASC, then re-dispatch. |
| Keyword field rejected | Keywords must be comma-separated, no spaces, ≤100 chars total. |
| Wrong build submitted | Use release skip_build:true to reuse the exact TestFlight build for this MARKETING_VERSION. |
scripts/scaffold-metadata.sh — create the deliver metadata tree (seeded with VoiceDrop copy)scripts/shoot.sh — scripted simctl screenshot capturescripts/release_lane.rb — the release fastlane lane to paste into your Fastfile© jianshuo, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 3 other files (scripts) in wjs-publishing-appstore of jianshuo/claude-skills.
Open the folder on GitHubat commit b2690f5
Wjs Publishing Appstore 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 |
|---|---|---|---|---|---|---|
| Wjs Publishing Appstore this skilljianshuo/claude-skills | 131 | — | ~2.6k | Automated safety check: Pass | MIT | |
| App Store Release Flowrorkai/app-store-connect-cli-skills | 1.1k | 2 repos | ~2k | Automated safety check: Pass | MIT | |
| App Store Submission Healthrorkai/app-store-connect-cli-skills | 1.1k | 2 repos | ~2.2k | Automated safety check: Pass | MIT | |
| App Store Preflight Skillstruongduy2611/app-store-preflight-skills | 1.4k | — | ~1.4k | Automated safety check: Pass | MIT | |
| App Store Connect App Creatorrorkai/app-store-connect-cli-skills | 1.1k | 3 repos | ~1.5k | Automated safety check: Pass | MIT | |
| OdevioOdevio/Odevio-CLI | 423 | — | ~7.6k | Automated safety check: Pass | MIT |
rorkai/app-store-connect-cli-skills
Orchestrates App Store releases with the asc CLI: staging a version, uploading or building, publishing and submitting for review, with dry-run and confirmation gates.
rorkai/app-store-connect-cli-skills
Diagnoses why an App Store version cannot be submitted or is stuck in review, using the asc CLI for validation, repair routing, status checks and retry decisions.
truongduy2611/app-store-preflight-skills
Scan an iOS/macOS Xcode project for common App Store rejection patterns before submission.
rorkai/app-store-connect-cli-skills
Creates a new App Store Connect app record by driving the New App form through browser automation, for cases where no public API covers app creation.
Odevio/Odevio-CLI
Take a Flutter project to an iPhone or the App Store with Odevio - build, sign and publish iOS apps from Windows, Linux or macOS with no Mac and no Xcode.
ZestfulPulse/ios-app-store-submit
Build, sign, and submit a Flutter/iOS app to the App Store Connect — covers Xcode archive/export, code signing (including headless-Mac keychain workarounds), the asc CLI for App Store Connect…
jianshuo/claude-skills
A skill your agent uses when the user has a long-form video (interview / lecture / podcast / conversation) and a transcript SRT, and wants to extract 3–6 stand-alone topical short clips from it.
jianshuo/claude-skills
Upload one or many videos to YouTube. An agent skill from jianshuo/claude-skills.
jianshuo/claude-skills
A skill your agent uses when migrating a WordPress site to a Hugo static site on GitHub Pages from a WXR export (.xml) plus the wp-content/uploads folder — preserving /archives/<id/ URLs, localizing…
jianshuo/claude-skills
A skill your agent uses when the user has a video + an SRT and wants the subtitles either burned into the pixels (libass, always-visible) or soft-muxed as a togglable track.
jianshuo/claude-skills
A skill your agent uses when the user complains about spam on his X/Twitter posts — 同城面付 / 寻固炮 / 线下上门 / 免费破处 这类引流号在他推文下刷的 emoji 垃圾回复 — and wants them removed.
jianshuo/claude-skills
A skill your agent uses when the user wants a book turned into YouTube chapter videos — 每章用 VoiceDrop 读书的有声书 mp3 做音轨,配 GPT Image 2 画面和中心思想大字,输出 1920×1080 横屏视频发 YouTube。Triggers — "把这本书做成视频"…
Works with
Categories
A skill your agent uses when an iOS app already on TestFlight needs to ship to the App Store — preparing the screenshots and the description/metadata, then using the existing fastlane setup to…. Wjs Publishing Appstore is an agent skill from jianshuo/claude-skills. Use when an iOS app already on TestFlight needs to ship to the App Store — preparing the screenshots and the description/metadata, then using the existing fastlane setup to submit for review.
Wjs Publishing Appstore fits situations like: an iOS app already on TestFlight needs to ship to the App Store — preparing the screenshots and the description/metadata; then using the existing fastlane setup to submit for review; — 「提交 App Store」「上架」「app store 审核」「准备截图和文案」「submit for review」「/wjs-publishing-appstore」.
Run `npx skills add jianshuo/claude-skills --skill wjs-publishing-appstore -a claude-code`. Or copy the skill folder (wjs-publishing-appstore in jianshuo/claude-skills) into .claude/skills/wjs-publishing-appstore in your project. Claude Code loads it when a task matches its description.
Run `npx skills add jianshuo/claude-skills --skill wjs-publishing-appstore -a codex`. Or copy the skill folder (wjs-publishing-appstore in jianshuo/claude-skills) into .agents/skills/wjs-publishing-appstore 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 jianshuo/claude-skills --skill wjs-publishing-appstore -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/wjs-publishing-appstore, .gemini/skills/wjs-publishing-appstore, .github/skills/wjs-publishing-appstore and .opencode/skills/wjs-publishing-appstore in your project.
Going by SKILL.md and its folder, Wjs Publishing Appstore needs a shell and Ruby for the scripts in its folder and the command-line tools its instructions call (bundle, git and xcrun). Our summary lists: A Bash shell.
SKILL.md contains no URLs. Its commands use git, which can reach the network depending on how they are called. 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. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
Wjs Publishing Appstore is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.6k 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.
Skills that share tags, products or a category with Wjs Publishing Appstore: App Store Release Flow (rorkai/app-store-connect-cli-skills, 1.1k stars), App Store Submission Health (rorkai/app-store-connect-cli-skills, 1.1k stars), App Store Preflight Skills (truongduy2611/app-store-preflight-skills, 1.4k stars) and App Store Connect App Creator (rorkai/app-store-connect-cli-skills, 1.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
jianshuo (a GitHub user) maintains it in jianshuo/claude-skills, which has 131 GitHub stars. The repository holds 38 skills in this directory. The repository was last updated on August 20, 2026.
Source: jianshuo/claude-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.