Mac Fleet Maintenance
steipete/agent-scripts
Inventories and maintains a fleet of Macs from a desired-state file: package updates, repo and Xcode sync, and disk, backup and security health reports.
Deploy a generated project (one process or several) to agent-sandboxes with scale-to-zero: idle sandboxes pause and auto-resume (process restarted) on the next HTTP request.
$ npx skills add agent-sandbox/agent-sandbox --skill ai-deploy -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install agent-sandbox/agent-sandbox ai-deploy --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/agent-sandbox/agent-sandbox.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/ai-deploy .claude/skills/ai-deploy && 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 "ai-deploy" agent skill from https://github.com/agent-sandbox/agent-sandbox/tree/main/skills/ai-deploy into .claude/skills/ai-deploy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-deploy", 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/agent-sandbox/agent-sandbox/tree/main/skills/ai-deployType 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 agent-sandbox/agent-sandbox --skill ai-deploy -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install agent-sandbox/agent-sandbox ai-deploy --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/agent-sandbox/agent-sandbox.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/ai-deploy .agents/skills/ai-deploy && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "ai-deploy" agent skill from https://github.com/agent-sandbox/agent-sandbox/tree/main/skills/ai-deploy into .agents/skills/ai-deploy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-deploy", 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 agent-sandbox/agent-sandbox --skill ai-deploy -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install agent-sandbox/agent-sandbox ai-deploy --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/agent-sandbox/agent-sandbox.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/ai-deploy .cursor/skills/ai-deploy && 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 "ai-deploy" agent skill from https://github.com/agent-sandbox/agent-sandbox/tree/main/skills/ai-deploy into .cursor/skills/ai-deploy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-deploy", 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/agent-sandbox/agent-sandbox.git --path skills/ai-deploy--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 agent-sandbox/agent-sandbox --skill ai-deploy -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install agent-sandbox/agent-sandbox ai-deploy --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/agent-sandbox/agent-sandbox.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/ai-deploy .gemini/skills/ai-deploy && 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 "ai-deploy" agent skill from https://github.com/agent-sandbox/agent-sandbox/tree/main/skills/ai-deploy into .gemini/skills/ai-deploy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-deploy", 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 agent-sandbox/agent-sandbox ai-deployInstalls 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 agent-sandbox/agent-sandbox --skill ai-deploy -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/agent-sandbox/agent-sandbox.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/ai-deploy .github/skills/ai-deploy && 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 "ai-deploy" agent skill from https://github.com/agent-sandbox/agent-sandbox/tree/main/skills/ai-deploy into .github/skills/ai-deploy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-deploy", 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 agent-sandbox/agent-sandbox --skill ai-deploy -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install agent-sandbox/agent-sandbox ai-deploy --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/agent-sandbox/agent-sandbox.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/ai-deploy .opencode/skills/ai-deploy && 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 "ai-deploy" agent skill from https://github.com/agent-sandbox/agent-sandbox/tree/main/skills/ai-deploy into .opencode/skills/ai-deploy/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ai-deploy", 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.
ai-deployDeploy a generated project (one process or several) to agent-sandboxes with scale-to-zero: idle sandboxes pause and auto-resume (process restarted) on the next HTTP request.
AI Deploy is an agent skill from agent-sandbox/agent-sandbox. Deploy a generated project (one process or several) to agent-sandboxes with scale-to-zero: idle sandboxes pause and auto-resume (process restarted) on the next HTTP request. Use when asked to deploy, host, or preview generated code through the sandbox platform.
Its SKILL.md is about 3k 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 DevOps & Cloud. The repository describes itself as: Agent-Sandbox is an easy-to-use, enterprise-grade sandbox platform for AI Agents — letting them securely run untrusted LLM-generated code, Browser use, Computer use, and deploy… The licence is Apache-2.0.
10 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 6f7b273. 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:
pipnpmFrom the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
e2b.devFrom URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
E2B_API_KEYFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
AI Deploy loads about 3k tokens when it runs. Until then it costs about 68 tokens; SKILL.md has 822 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 noted patterns worth knowing about, such as sudo or a known installer.
`.env`: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 agent-sandbox/agent-sandbox at commit 6f7b273, republished under its Apache-2.0 licence (© agent-sandbox). 822 words, ~2,955 tokens.
.claude/skills/ai-deploy/SKILL.md (or your agent's skills folder).Ship a project you just generated into agent-sandboxes via the e2b SDK, get a public URL, and let the platform pause/resume it on demand. No wrapper script — write SDK calls inline, adapted to the project at hand. Most steps below are optional; skip what this project doesn't need.
A project may be one process or several (API, worker, UI, ...). Each
deploys to its own sandbox, on whichever template matches its runtime
(sandbox-base for stdlib Python, sandbox-base-node for Node, ...),
with its own sandbox_id. If one service calls another, use the
platform's internal cluster address, not the public gateway.
pip install e2b==2.21.1 e2b-code-interpreter==2.4.1 python-dotenv.env:
E2B_API_KEY=<key>
E2B_DOMAIN=<domain>
E2B_API_URL=http://agent-sandbox.<domain>/e2b/v10.0.0.0./workspace) explicitly in
every file write and command./sandboxes/router/{id}/{port}/), so any
browser-facing assets need relative paths: vite build --base ./, CRA
"homepage": ".", plain ./app.js-style references.https:// regardless of E2B_API_URL's
own scheme — see public_base_url() below.Every deploy — first time or redeploy — walks the same ten steps. Several are optional; skip the ones this project doesn't need.
1. generate project → 2. build → 3. push to git
→ 4. create/reuse sandbox → 5. get the code onto it
→ 6. install deps → 7. start → 8. snapshot
→ 9. save deploy state → 10. push to gitThis is meant to be re-run on every code change: it reuses the
service's existing sandbox (same sandbox_id, same public URL) instead
of creating a new one, unless the recorded sandbox is gone.
Reuse depends on a state file (<project>/.ai-deploy-state.json —
anchor it to the project, not the caller's cwd) holding each service's
sandbox_id and last start command. Commit it with the project
(don't gitignore it) — it's what lets a redeploy from any session or
machine continue the same live sandboxes instead of forking new ones.
Write the source files into the project's own directory.
Only if the project has a build step, e.g. npm run build / vite build
→ dist/. Upload the output directory, not the source tree. Skip
entirely for a plain stdlib script or server.
If the project has a remote, commit and push the generated files now — this is what the git-based upload in step 5 clones/pulls from. Skip it if uploading via the files API instead.
import json
import os
from pathlib import Path
from urllib.parse import urlsplit, urlunsplit
from dotenv import load_dotenv
from e2b import CommandExitException, SandboxNotFoundException
from e2b_code_interpreter import Sandbox
load_dotenv()
idle_timeout = 600 # seconds
WORKDIR = "/workspace" # sandbox inner persistent mount; always address it explicitly
# Absolute path — a relative one breaks "reuse the existing sandbox"
# silently if this script ever runs from a different cwd.
PROJECT_DIR = Path("/path/to/the/project").resolve() # the project you just wrote
STATE_FILE = PROJECT_DIR / ".ai-deploy-state.json" # sandbox_id + start_cmd per service
def public_base_url():
# Force https regardless of E2B_API_URL's own scheme.
parts = urlsplit(os.environ["E2B_API_URL"])
return urlunsplit(("https", parts.netloc, "", "", ""))
def load_state():
return json.loads(STATE_FILE.read_text()) if STATE_FILE.exists() else {}
def save_state(state):
STATE_FILE.write_text(json.dumps(state, indent=2))
def get_or_create_sandbox(state, key, template, idle_timeout, envs=None):
"""Reuse the recorded sandbox if it still exists, else create one.
Returns (sandbox, service_state_entry, created)."""
entry = state.setdefault(key, {})
sandbox_id = entry.get("sandbox_id")
if sandbox_id:
try:
return Sandbox.connect(sandbox_id), entry, False # reused
except SandboxNotFoundException:
pass # deleted/expired — fall through and create a new one
sbx = Sandbox.create(
template=template,
timeout=-1, # no hard lifetime; idle timeout owns reclamation
metadata={"idleTimeout": str(idle_timeout)},
lifecycle={"on_timeout": "pause", "auto_resume": True},
envs=envs
)
entry["sandbox_id"] = sbx.sandbox_id
return sbx, entry, True # freshly createdPick per service, based on size.
Files API — simplest, no remote needed. Good for a handful of files:
def upload_dir(sbx, local_dir, workdir, skip=()):
for local in sorted(local_dir.rglob("*")):
if not local.is_file():
continue
rel = local.relative_to(local_dir).as_posix()
if rel in skip:
continue
with open(local, "rb") as file:
sbx.files.write(f"{workdir}/{rel}", file)Git clone/pull — better for many files (large source tree, a built frontend). Requires the project already pushed to a remote (step 3):
def sync_via_git(sbx, workdir, repo_url, branch=None, username=None, password=None):
if sbx.files.exists(f"{workdir}/.git"):
sbx.git.pull(workdir, branch=branch, username=username, password=password)
else:
sbx.git.clone(repo_url, path=workdir, branch=branch,
username=username, password=password)Never commit node_modules/venv to carry dependencies this way —
install them inside the sandbox instead (step 6).
Skip for a stdlib-only service. Otherwise, run the install command against the working directory like any other command:
def install_deps(sbx, workdir, cmd, timeout=300):
sbx.commands.run(cmd, cwd=workdir, timeout=timeout)
# install_deps(sbx, WORKDIR, "pip install -r requirements.txt")
# install_deps(sbx, WORKDIR, "npm install --omit=dev")Kill any previous run of this service — files.write() alone doesn't
make a running process pick up new code — start the fresh one with
output redirected to a log file, then verify it's actually serving.
The sandbox has no ps command; use sbx.commands.list() to see what's running instead:
def restart_service(sbx, workdir, match, start_cmd, port, log_file="service.log"):
for proc in sbx.commands.list():
if proc.cwd == workdir and any(match in arg for arg in proc.args):
sbx.commands.kill(proc.pid)
sbx.commands.run(f"{start_cmd} > {log_file} 2>&1", background=True, timeout=0, cwd=workdir)
try:
sbx.commands.run(f"curl -sf --retry 30 --retry-delay 1 --retry-all-errors "
f"-o /dev/null http://localhost:{port}/")
except CommandExitException:
log = sbx.files.read(f"{workdir}/{log_file}")
raise RuntimeError(f"{match} failed to start on port {port}, log:\n{log}") from NoneRetake only when the command line changes (new entry file, port, or flags) — a resumed sandbox re-runs the recorded command from scratch and picks up whatever's currently on disk, so a code-only redeploy doesn't need one:
def maybe_snapshot(sbx, entry, start_cmd, created):
if created or entry.get("start_cmd") != start_cmd:
sbx.create_snapshot()
entry["start_cmd"] = start_cmdPersist sandbox_id/start_cmd every run, not just the first deploy —
step 8's comparison depends on it staying current.
If step 3 pushed, push again now including the updated
.ai-deploy-state.json — a checkout from any machine then has both the
latest code and the sandbox IDs it's already running on.
PROJECT_DIR is the project root and anchors the one shared
STATE_FILE. For a single service, it's also the service's
source directory:
state = load_state()
base = public_base_url()
py_deps = f"{WORKDIR}/pylibs"
sbx, entry, created = get_or_create_sandbox(state, "service", "sandbox-base", idle_timeout, envs={"PYTHONPATH": py_deps})
upload_dir(sbx, PROJECT_DIR, WORKDIR) # step 5 (files variant)
# install_deps(sbx, WORKDIR, "pip install -r requirements.txt") # step 6, if needed
start_cmd = "python3 server.py"
restart_service(sbx, WORKDIR, match="server.py", start_cmd=start_cmd, port=8000) # step 7
maybe_snapshot(sbx, entry, start_cmd, created) # step 8
save_state(state) # step 9
url = f"{base}/sandboxes/router/{sbx.sandbox_id}/8000/"
print("sandbox:", sbx.sandbox_id)
print("url:", url)If one service calls another, deploy the dependency first and feed its
internal address —
http://agent-sandbox/sandboxes/router/{sandbox_id}/{port}/, not the
public https:// URL — into however the caller reads its config (env
var, config file, whatever fits).
sample-app/
├── .ai-deploy-state.json # shared state — "backend"/"ui" keys
├── api/
│ └── server.py # stdlib JSON API, :8000
└── ui/
├── server.js # static file server + /api/* proxy, :3000
├── index.html
├── logo.svg
└── config.json # {"apiBase": ...} — written by the deploy scriptsample-app/ deploys two services, showing the "multiple services"
and "one calls another" patterns together: a stdlib Python API
(api/server.py, :8000) and a small site (ui/, :3000, Tailwind via CDN,
no build step) that fetches /api/hello. ui/server.js serves the
static files and proxies /api/* to the backend's internal address —
read from config.json, written by the deploy script once the backend
sandbox exists — so the browser only ever sees same-origin requests.
Both services use the files-API upload (small, no git needed) with no
build or install step.
Deploy with PROJECT_DIR = Path("./sample-app").resolve() — both
services share sample-app/.ai-deploy-state.json under the
"backend"/"ui" keys — uploading from PROJECT_DIR / "api" and
PROJECT_DIR / "ui" per the "Multiple services" pattern above.
{
"backend": {
"sandbox_id": "e48864184f2f42e898ef52246d0f1050",
"start_cmd": "python3 server.py"
},
"ui": {
"sandbox_id": "44a8b436893b4fdc988929967889eadb",
"start_cmd": "node server.js"
}
}Sandbox — create/connect/pause/snapshotcommands — run/list/kill processesgit — clone/pull/push inside the sandbox (step 5, git variant)filesystem — read/write/exists (step 5, files variant; log retrieval in step 7)© agent-sandbox, 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 skills/ai-deploy of agent-sandbox/agent-sandbox.
Open the folder on GitHubat commit 6f7b273
AI Deploy 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 |
|---|---|---|---|---|---|---|
| AI Deploy this skillagent-sandbox/agent-sandbox | 218 | — | ~3k | Automated safety check: Notes | Apache-2.0 | |
| Mac Fleet Maintenancesteipete/agent-scripts | 7.3k | — | ~4.8k | Automated safety check: Pass | MIT | |
| Sentry Miniapp SDKlizhiyao/sentry-miniapp | 686 | — | ~5k | Automated safety check: Pass | MIT | |
| Add Discovery Typerunwhen-contrib/runwhen-local | 163 | — | ~2k | Automated safety check: Pass | Apache-2.0 | |
| Money Opsiamzifei/show-me-the-money | 1k | — | ~3.8k | Automated safety check: Pass | Custom licence | |
| Triage Issueskubernetes-sigs/agent-sandbox | 4.2k | — | ~1.5k | Automated safety check: Pass | Apache-2.0 |
steipete/agent-scripts
Inventories and maintains a fleet of Macs from a desired-state file: package updates, repo and Xcode sync, and disk, backup and security health reports.
lizhiyao/sentry-miniapp
Full Sentry SDK setup for Mini Programs — error monitoring, tracing, offline cache, source maps.
runwhen-contrib/runwhen-local
Stand up a brand-new RunWhen Local discovery platform / indexer from scratch (a new cloud or resource source) following the native SDK pattern used by azureapi and gcpapi.
iamzifei/show-me-the-money
24/7 autonomous business operations orchestrator with business health scoring, canary monitoring, and safety guardrails.
kubernetes-sigs/agent-sandbox
Triage open GitHub issues for kubernetes-sigs/agent-sandbox by mapping them to roadmap.md and assigning k8s priority labels + Kanban Priority (P0–P4) on Project
tech-leads-club/agent-skills
Inspect Sentry issues, summarize production errors, and pull health data via the Sentry API (read-only).
agent-sandbox/agent-sandbox
Create, manage, and use E2B sandboxes — run commands, manage files, use git, persist state, and configure networking.
agent-sandbox/agent-sandbox
Execute code in E2B sandboxes and integrate with LLMs for tool calling.
agent-sandbox/agent-sandbox
Core E2B SDK knowledge — correct imports, namespacing, terminology, and API patterns.
Categories
Deploy a generated project (one process or several) to agent-sandboxes with scale-to-zero: idle sandboxes pause and auto-resume (process restarted) on the next HTTP request. AI Deploy is an agent skill from agent-sandbox/agent-sandbox. Deploy a generated project (one process or several) to agent-sandboxes with scale-to-zero: idle sandboxes pause and auto-resume (process restarted) on the next HTTP request.
AI Deploy fits situations like: asked to deploy; preview generated code through the sandbox platform.
Run `npx skills add agent-sandbox/agent-sandbox --skill ai-deploy -a claude-code`. Or copy the skill folder (skills/ai-deploy in agent-sandbox/agent-sandbox) into .claude/skills/ai-deploy in your project. Claude Code loads it when a task matches its description.
Run `npx skills add agent-sandbox/agent-sandbox --skill ai-deploy -a codex`. Or copy the skill folder (skills/ai-deploy in agent-sandbox/agent-sandbox) into .agents/skills/ai-deploy 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 agent-sandbox/agent-sandbox --skill ai-deploy -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ai-deploy, .gemini/skills/ai-deploy, .github/skills/ai-deploy and .opencode/skills/ai-deploy in your project.
Going by SKILL.md and its folder, AI Deploy needs the command-line tools its instructions call (pip and npm) and credentials named E2B_API_KEY. Our summary lists: Python 3; Node.js; A credential in E2B_API_KEY.
SKILL.md names 1 domain. As links in the text: e2b.dev. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
AI Deploy 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 3k 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 AI Deploy: Mac Fleet Maintenance (steipete/agent-scripts, 7.3k stars), Sentry Miniapp SDK (lizhiyao/sentry-miniapp, 686 stars), Add Discovery Type (runwhen-contrib/runwhen-local, 163 stars) and Money Ops (iamzifei/show-me-the-money, 1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
agent-sandbox (a GitHub organization) maintains it in agent-sandbox/agent-sandbox, which has 218 GitHub stars. The repository holds 4 skills in this directory. The repository was last updated on September 20, 2026.
Source: agent-sandbox/agent-sandbox on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.