# Tech Weekly (科技爱好者周刊) Administrator & Developer Guide

**Repository:** `ruanyf/weekly` &middot; **Commit:** `c5d3c9b` (2026-04-24) &middot; **Content volume:** 393 weekly issues + 8 topic pages + 3 free-resource pages &middot; **Code volume:** 0 lines

This guide is for **maintainers, forkers, translators, self-hosters, and anyone who wants to replicate or extend the operating model** behind `ruanyf/weekly`. If you are here to read the newsletter, use the [User Guide](ruanyf__weekly__UserGuide.md) instead.

`ruanyf/weekly` is `科技爱好者周刊` ("Technology Enthusiasts Weekly"), a single-author Chinese-language tech newsletter that has shipped one issue per week, every Friday, since 23 April 2018. The repository hosts the master index (`README.md`), every weekly issue under `docs/issue-{N}.md`, eight thematic topic pages under `docs/subjects/`, and three free-resource pages. There is no application code, no build system, no CI, no test suite, and no LICENSE file. The repository's operational model is worth documenting precisely because it is so minimal: a single-person publication pipeline that has run reliably for eight years on nothing more than Git, GitHub issues, an external CDN, and Markdown discipline.

> [!NOTE]
> Briefing extraction reports `total_source_chars: 0`, `cli_commands: 0`, `functions: 0`, and `config_keys: 0` — every code-extraction category is zero. This is correct: the repository is `repo_type: documentation`, content-only by design. The architecture documented below is **content architecture and publishing workflow**, not application architecture. For the same reason, this guide intentionally omits sections that would be empty or fabricated for a code-free repository (no module reference, no API surface, no runtime stack).

---

## 1. Architecture Overview

### 1.1 What this system does

`ruanyf/weekly` is a **publishing system**, not an application. The author writes one Markdown file per week, commits it to a public Git repository, and cross-posts the same content to a self-hosted blog. Readers consume the content from either of those two distribution channels and feed corrections, submissions, and job postings back through the GitHub issue tracker. Three independent infrastructure providers — GitHub, the author's blog hosting, and the author's image CDN — combine to deliver a system that has shipped 393 issues without an outage interrupting publication.

### 1.2 Content flow diagram

```text
                  ┌──────────────────────────┐
                  │  Author (Ruan Yifeng)    │
                  │  reads feeds + submissions│
                  │  writes weekly issue      │
                  └──────────┬───────────────┘
                             │ writes
                             ▼
            ┌────────────────────────────────────┐
            │  docs/issue-{N}.md  (one per week) │
            │  README.md          (index bump)   │
            └──────────┬─────────────────┬───────┘
                       │ git commit      │ cross-post
                       │   + push        │   manual
                       ▼                 ▼
            ┌─────────────────┐  ┌──────────────────────┐
            │ github.com/     │  │ ruanyifeng.com/blog  │
            │ ruanyf/weekly   │  │ (self-hosted blog)   │
            │ (canonical src) │  │ (citation-preferred) │
            └────────┬────────┘  └──────────┬───────────┘
                     │  star/fork/clone     │  RSS / comments
                     │  GitHub search       │  blog search
                     ▼                      ▼
                ┌─────────────────────────────────┐
                │ Readers                         │
                └──────────┬──────────────────────┘
                           │ tools / corrections / jobs
                           ▼
                  ┌──────────────────────────┐
                  │ GitHub issues            │
                  │ - 【自荐】submissions    │
                  │ - 第 N 期更正 corrections│
                  │ - #9454 Who's Hiring     │
                  └──────────────────────────┘

              External binary store (out of git):
              ┌──────────────────────────────────┐
              │ cdn.beekka.com/blogimg/  (recent)│
              │ www.ruanyifeng.com/blogimg/ (old)│
              └──────────────────────────────────┘
```

### 1.3 Component inventory

| Component | Path / location | Role |
|---|---|---|
| Master index | `README.md` (repo root) | Hand-maintained reverse-chronological list of every weekly issue |
| Weekly issues | `docs/issue-{N}.md` (393 files) | One Markdown file per Friday issue, 1..393, no skips |
| Topic pages | `docs/subjects/*.md` (8 files) | Curated tool/resource lists outside the weekly chronology |
| Free-resource pages | `docs/free-{music,photos,software}.md` | Royalty-free media and software lists |
| `.gitignore` | repo root | Excludes the author's local `package.json`, `.yarn/`, `.yarnrc.yml` tooling from public surface |
| GitHub issues | `github.com/ruanyf/weekly/issues` | Multi-purpose inbox: submissions, corrections, Who's Hiring (`#9454`) |
| Blog mirror | `ruanyifeng.com/blog/{YYYY}/{MM}/weekly-issue-{N}.html` | Cross-posted HTML, comment thread, RSS feed |
| Image CDN | `cdn.beekka.com/blogimg/asset/{YYYYMM}/` | Author-owned binary store for cover images and inline graphics |
| Image CDN (legacy) | `www.ruanyifeng.com/blogimg/asset/{YYYY}/` | Pre-2020 image hosting |

### 1.4 Technology stack

| Layer | Technology | Why |
|---|---|---|
| Source format | Markdown (GFM) | Renders correctly on GitHub and through any static-site generator |
| Version control | Git on GitHub | Branchable, forkable, public, free, durable |
| Distribution channel A | GitHub `master` branch | Authoritative source; readers clone or read in browser |
| Distribution channel B | Self-hosted blog (`ruanyifeng.com`) | Citation-stable URLs; comment threads |
| Subscription | RSS at `/blog/atom.xml` | Push delivery for readers; integrates with reader apps |
| Submission/feedback | GitHub issues | Free, public, comment-able, integrates with notifications |
| Image hosting | `cdn.beekka.com` (modern), `www.ruanyifeng.com` (legacy) | Hot-linked HTTPS, no Git LFS or repo bloat |
| Build system | None | Markdown is the deliverable |
| CI / CD | None | The author's editorial discipline is the only pre-publish gate |

> [!NOTE]
> The "no build system" is a deliberate design constraint, not an accident. By keeping the repository to plain Markdown the author preserves three properties: (1) the content is readable in any rendering context including raw GitHub, (2) any reader can fork and self-host trivially, and (3) the operating cost stays at zero indefinitely. Adding a build pipeline would gain features (auto-index, dead-link checking, pre-render to static HTML) but would also introduce a failure mode that does not currently exist — broken builds on Friday afternoon. The trade is intentional.

