Contributor Handbook¶
Any community that collaborates for long enough accumulates unwritten rules: how to phrase a heading, how to name a file, what belongs in a pull request description, how issues get sorted, and the questions that come up in a contributor's first week. This handbook collects what would otherwise stay scattered across the README, issue comments, and Matrix conversations, so a new contributor can read it in one sitting and experienced members have something common to point at.
If this is your first time here, start with How to contribute to pick a direction, then come back for the specifics. Account requests and service entry points are on Community services.
Your first week¶
Sorted by what you want to do:
- Read first, decide later: pick anything from Concepts, then use the skill level self-assessment to gauge how familiar you are with Tor, Tails, and OONI
- Write or translate: request a Matrix account (see Community services), join the public Space, say what you would like to work on, and claim an issue
- Technical maintenance: request collaborator access to anoni-net/docs, then follow Development environment setup
- Event organizing: ask in the relevant Matrix room about what is coming up, and help with materials, on-site logistics, or registration
Every one of these starts with saying hello on Matrix. The community works asynchronously, so a reply landing a day or two later is the normal rhythm, not a snub.
Writing style¶
English and Chinese have separate rule sets¶
Traditional Chinese (docs/zh-TW) is the source of truth for the site, and its style rules cover Chinese punctuation, classifier repetition, register, and translated terminology. Those rules do not transfer, and several are actively wrong when applied to English. Em dashes, for example, are banned in Chinese body text and are ordinary English typography.
What follows is the English rule set. If you are writing or reviewing Chinese, use the Chinese contributor handbook (in Chinese) instead, which is the authority for zh-TW and zh-CN. The automated style linter in CI only covers docs/zh-TW and docs/zh-CN, so the English rules below rest on human review.
Voice and positioning¶
The English site is written for international peers, researchers, journalists, and English-preferring readers across the Sinophone Asia-Pacific, by people working inside the region. The prose should sound like it.
- Refer to ourselves as "we, a community based in Taiwan". Avoid "In Taiwan, we...", which addresses the reader as though they were also in Taiwan.
- Where a passage is specific to Taiwan, add the regional comparison rather than leaving Taiwan as the implied default. Mainland China, Hong Kong and Macau, Singapore, Malaysia, and the diaspora each have their own picture.
- Do not translate Chinese conceptual shorthand literally. Phrases like 在地脈絡 or 公民團體 turn into stilted English when carried across word for word. Say what is actually meant.
Terminology¶
- Write regulatory short names out in full on first use: PDPA becomes "the Personal Data Protection Act of Taiwan", VASP becomes "the virtual asset service provider regime".
- Write institution names out in full: 金管會 becomes "the Financial Supervisory Commission (FSC)".
- Give technical names a short expansion on first use: Tor (onion routing network), Tails (amnesic live operating system), OONI (Open Observatory of Network Interference).
- Cite English-language primary sources in footnotes. Do not cite the Chinese translation of a piece that exists in English.
Headings¶
- Do not use the "Topic: explanation" colon construction. Write a heading as a complete statement instead.
-
Brave and GPU fingerprinting: uniformity and randomization in one release -
Brave flattens GPU fingerprints two opposite ways
-
- This applies to article titles and to section headings at every level.
- Keep an external source's original title as-is when the link text quotes it.
- Existing articles do not need retrofitting. Apply this to new articles and substantial rewrites.
Paragraph voice¶
- Write like a community member who knows the subject explaining it, not like an encyclopedia entry.
- Do not end every paragraph with a summarizing sentence. Let paragraphs stop when they are finished.
- Avoid openers like "It is worth noting that", "In conclusion", and "All in all".
- Avoid the over-symmetrical three-part structure that reads as machine-generated.
- Define a concept by stating it completely. Constructions like "what this is about is" or "this refers to" push the definition out of focus without adding anything.
No animacy for things that are not people¶
Non-human subjects do not take human actions. The common cases and their fixes:
| Case | ||
|---|---|---|
| Organizations speaking | Brave said it would follow up later |
Brave's announcement said it would follow up later |
| Documents speaking | The report points out the risk |
The risk is in the report's conclusion |
| Software perceiving | The site sees an unfamiliar string |
The string the site receives is not in its existing list |
| Abstractions having intent | The toggle's existence says the trade-off remains |
Keeping the toggle means the trade-off remains |
Two exceptions. An organization acting as an agent keeps the plain verb when the action is something it can actually do (Brave shipped the protection, the Tor Project released a new version, OONI collects measurements). Direct quotations keep their original wording.
Cutting the machine-written texture¶
The edits that come up most in review:
- Delete the throat-clearing opener.
Let us first lay out the basics of CryptPad. It is...becomesCryptPad is.... Start with the content instead of announcing what is coming. - Cut filler transitions: "essentially", "in other words", "to put it plainly". Delete rather than replace where possible.
- Replace an abstract placeholder with the actual content.
The next section explains why that conclusion does not holdbecomesThe usage figures in the next section contradict it. - Drop intensifiers and emotional colour.
battle-tested under real-world pressurebecomeshas a record of production use. Ordinary terms do not need quotation marks for emphasis. - Do not open a paragraph with a bolded complete sentence. Promote parallel items to headings, and write standalone paragraphs as ordinary prose.
**Location.** OONI records the country and ASN...becomes a### Locationheading followed by the text. Bold words as sentence elements or list labels are fine (the **control day** uses the same parameters,**Data source**: ...). The test is whether the bolded text is a complete sentence ending in a period.
Numbers and identifiers¶
Mark list numbers, IDs, and serial numbers as inline code (10006, 10298), so a reader can see at a glance that they are identifiers rather than quantities.
Writing about security and privacy¶
Anonymity and privacy are the subject of this site, and the writing has to hold the same line:
- Do not publish recipes that can be misused. Even where the data and APIs are public, we do not walk readers through full enumeration, bulk scraping, de-anonymization, or bypassing a security control. State the result instead:
we took a snapshot of the full list on a given day, rather than printing the command that iterates every identifier. - Do not expose individual operators' accounts or handles. Refer to someone's observations by region or role (
an observer in Thailand), and name people only when they are already public and naming them is necessary. - Material involving victims, unpublished research, or personal data goes through Sending us sensitive material.
Files and directories¶
Filenames¶
- All lowercase, hyphen-separated (
tor-browser-advanced.md,anonymity-vs-privacy.md) - Slugs in English
- Acronyms stay lowercase (
vasp-2026.md, notVASP-2026.md)
Directory structure¶
The structure stays flat. New articles go into an existing section:
| Section | Content |
|---|---|
basics/ |
Concepts. The thinking tools behind anonymity and privacy |
tools/ |
Specific tools, comparisons, and hardening guidance |
scenarios/ |
Situations and roles, and what they change |
regional/ |
Regional observation and local regulatory context across the Sinophone Asia-Pacific |
reports/ |
Curated external research, indexed with links to the originals |
community/ |
Governance, process, and entry points |
blog/ |
Posts and original commentary |
The English site uses regional/ where the Chinese site uses taiwan/. An English reader who sees taiwan/ assumes a site about Taiwan, while the content spans several jurisdictions with Taiwan as the anchor point.
If you are not sure where an article belongs, ask on Matrix before opening a PR, rather than moving it afterwards.
Moving, renaming, or deleting a page needs a redirect¶
When you move, rename, or delete a page that is already live, add the redirect in the same PR so the old URL does not turn into a 404. Old URLs live on in search engines, bookmarks, and other people's links.
- Redirects go in
plugins.redirects.redirect_mapsin the three mkdocs configs:mkdocs.ymlfor zh-TW (/docs/),mkdocs_en.ymlfor en, andmkdocs_cn.ymlfor zh-cn. - The format is
old path: new path, relative to each language's docs directory, without thedocs/<lang>/prefix. For example,'tools/what-is-ooni.md': 'tools/index.md'. - Where there is no one-to-one replacement, point at the section index (
community/index.md,tools/index.md). - Keep existing redirects. People keep arriving at old URLs. The one case for revisiting an entry is when its target page has itself been removed and the redirect now dead-ends.
- When you add a page at a path that an existing redirect points away from, remove that redirect entry in the same PR. Otherwise the redirect shadows the new page.
Splitting or moving content needs the inbound links checked¶
A redirect handles a URL that disappears. It does nothing for the case where a page stays put and the content moves out of it, which is what a page split produces. The old page still returns 200, so nothing reports an error, while every button and link pointing at it now promises material that has gone somewhere else.
When you split a page, or move a section from one page to another, search the site for links to the source page in the same PR and repoint the ones whose text refers to what moved. Two things to know about this check:
- Neither strict build nor the style linter catches it: Both target files exist and both links resolve, so the failure is in what the link means rather than whether it works. Only reading the link text against the destination finds it.
- Dated blog posts count: A post that was accurate when published keeps its text, and a button in it is a functional entry point rather than part of the record. Repointing the button does not alter what the post said at the time, and leaving it broken means a reader following it lands somewhere that no longer holds what they were promised.
This came up in August 2026: a May 2025 split moved the workshop recruitment content into its own page, and two earlier posts kept pointing at the original, where the material no longer was.
Images and assets¶
- Images go in
docs/en/assets/images/. - In markdown image syntax, the path is relative to the file:
../assets/images/filenamefrom a section directory such ascommunity/. - In raw HTML
<img src>and<a href>, the path resolves against the generated URL, not the source file. From a page at/docs/en/basics/internet-freedom/that means../../assets/images/filename. - Prefer webp or an optimized png. Do not commit unprocessed phone camera files.
- For a lightbox image, wrap
<img>in<figure>and<a href>, and keep both relative paths aligned.
Cross-file links¶
Internal links use relative paths, not absolute /docs/en/... paths:
- Same directory:
./other-file.md - Across directories:
../basics/anonymity-vs-privacy.md - Across depths:
../../blog/posts/2025to2026.md
Linking to a page that exists only in Chinese is the one case where you write a full URL, because the language sites build separately and no relative path reaches across them. Use /community/privacy-guide/ and mark it (in Chinese) so the reader knows what they are clicking. The default language, zh-TW, carries no language segment in its URLs. zh-CN uses lowercase /zh-cn/... and English uses /en/..., while the source directories keep their original casing.
Ending an article with a short "Related" section linking two to four other pages helps. Sideways links between concepts, tools, scenarios, and regional material are worth more than one-directional references.
Pull requests¶
Branch naming¶
blog/<short-slug>for blog posts (blog/throttle-drill-results)feat/<short-slug>for new features, new sections, writing rules, and substantial rewrites of existing pages (feat/title-colon-rule)fix/<short-slug>for bugs, styling, and small corrections (fix/table-width)
docs/ cannot be used as a prefix. docs is itself the build trigger branch, and git will not allow the same name to be both a ref and a directory of refs, so git switch -c docs/vasp-2026-rewrite fails with cannot lock ref.
Commit messages¶
Conventional commits:
<type>(<scope>): <subject>
<body>
Common types: docs, feat, fix, chore, refactor. The scope is a language or sub-project name (zh-TW, zh-CN, en, pulse, asn_coverage).
PR descriptions¶
A PR description covers at least:
- Why the change is being made, linking the issue or the community discussion
- What it touches: which files, which sections
- What it means for readers: whether links break, whether URLs change, whether other files need to change alongside it
Review¶
- Translation and copy editing: request at least one reviewer who is not the author
- Structural changes such as moves or nav edits: propose on Matrix first, then open the PR
- Images and assets: check alt text, filename, and licensing yourself
Maintainers merge. Contributors, including AI assistants working on a contributor's behalf, do not self-merge, and pages touching security-sensitive material always get a maintainer's technical review.
Issue labels¶
The label scheme, which is still settling:
type:docsdocumentationtype:bugincorrect behaviourtype:enhancementimprovement proposalstype:questiondiscussionarea:zh-TW/area:zh-CN/area:enby languagearea:tools/area:scenariosand the rest by sectiongood first issuefor newcomershelp wantedwhere more hands are needed
Search existing issues before opening a new one.
How translation works¶
zh-TW is the single source of truth. zh-CN and en are derived from it. The full process is in Localization and translation:
- New articles are written in zh-TW first
- zh-CN uses tool-assisted first drafts plus human adjustment for vocabulary differences
- en takes more human work, because the cultural context has to be re-framed rather than converted
- zh-CN and en do not have to ship together with zh-TW. They roll out as people are available
- When reviewing an English page that derives from a zh-TW original, the class of error to look for is named information being replaced by a category term. What goes missing when an English page derives from zh-TW has the test and how to run it
The English site is a rewrite, not a word-for-word translation. A page whose value is entirely in its Chinese-language context does not automatically get an English version, and an English page can carry regional comparisons its Chinese source does not have. Where an upstream English original already exists, as with translated Tor Project, OONI, Tails, and Signal blog posts, the English site links to the original instead of translating it back.
Where to look before asking¶
| Question | Page |
|---|---|
| How do I pick something to work on? | How to contribute |
| How do I get a Matrix account? | Community services |
| What suits my level? | Skill level self-assessment |
| How do I set up the development environment? | Development environment setup |
| What are the translation rules? | Localization and translation |
If none of those answer it, ask on Matrix. Include what you are trying to do, what you have already tried, and where you are stuck.
Code of conduct, in brief¶
The community works on openness, mutual support, and staying within the law. This is the short version. The full text, including role definitions, decision-making, and dispute handling, is in the governance charter, which takes precedence where the two differ.
- Mutual respect: members get the same treatment regardless of background or familiarity with the subject
- Argue the issue, not the person
- Lawful purposes: all discussion and collaboration presumes lawful use. We do not assist money laundering, tax evasion, harassment, stalking, or unauthorized intrusion
- Disclosure: anything involving personal data or sensitive material goes through Sending us sensitive material
- Disputes: raise it on Matrix first. Without consensus there, it goes to the next community sync
Conduct that breaches these gets handled by core members under the governance charter.
This handbook is a living document¶
If you hit something this page does not cover, or find a process that turns out to be under-documented, propose a change. Editing the contributor handbook is itself a good first issue.