diff --git a/apps/docs/src/content/docs/guides/python-wrapper.mdx b/apps/docs/src/content/docs/guides/python-wrapper.mdx
new file mode 100644
index 0000000..73d2cfa
--- /dev/null
+++ b/apps/docs/src/content/docs/guides/python-wrapper.mdx
@@ -0,0 +1,229 @@
+---
+title: How to use HCTV's python wrapper!
+description: How to use HCTV's unofficial Python wrapper.
+---
+
+A Pycord-style Python wrapper for [hackclub.tv](https://hackclub.tv), made by [Christian](https://github.com/christianwell). Build chat bots with decorators and minimal boilerplate.
+
+Check it out on PyPI: https://pypi.org/project/hctvwrapper/
+You can take a look at the code [here](https://github.com/christianwell/hctvwrapper)
+
+```
+pip install hctvwrapper
+```
+
+## Quick Start
+
+```python
+from hctvwrapper import Bot
+
+bot = Bot(command_prefix="!")
+
+@bot.event
+async def on_ready(session):
+ print(f"Logged in as {session.viewer}")
+
+@bot.event
+async def on_message(message):
+ print(f"{message.author.username}: {message.content}")
+
+@bot.command()
+async def ping(ctx):
+ await ctx.reply("pong!")
+
+bot.run("hctvb_your_token_here", channel="bot-playground")
+```
+
+## Getting a Bot Token
+
+1. Go to [hackclub.tv](https://hackclub.tv)
+2. Create a bot account and get your API key (starts with `hctvb_`)
+3. Set it as an environment variable: `export BOT_TOKEN=hctvb_xxx`
+
+## Guide
+
+### Events
+
+Register event handlers with `@bot.event`. The function name determines which event it handles.
+
+```python
+@bot.event
+async def on_ready(session):
+ """Fired when the bot connects and receives session info."""
+ print(f"Logged in as {session.viewer.username}")
+ print(f"Can moderate: {session.permissions.can_moderate}")
+ print(f"Max message length: {session.moderation.max_message_length}")
+
+@bot.event
+async def on_message(message):
+ """Fired on every chat message."""
+ print(f"[{message.channel}] {message.author.username}: {message.content}")
+ # message.author.id, .pfp_url, .display_name, .is_bot,
+ # .is_platform_admin, .channel_role
+ # message.msg_id, .timestamp, .type
+
+@bot.event
+async def on_history(messages):
+ """Fired once on connect with up to 100 recent messages."""
+ print(f"Got {len(messages)} historical messages")
+
+@bot.event
+async def on_system_message(message):
+ """Fired on system notifications (bans, unbans, etc.)."""
+ print(f"System: {message.content}")
+
+@bot.event
+async def on_message_deleted(event):
+ """Fired when a message is deleted by a moderator."""
+ print(f"Message {event.msg_id} deleted in {event.channel}")
+
+@bot.event
+async def on_chat_access(access, channel):
+ """Fired when chat permissions change (timeouts, bans)."""
+ print(f"Can send in {channel}: {access.can_send}")
+ if access.restriction:
+ print(f" Restriction: {access.restriction.type}")
+
+@bot.event
+async def on_moderation_error(error, channel):
+ """Fired when a moderation action or message is rejected."""
+ print(f"Error in {channel}: {error.code} — {error.message}")
+ # error.code is one of: FORBIDDEN, RATE_LIMIT, SLOW_MODE,
+ # TIMED_OUT, BANNED, MESSAGE_TOO_LONG, BLOCKED_TERM,
+ # INVALID_TARGET, INVALID_REQUEST, NOT_FOUND
+```
+
+### Commands
+
+Register commands with `@bot.command()`. The bot automatically parses messages starting with the prefix.
+
+```python
+bot = Bot(command_prefix="!")
+
+# Simple command — no arguments
+@bot.command()
+async def ping(ctx):
+ await ctx.reply("pong!")
+
+# Named command with aliases
+@bot.command(name="say", aliases=["echo", "repeat"])
+async def say_cmd(ctx, *, text):
+ await ctx.send(text)
+
+# Positional arguments (split by whitespace)
+@bot.command()
+async def greet(ctx, name, greeting="hello"):
+ await ctx.reply(f"{greeting}, {name}!")
+```
+
+### Context
+
+The `ctx` object passed to commands gives you everything you need:
+
+```python
+@bot.command()
+async def info(ctx):
+ ctx.message # the full Message object
+ ctx.author # shortcut to ctx.message.author (Author)
+ ctx.channel # channel name (str)
+ ctx.bot # reference to the Bot
+
+ await ctx.reply("text") # sends "@username text"
+ await ctx.send("text") # sends "text" without mention
+ await ctx.delete() # deletes the triggering message (needs mod perms)
+```
+
+### Sending Messages
+
+```python
+# Inside a command
+await ctx.reply("mentioned reply")
+await ctx.send("plain message")
+
+# Anywhere (if you have a reference to the bot)
+await bot.send("hello!", channel="bot-playground")
+```
+
+### Multi-Channel
+
+Connect to multiple channels at once:
+
+```python
+bot.run("hctvb_xxx", channels=["channel1", "channel2", "bot-playground"])
+```
+
+Messages and commands work across all channels. Use `ctx.channel` or `message.channel` to know which channel a message came from.
+
+```python
+@bot.event
+async def on_message(message):
+ print(f"[{message.channel}] {message.author.username}: {message.content}")
+
+@bot.command()
+async def where(ctx):
+ await ctx.reply(f"you're in {ctx.channel}")
+```
+
+### Moderation
+
+Bots with moderation permissions can manage users:
+
+```python
+# Timeout a user for 5 minutes (default)
+await bot.timeout_user("channel", user_id="user123", duration=300, reason="spam")
+
+# Ban a user
+await bot.ban_user("channel", user_id="user123", reason="repeated violations")
+
+# Remove a timeout
+await bot.lift_timeout("channel", user_id="user123")
+
+# Unban a user
+await bot.unban_user("channel", user_id="user123")
+
+# Delete a specific message
+await bot.delete_message("channel", msg_id="msg-uuid")
+```
+
+### Async Entry Point
+
+If you manage your own event loop:
+
+```python
+import asyncio
+
+async def main():
+ bot = Bot(command_prefix="!")
+
+ @bot.event
+ async def on_ready(session):
+ print("Connected!")
+
+ await bot.start("hctvb_xxx", channel="bot-playground")
+
+asyncio.run(main())
+```
+
+## Models Reference
+
+| Model | Fields |
+|---|---|
+| `Message` | `content`, `author`, `channel`, `msg_id`, `timestamp`, `type`, `is_bot` |
+| `Author` | `id`, `username`, `pfp_url`, `display_name`, `is_bot`, `is_platform_admin`, `channel_role` |
+| `Session` | `viewer` (Author), `permissions`, `moderation` |
+| `Permissions` | `can_moderate` |
+| `ModerationSettings` | `has_blocked_terms`, `slow_mode_seconds`, `max_message_length` |
+| `SystemMessage` | `type`, `channel`, `content`, `timestamp` |
+| `ChatAccess` | `can_send`, `restriction` |
+| `Restriction` | `type` (timeout/ban), `reason`, `expires_at` |
+| `ModerationError` | `code`, `message`, `restriction` |
+| `ModerationEvent` | `type`, `msg_id`, `channel` |
+
+## Requirements
+
+- Python 3.10+
+- `websockets` (only dependency)
+
+## License
+
+Copyright (c) 2026 Christian Well - [MIT License](https://github.com/christianwell/hctvwrapper/blob/main/LICENSE)
\ No newline at end of file
diff --git a/apps/docs/src/content/docs/guides/start-stream.mdx b/apps/docs/src/content/docs/guides/start-stream.mdx
index 0b9c0b3..71c5fd3 100644
--- a/apps/docs/src/content/docs/guides/start-stream.mdx
+++ b/apps/docs/src/content/docs/guides/start-stream.mdx
@@ -3,40 +3,40 @@ title: How to stream
description: Get started with OBS and streaming on hackclub.tv
---
-_This guide demonstrates how to stream with hackclub.tv via OBS Studio, for other streaming softwares you will need to edit these steps for your chosen softwear._
+_This guide demonstrates how to stream with hackclub.tv via OBS Studio. For other streaming software, you will need to adapt these steps for your chosen software._
-- Open OBS Studio
+- Open OBS Studio.
-(_if it is not installed head to [this webpage](https://obsproject.com/) to download the installer_)
+(_If it is not installed, head to [this webpage](https://obsproject.com/) to download the installer._)
-
+
-- In OBS, in the navbar click `File > Settings`
+- In OBS, click `File > Settings` in the top navigation bar.

-- In the popup Setting box, from the sidebar open `Stream`
+- In the Settings popup, open `Stream` from the sidebar.
-- Set `Service` box to `Custom...`
+- Set `Service` to `Custom...`.

-- Go to https://hackclub.tv/settings/channel/ on your chosen web browser
+- Go to https://hackclub.tv/settings/channel/ in your web browser.
-(_if you are not logged in you may have to log back in and then try again_)
+(_If you are not logged in, you may have to log in again and then try again._)
-- Under `Stream Settings` you will find your `Stream Key` and `Stream URL` - copy the `Stream URL` and paste it into OBS
+- Under `Stream Settings`, you will find your `Stream Key` and `Stream URL`. Copy the `Stream URL` and paste it into OBS.

-- Go back on to the website and click this
icon to regenerate your stream key - copy the new key and past it into the `Stream Key` box in OBS
+- Go back to the website and click this
icon to regenerate your stream key. Copy the new key and paste it into the `Stream Key` box in OBS.

(_Your OBS settings should now look like this_)
-- You can now safely `Apply` changes in OBS and start streaming!
+- You can now safely apply the changes in OBS and start streaming.
Thanks for using this guide and happy streaming!
-_A video tutorial is currently in the making, check back another time if you would like to see it!_
+_A video tutorial is currently being made, so check back later if you would like to see it!_