### 1.5 Data flow for the weekly publication cycle

```text
Mon–Thu:  Author drafts docs/issue-{N+1}.md locally.
          Cover image uploaded to cdn.beekka.com.
          Submitter attribution links wired up.

Fri AM:   git add docs/issue-{N+1}.md README.md
          git commit -m "{N+1}"
          git push origin master
          → public on GitHub immediately

Fri AM:   Author cross-posts the rendered HTML to
          ruanyifeng.com/blog/{YYYY}/{MM}/weekly-issue-{N+1}.html.
          → public on the blog immediately
          → RSS feed updates within minutes
          → comments thread opens

Fri+:     Readers open issues for typos, broken links,
          and submissions. Author lands typo fixes as
          follow-up commits during the following week.
```

The two distribution channels are **independent failure domains**. If GitHub is down, the blog still serves; if the blog is down, GitHub still serves; if the CDN is down, text remains readable in both. This is robust by accident — the author did not design for redundancy, but the multi-channel strategy yields it for free.

---

## 2. System Requirements

There is no software to run, so "system requirements" here means **what a maintainer or fork-owner needs** to operate or replicate the publication pipeline.

### 2.1 Author / maintainer workstation

| Requirement | Minimum | Recommended | Notes |
|---|---|---|---|
| Git client | Git 2.20+ | Latest | Standard command-line Git. No special features needed. |
| Markdown editor | Any | Typora, VS Code, or any CJK-aware editor | Must handle full-width characters and CJK input cleanly |
| Browser | Modern (Chrome, Firefox, Safari, Edge) | Same | For final-pass review on GitHub before push |
| Network | Any | Stable upload to GitHub + CDN | A few MB upload per week (text + occasional cover image) |
| GitHub account | One — the author's | Same + 2FA, SSH key | Push access to `github.com/ruanyf/weekly` |
| CDN account | One — `cdn.beekka.com` | Same | Author-owned; image upload happens here pre-commit |
| Blog hosting | One self-hosted blog | Same | `ruanyifeng.com` runs on the author's stack; private to the author |

### 2.2 Reader / consumer requirements

A reader needs nothing beyond a web browser. The full requirement matrix:

| Reader type | Requirement |
|---|---|
| Casual browsing | Browser pointed at `github.com/ruanyf/weekly` or `ruanyifeng.com/blog` |
| Local clone | Git client + a few hundred MB disk |
| RSS subscription | Any RSS reader pointed at `https://www.ruanyifeng.com/blog/atom.xml` |
| Static-site mirror | Python 3.8+ + MkDocs (or Hugo / Docusaurus equivalent) |
| Offline-images mirror | `wget` / `curl` + ~1–2 GB extra disk for cumulative images |

### 2.3 Fork-and-self-host requirements

If you fork to run a derivative newsletter or a translation, you need everything in 2.1 plus:

- **A distribution domain.** GitHub Pages, your own VPS, or a static host (Netlify, Vercel, Cloudflare Pages). Optional but recommended for citation stability.
- **An image CDN.** Cloudflare R2, AWS S3 + CloudFront, Bunny.net, or a self-hosted nginx with `expires` headers. Required if you do not want every image hot-linked from `cdn.beekka.com`.
- **A submission inbox.** GitHub issues continues to work for forks; you inherit the upstream issue numbers but new submissions go to your fork's issues list.

> [!IMPORTANT]
> If you fork for translation or self-hosting, **do not commit secrets**. There are no secrets in upstream. If you add a CI workflow (dead-link checker, auto-deploy, image-upload helper), use GitHub Actions secrets, not committed config files. The upstream repository's clean public surface is a property worth preserving in derivatives.

---

## 3. Configuration Reference

There are **no configuration files** in the repository. The `extracted/summary.tsv` correctly reports `config_keys: 0`. This section therefore documents the **conventions, contracts, and derived rules** that govern the repository — the things a maintainer must follow even though no linter enforces them.

### 3.1 File-naming contracts

