Markdown reference
shithub renders user-authored markdown — issue bodies, comments, PR descriptions, READMEs — through a CommonMark + GFM parser with a UGC-safe sanitizer. The set we support is close to GitHub's, with a few deliberate omissions.
Basics
# Heading 1
## Heading 2
### Heading 3
**bold**, *italic*, ~~strikethrough~~, `inline code`.
> A blockquote.
- bullet
- list
1. ordered
2. list
[link text](https://example.com)

--- (horizontal rule)
Code
Three-backtick fenced blocks with an optional language tag. The language drives syntax highlighting (chroma).
```go
func main() {
fmt.Println("hello")
}
```
Tables
GFM-style:
| Column A | Column B |
|----------|----------|
| cell 1 | cell 2 |
| cell 3 | cell 4 |
Alignment with ::
| Left | Center | Right |
|:-----|:------:|------:|
Task lists
- [x] done
- [ ] todo
Checkboxes are clickable in issues and PRs you can edit.
References
shithub auto-links these in any user-authored markdown:
#123— issue or PR in the current repo.owner/repo#123— issue/PR in another repo.@username— user mention; notifies them.@org/team— team mention.- A SHA (full or 7+ chars) — commit link.
Emoji shortcodes
:rocket: → 🚀, :eyes: → 👀, etc. The set matches GitHub's
shortcode list.
What we don't support
- Inline HTML — sanitized away. Use markdown alternatives.
<style>/<script>— sanitized away.- Custom HTML attributes (
onclick,style,idon arbitrary elements) — stripped. - Footnotes — not yet (planned).
- MathJax / KaTeX — not yet (planned).
- Mermaid diagrams — not yet (post-MVP).
README-style HTML alignment (align="center" on headings,
paragraphs, or divs) and image dimensions (<img width="200">) are
preserved because GitHub READMEs commonly use them for logos and
badges.
Why a sanitizer?
User-authored markdown is the largest XSS surface on a forge.
shithub renders through a single helper (internal/markdown)
that runs every input through a bluemonday UGC policy after
parsing. Anything outside the supported set is silently dropped,
not preserved as escaped text.
Previewing
Issue and PR forms have a "Preview" tab that renders the markdown through the exact same pipeline we use for the saved version. What you see in preview is what you'll see after submit.
View source
| 1 | # Markdown reference |
| 2 | |
| 3 | shithub renders user-authored markdown — issue bodies, comments, |
| 4 | PR descriptions, READMEs — through a CommonMark + GFM parser |
| 5 | with a UGC-safe sanitizer. The set we support is close to |
| 6 | GitHub's, with a few deliberate omissions. |
| 7 | |
| 8 | ## Basics |
| 9 | |
| 10 | ``` |
| 11 | # Heading 1 |
| 12 | ## Heading 2 |
| 13 | ### Heading 3 |
| 14 | |
| 15 | **bold**, *italic*, ~~strikethrough~~, `inline code`. |
| 16 | |
| 17 | > A blockquote. |
| 18 | |
| 19 | - bullet |
| 20 | - list |
| 21 | |
| 22 | 1. ordered |
| 23 | 2. list |
| 24 | |
| 25 | [link text](https://example.com) |
| 26 | |
| 27 |  |
| 28 | |
| 29 | --- (horizontal rule) |
| 30 | ``` |
| 31 | |
| 32 | ## Code |
| 33 | |
| 34 | Three-backtick fenced blocks with an optional language tag. The |
| 35 | language drives syntax highlighting (chroma). |
| 36 | |
| 37 | ```` |
| 38 | ```go |
| 39 | func main() { |
| 40 | fmt.Println("hello") |
| 41 | } |
| 42 | ``` |
| 43 | ```` |
| 44 | |
| 45 | ## Tables |
| 46 | |
| 47 | GFM-style: |
| 48 | |
| 49 | ``` |
| 50 | | Column A | Column B | |
| 51 | |----------|----------| |
| 52 | | cell 1 | cell 2 | |
| 53 | | cell 3 | cell 4 | |
| 54 | ``` |
| 55 | |
| 56 | Alignment with `:`: |
| 57 | |
| 58 | ``` |
| 59 | | Left | Center | Right | |
| 60 | |:-----|:------:|------:| |
| 61 | ``` |
| 62 | |
| 63 | ## Task lists |
| 64 | |
| 65 | ``` |
| 66 | - [x] done |
| 67 | - [ ] todo |
| 68 | ``` |
| 69 | |
| 70 | Checkboxes are clickable in issues and PRs you can edit. |
| 71 | |
| 72 | ## References |
| 73 | |
| 74 | shithub auto-links these in any user-authored markdown: |
| 75 | |
| 76 | - `#123` — issue or PR in the current repo. |
| 77 | - `owner/repo#123` — issue/PR in another repo. |
| 78 | - `@username` — user mention; notifies them. |
| 79 | - `@org/team` — team mention. |
| 80 | - A SHA (full or 7+ chars) — commit link. |
| 81 | |
| 82 | ## Emoji shortcodes |
| 83 | |
| 84 | `:rocket:` → 🚀, `:eyes:` → 👀, etc. The set matches GitHub's |
| 85 | shortcode list. |
| 86 | |
| 87 | ## What we don't support |
| 88 | |
| 89 | - **Inline HTML** — sanitized away. Use markdown alternatives. |
| 90 | - **`<style>` / `<script>`** — sanitized away. |
| 91 | - **Custom HTML attributes** (`onclick`, `style`, `id` on arbitrary |
| 92 | elements) — stripped. |
| 93 | - **Footnotes** — not yet (planned). |
| 94 | - **MathJax / KaTeX** — not yet (planned). |
| 95 | - **Mermaid diagrams** — not yet (post-MVP). |
| 96 | |
| 97 | README-style HTML alignment (`align="center"` on headings, |
| 98 | paragraphs, or divs) and image dimensions (`<img width="200">`) are |
| 99 | preserved because GitHub READMEs commonly use them for logos and |
| 100 | badges. |
| 101 | |
| 102 | ## Why a sanitizer? |
| 103 | |
| 104 | User-authored markdown is the largest XSS surface on a forge. |
| 105 | shithub renders through a single helper (`internal/markdown`) |
| 106 | that runs every input through a `bluemonday` UGC policy after |
| 107 | parsing. Anything outside the supported set is silently dropped, |
| 108 | not preserved as escaped text. |
| 109 | |
| 110 | ## Previewing |
| 111 | |
| 112 | Issue and PR forms have a "Preview" tab that renders the markdown |
| 113 | through the exact same pipeline we use for the saved version. |
| 114 | What you see in preview is what you'll see after submit. |