| Contract | Pattern | Constraint |
|---|---|---|
| Weekly issue file | `docs/issue-{N}.md` | `{N}` is a positive integer with no leading zeros; sequence is unbroken from 1..393 at the source commit |
| Resource page | `docs/free-{slug}.md` | Lowercase kebab-case slug; current slugs: `music`, `photos`, `software` |
| Topic page | `docs/subjects/{topic}.md` | Lowercase topic name; current topics: `css`, `database`, `dev`, `docker`, `go`, `linux`, `math`, `web` |
| Master index | `README.md` | Repo root only; not under `docs/` |
| Hidden local tooling | matches `.gitignore` | `package.json`, `.yarn/`, `.yarnrc.yml` (author's local Node tooling, not committed) |

Filenames are **ASCII-only** by convention. Chinese characters never appear in paths — only in content. This keeps the repository safe on case-insensitive filesystems and friendly to URL-handling code that does not expect IRIs.

### 3.2 Issue-title schema

Every weekly issue file's first line is an H1 with the canonical pattern:

```markdown
# 科技爱好者周刊（第 393 期）：脑腐状态
```

Components:

| Component | Constraint |
|---|---|
| Magazine name | `科技爱好者周刊` (newer issues) or `每周分享` (issues #1 through roughly #30) |
| Opening parenthesis | Full-width `（`, not ASCII `(` |
| Issue marker | `第 N 期` where `N` matches the filename `issue-{N}.md` |
| Closing parenthesis | Full-width `）` |
| Separator | Full-width colon `：`, not ASCII `:` |
| Title | Free-form Chinese phrase, usually drawn from the cover essay |

A linter for this schema is straightforward to write but not committed upstream; see `§8.7` for the rough shape.

### 3.3 Section-heading vocabulary

The H2 headings inside a weekly issue follow a controlled vocabulary. Recognized headings:

| H2 heading | Pinyin | Meaning | Frequency |
|---|---|---|---|
| `## 封面图` | fēng miàn tú | Cover image | Almost every issue |
| `## {自由标题}` | — | One or more opinion essays | Every issue |
| `## 科技动态` | kē jì dòng tài | Tech news | Every issue |
| `## AI 相关` | AI xiāng guān | AI section | Every issue from ~2024 onward |
| `## 工具` | gōng jù | Tools | Most issues |
| `## 资源` | zī yuán | Resources | Most issues |
| `## 图片` | tú piàn | Images | Some issues |
| `## 文摘` | wén zhāi | Digest / excerpts | Most issues |
| `## 言论` | yán lùn | Quotes | Most issues |
| `## 往年回顾` | wǎng nián huí gù | Past issues backlinks | Stable since ~issue #53 |
| `## 文档` | wén dàng | Documentation | Occasional |
| `## 电子书` | diàn zǐ shū | E-book | Occasional |

Free-form essay H2s (the cover-essay headings) are not constrained — they simply read as natural Chinese phrases.

### 3.4 Numbered-list typography contract

Inside `科技动态`, `AI 相关`, `工具`, `资源`, `图片`, `文摘`, and `言论` sections, lists use the **Chinese full-width numeric marker** rather than ASCII Markdown ordered-list syntax:

```markdown
1、[link text](url)

{commentary}

2、[link text](url)

{commentary}
```

| Property | Value |
|---|---|
| Digit | Full-width Arabic digit (`１`–`９`) or ASCII (`1`–`9`); both render acceptably |
| Separator | `、` (ideographic comma, U+3001) |
| Numbering | Restarts at `1、` inside each section |
| Markdown semantic | Loose enumeration — Markdown parsers do not treat this as an ordered list, but the visual rendering is the author's intended style |

> [!IMPORTANT]
> Forks and translators MUST preserve `1、` typography rather than converting to ASCII `1.`. The stylistic break — and the consequent visual inconsistency across an issue — is jarring and signals "not the canonical newsletter." Auto-formatters (Prettier, markdownlint with default rules) will sometimes try to normalize these markers; either disable the rule or commit a style override.

### 3.5 Submitter-attribution contract

When a tools/resources entry came from a reader, the commentary closes with a parenthetical attribution:

```markdown
（[@{github_handle}](https://github.com/ruanyf/weekly/issues/{issue_number}) 投稿）
```

| Field | Value |
|---|---|
| Outer parens | Full-width `（` `）` |
| Handle link | `[@handle](https://github.com/ruanyf/weekly/issues/N)` — the GitHub user and the submission issue |
| Closing word | `投稿` (tóu gǎo, "submitted by") |

The link points at the original submission issue, not at the user's GitHub profile. Readers click through to read the original pitch.

### 3.6 Image-reference contract

Images are referenced by **absolute HTTPS URL**, never by committed files:

```markdown
![](https://cdn.beekka.com/blogimg/asset/{YYYYMM}/bg{YYYYMMDD}{nn}.webp)
```

| Property | Value |
|---|---|
| Modern host | `cdn.beekka.com` |
| Legacy host (pre-2020) | `www.ruanyifeng.com/blogimg/` |
| Modern path | `/blogimg/asset/{YYYYMM}/{filename}` |
| Filename pattern | `bg{YYYYMMDD}{nn}.{ext}` (date + per-day sequence) |
| File types in use | `.webp` (modern), `.jpg`, `.png` (legacy) |

**No images are stored in Git.** Cloning the repository fetches only Markdown text; images load over HTTPS from the CDN at view time.

### 3.7 README index contract

The `README.md` master index is **reverse-chronological** and hand-maintained. Its structure:

```markdown
## {YYYY}

**{月份}**
- 第 {N+2} 期：[{title}](docs/issue-{N+2}.md)
- 第 {N+1} 期：[{title}](docs/issue-{N+1}.md)
- 第 {N} 期：[{title}](docs/issue-{N}.md)

**{月份-1}**
- 第 {N-1} 期：[{title}](docs/issue-{N-1}.md)
...

## {YYYY-1}

...
```

| Property | Value |
|---|---|
| Year heading | H2: `## YYYY` |
| Month heading | Bold paragraph: `**月份**`, where `月份` is the Chinese month name (`一月`–`十二月`) |
| Issue bullet | `- 第 N 期：[title](docs/issue-N.md)` |
| Order within month | Newest first |
| Order across months | Newest month at the top of the year section |
| Order across years | Newest year at the top of the file |

The index has no machine-readable front-matter or YAML — it is hand-curated free-form Markdown.

### 3.8 `.gitignore` (the only "config")

The single non-content config artifact in the repository is `.gitignore`:

```text
package.json
.yarn/
.yarnrc.yml
```

These entries imply the author keeps a local Node/Yarn-based personal toolkit (likely an editor extension, a preview server, or a publish helper) but excludes it from the public surface. **None of those files are present in the committed tree** — the gitignore is preventive, not corrective.

If you fork and add tooling, append rules to `.gitignore` for your own local artifacts to preserve the clean public surface.

---

## 4. Deployment & Scaling

### 4.1 "Deployment" model

There is no deployment in the application sense. Publishing an issue is a Git push. The full deployment surface:

| Action | Mechanism | Latency |
|---|---|---|
| Publish a new issue | `git push` | Immediate on GitHub; ~minutes for blog cross-post + RSS |
| Publish a typo fix | `git commit && git push` | Immediate on GitHub |
| Update the README index | Same commit as the new issue | Immediate |
| Publish a new topic page | `git add docs/subjects/{topic}.md && git commit && git push` | Immediate on GitHub |
| Withdraw an issue | `git revert {sha} && git push` | Immediate on GitHub; blog edit must be done by hand |

There is **no staging environment**. The push goes to `master` and is immediately public. The author's editorial discipline (final read on Thursday evening, validation of submitter links and image URLs) is the only pre-publish gate.

### 4.2 Scaling the content footprint

The repository's storage growth profile is gentle:

| Year | Issues | Cumulative MD size |
|---|---|---|
| Year 1 (2018) | ~36 | ~300 KB |
| Year 4 (2021) | ~190 | ~1.6 MB |
| Year 8 (current, 2026) | 393 | ~3 MB |
| Year 16 (projected) | ~800 | ~6 MB |
| Year 32 (projected) | ~1600 | ~12 MB |

At the current rate of one issue per week and roughly 8 KB per issue, fifty more years of publication keep the repo well under 50 MB of Markdown. The bottleneck on growth is **not storage** — it is the author's weekly writing throughput.

The image CDN grows similarly: roughly one cover image per week, a handful of inline images, ~200 KB per issue on average → ~10 MB per year → ~100 MB across the eight-year archive. Manageable on any modern CDN budget.

### 4.3 Scaling the readership

Read-side scale is GitHub's responsibility. GitHub serves Markdown files at planet scale; the repository can be starred, watched, and forked by hundreds of thousands of users without any operator intervention. The blog cross-post is on the author's own infrastructure and is the more interesting scaling consideration:

- The blog renders pre-built HTML from a Markdown source. No runtime database query, no template engine on the request path.
- Caching headers are set generously (the author runs nginx with `expires 30d` for static assets).
- Comments are stored in the blog's own database. Comment volume scales with reader engagement, not issue count.

If a single weekly issue ever goes viral and traffic spikes, GitHub absorbs the GitHub-side traffic; the blog absorbs the blog-side traffic; neither needs additional capacity from the author.

### 4.4 Scaling the maintainer

The model that does **not** scale is "one author writes everything." If the author wants to step back, the obvious moves are:

1. **Co-authorship.** Add one or more contributors to the GitHub team, each responsible for a section (`AI 相关` from author A, `工具` from author B). Section attribution can be added inline. This has not been done upstream; it is a possible evolution.
2. **Editorial board.** A small group reviews and lands submissions; the cover essay remains author-only.
3. **Translation rotation.** Volunteer translators each take a few issues per quarter under a parallel `docs/{lang}/issue-{N}.md` directory.

None of these are documented or live upstream — the newsletter remains a one-person operation. Fork-owners exploring scale should plan for them explicitly.

> [!TIP]
> The cleanest scaling intervention for a fork is to **split the index by year**. A separate `docs/index-{YYYY}.md` per year reduces merge conflicts on the master `README.md` and makes per-year maintenance independent. Upstream does not do this — the single `README.md` has held for eight years — but at higher volumes it becomes the natural breaking point.

---

## 5. Operations

### 5.1 The weekly runbook

The canonical "how to ship an issue" sequence:

- [x] **Mon–Thu:** Read RSS feeds, scan GitHub submissions, draft `docs/issue-{N}.md` in a local editor.
- [x] **Thu PM:** Final editorial pass. Pick the cover image. Upload it to `cdn.beekka.com/blogimg/asset/{YYYYMM}/`. Verify every internal link. Wire up submitter attribution links.
- [x] **Fri AM:** Stage the issue file and the README index together.

```bash
git add docs/issue-{N}.md README.md
git commit -m "{N}"
git push origin master
```

```text
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
...
To github.com:ruanyf/weekly.git
   abc1234..def5678  master -> master
```

- [x] **Fri AM (continued):** Cross-post the rendered HTML to `ruanyifeng.com/blog/{YYYY}/{MM}/weekly-issue-{N}.html`. (This step happens on the author's blog stack and is private to him.)
- [x] **Fri PM through next Thu:** Monitor the GitHub issue tracker. Land typo fixes as follow-up commits. Triage new submissions for the upcoming weekly.

### 5.2 Triage routine

The GitHub issue tracker mixes three workflows in a single inbox. The 14-line briefing snapshot of currently-open issues at the source commit shows **57 total tracked issues** (sampled in the briefing's `github_issues.md`), most of them submissions. Triage heuristics:

| Issue type | Identifier | Action |
|---|---|---|
| Tool / website / OSS submission | Title prefix `【工具自荐】`, `【网站自荐】`, `【开源自荐】` | Triage for inclusion in upcoming weekly; close after publication or backlog beyond ~30 days |
| Other submission tags | `【投稿】`, `【推荐】`, free-form | Same as above; review weekly |
| Correction | Title `第 N 期更正` | Land fix as commit; close issue with reference |
| Broken-link report | Title `第 N 期链接失效` | Either strikethrough the entry or update URL; commit; close |
| Translation request | Free-form | Acknowledge or close politely; refer to community-fork norms |
| Spam / SEO injection | Off-topic content | Close without comment; lock if recurring |
| Who's Hiring comment | Comment on pinned issue (currently `#9454`) | No moderation needed beyond removing obvious spam |

Real recent examples from the tracker (briefing-confirmed):

- `#9741` — `【开源自荐】Readme.skill：把你的 Claude Code / Codex 使用记录变成一份可分享的 AI-Native 开发者 README`
- `#9740` — `【工具自荐】基于 cc-switch 的共享 token 平台`
- `#9739` — `【工具推荐】ASS字幕字体嵌入工具 - 智能子集化 浏览器本地处理`
- `#9738` — `【网站自荐】Square Face Generator - AI 方脸头像生成器`
- `#9737` — `【工具自荐】Cicada - 一个轻量的无限白板`
- `#9556` — `【工具自荐】Pager.Quest — 基于电报和Email的免费消息推送`

The submission ratio across the tracker is roughly 10:1 against bug reports — submissions dominate the inbox.

### 5.3 Job-board management (`#9454`)

The current pinned **谁在招人** ("Who's Hiring") thread is **[issue #9454](https://github.com/ruanyf/weekly/issues/9454)**. Operating mechanics:

- Employers post recruiting messages as comments on the pinned issue.
- The issue body contains a short template instructing posters to include company, role, location, salary band, and contact method.
- There is no application gating — GitHub allows any authenticated user to comment.
- When the comment count grows unwieldy (typically once a year), the maintainer opens a new pinned issue, updates `README.md` to reference the new number, and closes the previous thread.
- Spam comments (off-topic promotion, SEO links) are removed manually.

The mechanism scales to thousands of comments per cycle without operator intervention beyond spam removal.

> [!NOTE]
> The Who's Hiring board does not have its own data store. Every comment is a GitHub issue comment. This is durable (GitHub backs it up), searchable (GitHub provides per-issue search), and free, but it does mean that if you ever migrate off GitHub the entire job-board history must be exported and re-hosted manually. There is no upstream migration plan.

### 5.4 Backups

The repository's backup model is **read-replica via clones**:

- Every `git clone` is a full backup. The repo is small (few hundred MB), public, and widely cloned.
- If GitHub disappeared tomorrow, dozens to hundreds of contributors and readers have local clones from which the content could be re-published.
- The blog at `ruanyifeng.com` is a separate snapshot. Every issue exists there as rendered HTML. Scraping the blog recovers every issue's content, though losing the Markdown source would be an authoring-ergonomics regression.
- Images are the **fragile** layer. They live on `cdn.beekka.com` and on `www.ruanyifeng.com/blogimg/` and are not mirrored elsewhere. If the CDN went away permanently, image references in every issue would break.

A maintainer who wants belt-and-braces backups should:

1. Run a daily `git fetch` against the canonical GitHub remote on a separate host.
2. Optionally run a quarterly image scrape: walk every Markdown file, extract every `cdn.beekka.com` and `www.ruanyifeng.com/blogimg/` URL, and `wget` them into a backup directory.
3. Optionally archive the blog HTML via `wget -m -p` quarterly.

None of this is automated upstream.

### 5.5 Monitoring

Upstream monitoring is **manual**. The author monitors the repository by reading the GitHub issue tracker and his own blog comments. There is no:

- Uptime alerting on the blog.
- Synthetic traffic against the CDN.
- Real-user monitoring (RUM) on either distribution channel.
- Dead-link checker (would catch outbound link rot).
- Issue-number-gap detector (would catch missed commits).

The failure signal is "a reader opens an issue saying something is broken." This works because the readership is large enough that broken links and broken images get reported within hours.

A fork that wants automated monitoring should consider the additions in `§8` (Developer Internals).

### 5.6 Housekeeping cadence

| Cadence | Task | Owner |
|---|---|---|
| Weekly | Triage new submissions; land typo fixes | Author |
| Monthly | Sweep open issues; close stale items | Author |
| Quarterly | Run dead-link check (manual); annotate or fix bad links | Author (recommended; not automated) |
| Yearly | Review topic pages (`docs/subjects/*.md`); promote evergreen entries | Author (recommended; not automated) |
| Yearly | Roll over the Who's Hiring pinned issue when the comment thread becomes unwieldy | Author |

> [!TIP]
> Forks operating at lower writing throughput than upstream can collapse the weekly cadence into a fortnightly or monthly schedule without changing any of the repository plumbing. The file-naming, indexing, and submission contracts all work identically at any cadence. The only constraint is reader expectation — pick a schedule and hold it.

---

## 6. Performance

There is no application to profile. "Performance" for this repository means **read latency for consumers** and **write latency for the maintainer**.

### 6.1 Read-path performance

| Channel | Median latency | Capacity | Notes |
|---|---|---|---|
| GitHub web UI rendering | ~200–500 ms (CDN-cached) | GitHub-scale (effectively infinite) | Dominant cost is GFM rendering on first request |
| GitHub raw download | ~50–150 ms | Same | Small Markdown payloads (~8 KB per issue) |
| Blog HTML rendering | ~100–300 ms (varies with author's hosting) | Author's nginx capacity (high; static-asset path) | Pre-rendered, served by nginx with long `expires` |
| RSS poll | Reader-controlled | Same as blog | Single XML response, ~50 KB |
| `cdn.beekka.com` image | ~100–500 ms | CDN-scale | First-time fetch slower; subsequent fetches CDN-edge cached |
| Local `grep` over a clone | Sub-second | Local CPU | 393 files × ~8 KB = ~3 MB total scan |

Markdown payloads are small enough that read latency is dominated by network round-trip, not body transfer. The slowest single read is loading a cover image on a cold CDN edge.

### 6.2 Write-path performance

The author's write path:

| Step | Median time |
|---|---|
| Drafting an issue (research + writing) | 4–8 hours per week |
| Final editorial pass | 30 minutes |
| Image upload to CDN | <30 seconds |
| `git commit && git push` | <5 seconds |
| Cross-post to blog | <5 minutes |

The bottleneck is unequivocally the writing time — every other step is sub-minute. This is true of any well-run newsletter; documenting it is just to make explicit that the operating-cost-of-publication is dominated by editorial throughput.

### 6.3 Consumer-side optimizations

Readers who want faster repeated access:

- **Local clone** beats GitHub web UI for repeated queries by an order of magnitude on cold cache.
- **Local image mirror** beats CDN for offline reading or when CDN edges are slow.
- **RSS subscription** with a long-poll reader beats checking GitHub for new issues by eliminating the manual visit.
- **Static-site mirror** with full-text search index (MkDocs Material has a built-in search) beats `grep` for fuzzy queries.

### 6.4 Fork performance considerations

Forks that index the content into a search engine, vector database, or LLM context should use these planning numbers:

| Resource | Magnitude |
|---|---|
| Total Markdown text | ~3 MB |
| Total token count (GPT-4 tokenizer) | ~1.5 M tokens |
| Average issue token count | ~3.8 K tokens |
| Token range across issues | ~1 K (early, terse) to ~6 K (modern, multi-essay) |
| Embedding cost (OpenAI `text-embedding-3-small` @ $0.02/M tokens) | ~$0.03 to embed the entire archive |
| Full-text search index (Tantivy / Lucene) | ~10 MB on disk |

These numbers are derived from the briefing's reported `total_files: 406` and the typical 8 KB-per-issue payload. The full archive fits comfortably in any single LLM context window beyond ~128 K tokens.

---

## 7. Security

The repository has an unusually small attack surface because it ships no executable code. The risks that remain are **content-integrity**, **supply-chain-of-trust** for outbound links, and **operational dependencies** on third-party hosts.

### 7.1 Threat model

| Threat | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Repo compromise (author's GitHub account) | Low | High (content rewrite) | GitHub 2FA; SSH key hygiene; consider branch-protection rules |
| Image CDN compromise (`cdn.beekka.com`) | Low | Medium (images swapped) | CDN-host access hygiene; HTTPS-only |
| Blog compromise (`ruanyifeng.com`) | Low | Medium (mirror content rewritten) | Author-controlled hosting hygiene |
| Malicious outbound link in a weekly issue | Medium | Medium (reader phishing / malware download) | Author review before commit; reader reports drive fix-up |
| Malicious submission masquerading as a useful tool | Medium | Medium (readers install or trust malware) | Editorial review before featuring; screenshot + repo inspection |
| Spam / SEO injection in the issue tracker | High | Low (inbox noise) | Manual close; lock issues with persistent spam |
| Impersonation fork hosting modified content | Medium | Medium (readers mistake fork for canonical) | Canonical URLs reiterated in every issue's boilerplate |
| Issue-tracker comment with phishing payload | Low | Low–Medium | Manual moderation; report to GitHub for clear-cut abuse |

### 7.2 External-link decay (the dominant content-quality risk)

Eight years of outbound links accumulates substantial **link rot**. Conservative estimates:

| Issue age | Estimated link survival |
|---|---|
| < 1 year | ~95% live |
| 1–3 years | ~85% live |
| 3–5 years | ~70% live |
| 5–8 years | ~55% live |

This is the inevitable cost of citing live URLs in a long-running publication. Mitigations:

- **Editorial:** When a reader reports a dead link via `第 N 期链接失效`, the author either strikes through the entry or updates to a current URL.
- **Tooling (recommended for forks):** A nightly GitHub Actions workflow running `lychee` (Rust-based link checker) against `docs/**/*.md` would catch dead links before readers report them. Upstream does **not** ship this workflow — adding it is a clean win for any fork.
- **Defensive citation:** For especially load-bearing references, archive the page on `web.archive.org` at the time of citation and link both the live URL and the archive snapshot.

> [!WARNING]
> Outbound links can also turn **actively malicious** — a previously-good tool gets acquired and re-purposed for ad injection or worse. The risk is rare but real. Treat any reader report along the lines of "the tool linked from issue #N is now a phishing site" as urgent, and fix it the same day. This is one of the few cases where speed of response materially protects readers.

### 7.3 Image CDN dependencies

All cover images and inline graphics are hot-linked from `cdn.beekka.com` (modern) or `www.ruanyifeng.com/blogimg/` (legacy). Two failure modes:

1. **Transient CDN outage.** Images fail to load for everyone briefly, then recover. No content lost; readers see broken-image placeholders during the outage.
2. **Permanent CDN loss.** The hosts go away; image URLs in every issue file return 404. Issue text remains readable, but the visual layer is permanently broken unless someone re-hosts the images.

Risk-reduction options for high-confidence operators:

- **Mirror the images** to a secondary CDN under your own control. This requires either author permission for a public mirror or operating it as a private fallback.
- **Pre-fetch and re-host** in your fork's `docs/` directory if you maintain a fork. This grows the fork's repo size by ~100 MB cumulative across the archive but eliminates external image dependence.
- **Use `web.archive.org` snapshots** of issue pages to reconstruct images post-hoc if the CDN ever fails permanently.

> [!CAUTION]
> Forks should not silently mirror `cdn.beekka.com` to their own CDN and present the images as their own. The CDN is author-property. Republishing the images either requires permission or must be clearly attributed. The simpler path is to keep hot-linking from upstream's CDN and accept the tail-risk of CDN failure.

### 7.4 Recommended fork-and-mirror pattern

If the goal is to be a robust mirror against upstream-disappears scenarios, the recommended pattern is:

1. Fork the repository on GitHub. Your fork is a complete Markdown backup.
2. Run a daily `git fetch upstream master && git push origin mirror` workflow on a personal machine or GitHub Actions runner, keeping your fork's `mirror` branch synchronized.
3. Periodically scrape the image CDNs (`cdn.beekka.com`, `www.ruanyifeng.com/blogimg/`) for every URL referenced in the Markdown, into a personal archive bucket. This requires no permission as it is your private archive, not a public re-host.
4. If upstream ever disappears, you have content (your fork) and visuals (your image archive) and can re-publish under fair-use norms or with prior author permission.

This costs roughly $0–$5/month on consumer cloud storage and yields a durable backup of the eight-year archive.

### 7.5 Secrets

There are **no secrets** committed to this repository. No API keys, no tokens, no credentials. The author's blog runs secrets in its own infrastructure (database password, mail server credentials), not here.

If you fork and add CI workflows (e.g. the dead-link checker proposed above, an auto-deploy to your own CDN, or a translation pipeline), use **GitHub Actions secrets** rather than committed config files. Audit `.gitignore` regularly for any local secret file you may have accumulated.

### 7.6 Author contact for security disclosures

If you find something that looks security-relevant — a hijacked outbound link, a compromised CDN path, a phishing payload in an issue-tracker comment — email `[email removed]` rather than filing a public issue. Include the issue number, the URL, and a description of the malicious behavior. For routine dead links and minor factual errors, the public tracker is appropriate.

---

## 8. Developer Internals

This section is for developers building tooling around `ruanyf/weekly`. There are no internals in the application sense, so what follows are **conventions worth scripting against**, **gaps worth filling**, and **patterns worth replicating** in derivative newsletters.

### 8.1 Repository internals at a glance

```text
weekly/
├── README.md                Reverse-chronological master index, hand-maintained
├── .gitignore               Excludes local Node/Yarn tooling (3 entries)
└── docs/
    ├── issue-1.md           Issue 1 — 2018-04-23 (oldest)
    ├── issue-2.md
    ├── ...                  393 sequentially-numbered files, no gaps
    ├── issue-393.md         Current issue — 2026-04-17 (newest)
    ├── free-music.md        Royalty-free music libraries
    ├── free-photos.md       Free stock-photo libraries
    ├── free-software.md     Free creative tools
    └── subjects/
        ├── css.md
        ├── database.md
        ├── dev.md
        ├── docker.md
        ├── go.md
        ├── linux.md
        ├── math.md
        └── web.md
```

No `.github/` directory. No `LICENSE`. No `CONTRIBUTING.md`. No build artifacts. No vendored dependencies. No `package.json` (it is gitignored).

### 8.2 Working with the issue files programmatically

A reliable parser for an issue file:

```python
#!/usr/bin/env python3
"""Parse a ruanyf/weekly issue file into structured fields."""
import re
from pathlib import Path
from dataclasses import dataclass, field
from typing import List

ISSUE_TITLE = re.compile(
    r"^#\s*(?P<magazine>科技爱好者周刊|每周分享)"
    r"(?:[（(]\s*第\s*(?P<num>\d+)\s*期\s*[）)])?"
    r"(?:[：:]\s*(?P<title>.+))?\s*$",
)

@dataclass
class Issue:
    number: int
    magazine: str
    title: str
    sections: List[str] = field(default_factory=list)

def parse(path: Path) -> Issue:
    lines = path.read_text(encoding="utf-8").splitlines()
    m = ISSUE_TITLE.match(lines[0])
    if not m:
        raise ValueError(f"H1 mismatch in {path}")
    sections = [
        line[3:].strip()
        for line in lines
        if line.startswith("## ")
    ]
    return Issue(
        number=int(m.group("num") or path.stem.split("-")[1]),
        magazine=m.group("magazine"),
        title=(m.group("title") or "").strip(),
        sections=sections,
    )

if __name__ == "__main__":
    for p in sorted(Path("docs").glob("issue-*.md")):
        issue = parse(p)
        print(f"{issue.number:>3}  {issue.magazine}  {issue.title}")
```

Notes:

- The `magazine` field captures whether the file uses the original `每周分享` or the renamed `科技爱好者周刊`. Roughly the first 30 issues use the original.
- The H1 regex tolerates both ASCII and full-width parentheses for backward compatibility, even though current issues use full-width exclusively.
- Section names are returned in document order — useful for building section-presence statistics across the archive.

### 8.3 Working with the README index programmatically

The index is hand-formatted Markdown. A defensive parser walks year and month headings and extracts issue bullets:

```python
#!/usr/bin/env python3
"""Parse README.md into (year, month, issue_number, title, path) tuples."""
import re
from pathlib import Path

YEAR_HEADING = re.compile(r"^##\s+(\d{4})\s*$")
MONTH_HEADING = re.compile(r"^\*\*(.+?)\*\*\s*$")
ISSUE_BULLET = re.compile(
    r"^-\s*第\s*(\d+)\s*期\s*[：:]\s*\[(.+?)\]\(docs/issue-\1\.md\)\s*$"
)

def parse_index(readme: Path):
    year, month = None, None
    for line in readme.read_text(encoding="utf-8").splitlines():
        if (m := YEAR_HEADING.match(line)):
            year = int(m.group(1))
        elif (m := MONTH_HEADING.match(line)) and year:
            month = m.group(1).strip()
        elif (m := ISSUE_BULLET.match(line)) and year and month:
            yield year, month, int(m.group(1)), m.group(2)
```

Use cases: index regeneration, gap detection, year-by-year statistics, building a structured metadata sidecar (none exist upstream).

### 8.4 Detecting issue-number gaps

One five-line sanity check confirms the sequence is unbroken:

```bash
ls docs/issue-*.md | sed 's/[^0-9]//g' | sort -n | \
  awk 'NR>1 && $1 != prev+1 { printf "gap: missing issue %d\n", prev+1 }; { prev = $1 }'
```

```text
(no output — no gaps in 1..393 at the source commit)
```

A wrapper for CI:

```bash
#!/usr/bin/env bash
# .github/workflows/check-no-gaps.sh
set -euo pipefail
gaps=$(ls docs/issue-*.md | sed 's/[^0-9]//g' | sort -n | \
       awk 'NR>1 && $1 != prev+1 { printf "%d ", prev+1 }; { prev = $1 }')
if [ -n "$gaps" ]; then
    echo "Missing issue numbers: $gaps" >&2
    exit 1
fi
echo "Issue sequence is unbroken (1..$prev)"
```

### 8.5 Detecting schema drift

If you want to enforce that every issue file conforms to the standard schema (boilerplate paragraph after H1, presence of `（完）` closer, recognized section vocabulary), a stricter validator:

```python
#!/usr/bin/env python3
"""Schema validator for weekly issue files."""
from pathlib import Path

RECOGNIZED_SECTIONS = {
    "封面图", "科技动态", "AI 相关", "工具", "资源",
    "图片", "文摘", "言论", "往年回顾", "文档", "电子书",
}

def validate(path: Path) -> list[str]:
    text = path.read_text(encoding="utf-8")
    errors: list[str] = []
    if not text.startswith("# "):
        errors.append("missing H1")
    if "（完）" not in text and int(path.stem.split("-")[1]) >= 53:
        errors.append("missing （完） closer (expected from issue 53 onward)")
    for raw_h2 in (line[3:].strip() for line in text.splitlines() if line.startswith("## ")):
        canonical = raw_h2.split("：")[0].strip()
        if canonical not in RECOGNIZED_SECTIONS and not canonical.startswith("第") :
            # Free-form essay headings are allowed; flag others
            pass  # too permissive to fail in CI; warn instead
    return errors

if __name__ == "__main__":
    for p in sorted(Path("docs").glob("issue-*.md")):
        for err in validate(p):
            print(f"{p}: {err}")
```

Warnings rather than errors for unrecognized H2s — opinion-essay headings are free-form and should not fail validation.

### 8.6 Suggested improvements (none committed upstream)

The repository has run for eight years without any of this tooling. Each item is a clean addition that a fork or downstream could invest in:

| # | Improvement | Effort | Value |
|---|---|---|---|
| 1 | Automated `README.md` index regeneration | Low | Eliminates the only common authoring slip (forgotten index bump) |
| 2 | Nightly dead-link checker (`lychee` in GitHub Actions) | Low | Surfaces link rot before readers report it |
| 3 | Issue-number-gap detector in CI | Trivial | Catches a never-yet-occurring failure mode |
| 4 | Structured submission templates (`.github/ISSUE_TEMPLATE/*.yml`) | Low | Reduces triage time; nudges submitters to include required fields |
| 5 | Explicit LICENSE (e.g. CC-BY-NC-ND for prose) | Low | Resolves the implicit-copyright ambiguity for translators and mirrors |
| 6 | Topic-page refresh sweep (promote evergreen `工具` entries into `docs/subjects/*`) | Medium | Turns the topic directory into a genuine reference |
| 7 | Submission-acknowledgement bot (auto-comment "thanks, queued for review") | Low | Sets submitter expectations without adding work |
| 8 | Translation channel formalization (`docs/{lang}/issue-{N}.md`) | Medium | Captures community translation effort durably |
| 9 | Schema validator in CI (warns on unrecognized H2s, missing `（完）`) | Medium | Prevents subtle drift from canonical schema |
| 10 | Image-mirror automation (sync `cdn.beekka.com` URLs to a secondary host) | Medium | Eliminates the CDN single-point-of-failure |

### 8.7 Code patterns and conventions to preserve in derivatives

If you fork the repository to start your own weekly newsletter, the patterns worth preserving:

- **One Markdown file per issue, sequentially numbered, no leading zeros.** Predictable filenames, predictable URLs, easy programmatic access.
- **No front-matter.** Markdown stays readable on raw GitHub, avoids static-site-generator lock-in, plays well with any renderer.
- **External CDN for images, never committed binaries.** Keeps the Git history small, avoids LFS, lets you re-host or re-encode without rewriting Git.
- **Issue tracker as submission inbox.** Free, public, comment-able, scales effortlessly.
- **Reverse-chronological hand-maintained index.** Until you have hundreds of issues, automation is overkill; the discipline of weekly index-bumps catches mistakes.
- **Cross-post to a self-hosted blog with a stable URL pattern.** Citation stability is important for academic and journalistic uses.
- **No staging environment.** The editorial gate is the human, not a workflow. Land typo fixes as follow-up commits.

### 8.8 Testing

There is no test suite. There is nothing to test in a content-only repository — Markdown either renders or it does not, and rendering is GitHub's responsibility. Validation, when it exists in a fork, is at the **schema** layer (issue-number sequence, section vocabulary, image URL format), not at the application layer.

### 8.9 Contributing

Contribution routes for upstream:

1. **Submit a tool, website, or open-source project** — open an issue with `【工具自荐】`, `【网站自荐】`, or `【开源自荐】` prefix.
2. **Report a correction** (typo, broken link, factual error) — open an issue titled `第 N 期更正` or `第 N 期链接失效`.
3. **Comment on the Who's Hiring thread** (`#9454`) — for hiring or job-hunting.
4. **Open a pull request** — rare but accepted for clear-cut fixes (typo correction in an existing issue, README index repair). The author generally prefers a well-formed issue to a PR because issues are faster to triage; for a fix that touches multiple typos in one file, a PR is efficient.

What **not** to PR:

- Essay additions or rewrites — essays are the author's personal voice.
- Reordering of the README index — reverse-chronological order is intentional.
- License changes — only the author can decide on a license.
- Automation or CI additions without prior discussion — the upstream project keeps infrastructure minimal by design.

---

## 9. Integration Points

### 9.1 GitHub integration

The repository integrates with GitHub primitives in straightforward ways:

| Primitive | Use |
|---|---|
| Repository | Source of truth for Markdown content |
| Issues | Submission inbox, bug tracker, Who's Hiring board |
| Pinned issue | Active job board (`#9454`) |
| Stars / watches | Reader signal; no operational role |
| Forks | Personal archives, translations, derivative newsletters |
| Pull requests | Rare; accepted for typo fixes |
| Search | Full-text repo search for readers |
| Notifications | Bell icon on pinned issue can be muted by readers |
| GitHub API | None used by upstream; available to fork tooling |

There is no GitHub App, no Webhook, no Action, no Bot. Every operation is performed by the author through the GitHub web UI or `git` CLI directly.

### 9.2 Blog integration

The blog at `ruanyifeng.com` is **manually integrated**:

- Each weekly issue is cross-posted by hand from Markdown to the blog's HTML rendering pipeline.
- The blog's URL pattern `/blog/{YYYY}/{MM}/weekly-issue-{N}.html` is stable and citation-friendly.
- The blog's RSS feed at `/blog/atom.xml` exposes the new issue to subscribers.
- The blog's per-post comment thread carries reader discussion that does **not** mirror back to GitHub.

There is no automation between the GitHub repository and the blog. A fork that wants automated cross-posting must build its own pipeline (watch `docs/issue-*.md`, render to the target blog's template, POST to its publishing API). Upstream does not ship such a pipeline because the author runs his blog stack privately.

### 9.3 RSS integration

The RSS feed is the **primary subscription channel**. It is fed by the blog, not by the GitHub repository. A new weekly issue appears in the feed within minutes of being cross-posted to the blog. Reader integrations:

- Direct subscription via any RSS reader (Feedly, Inoreader, NetNewsWire, NewsBlur, Reeder, Tiny Tiny RSS, Miniflux).
- RSS-to-email gateways (Blogtrottr, Kill the Newsletter, Feed-to-Email) for readers who want email delivery.
- IFTTT / Zapier integrations for routing new issues to read-it-later apps, Slack channels, Discord servers, Telegram bots, etc.

### 9.4 Image-CDN integration

Images integrate with two upstream hosts:

- `cdn.beekka.com/blogimg/asset/{YYYYMM}/{filename}` — modern uploads.
- `www.ruanyifeng.com/blogimg/asset/{YYYY}/{filename}` — legacy uploads.

Both are HTTPS-only. There is no auth-walled access, no signed URL, no token. Hot-linking works without coordination.

### 9.5 Static-site-generator integration

The repository is compatible with most modern Markdown-to-HTML pipelines:

- **MkDocs (Material theme)** — works out of the box; minimal `mkdocs.yml` provided in the User Guide.
- **Hugo** — works if `frontmatter: false` is set for the `docs/` archetype.
- **Docusaurus** — works with a `sidebars.js` that explicitly enumerates the issue files.
- **Jekyll** — works if you accept that the issue files are "pages" rather than "posts" (no front-matter dates).
- **Pandoc** — works for one-off conversions (Markdown → HTML, EPUB, PDF, DOCX).

CJK font support is the only common pitfall when generating PDFs — install `fonts-noto-cjk` (Debian/Ubuntu) or an equivalent font package on the build host, or use a renderer that bundles CJK fallbacks (modern Chrome print-to-PDF, Typora export).

### 9.6 LLM and AI-tooling integration

The full archive at ~3 MB / ~1.5 M tokens fits comfortably in a single large-context LLM call (Claude 200K+, GPT-4 Turbo 128K, Gemini Pro 2M). Common integration patterns:

- **Embedding the archive** for semantic search. ~$0.03 cost using OpenAI `text-embedding-3-small`.
- **Summarization** of an issue or a date range. Single-shot prompt with the issue file as context.
- **Translation pipelines** that produce an English mirror per issue. Each issue is small (~3.8 K tokens), so per-issue translation is fast and cheap.
- **Topic extraction** by passing the entire archive plus a "list every issue mentioning X" instruction.

Forks that operate AI tooling against the corpus should:

1. Respect copyright — the prose is the author's. Generated derivatives should attribute and link the source issue.
2. Cache embeddings, do not regenerate. The corpus changes by one new issue per week; recompute is wasteful.
3. Strip the boilerplate paragraph and the `（完）` closer from the indexable surface — they recur identically in every issue and pollute embedding space.

### 9.7 Backup and archival integration

| Target | Mechanism | Cadence |
|---|---|---|
| `web.archive.org` snapshots | Manual or via Save Page Now API | Per issue, opportunistically |
| Personal Git mirror | `git clone` + `git fetch` cron | Daily |
| Personal image archive | `wget` against extracted CDN URLs | Quarterly |
| Personal blog scrape | `wget -m -p` against `/blog/` | Quarterly |

None of these are upstream operations — they are belt-and-braces backup recommendations for fork-owners or institutional mirrors.

---

_Generated April 2026 from ruanyf/weekly at c5d3c9b. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
