> ## Documentation Index
> Fetch the complete documentation index at: https://docs.confess.best/llms.txt
> Use this file to discover all available pages before exploring further.

# alterself Cogs: Group Commands and Event Listeners

> Use alterself Cogs to group related commands and listeners into reusable classes. Add and remove cogs at runtime to manage your bot's features.

As your bot grows, placing every command and event listener in a single file quickly becomes hard to navigate and maintain. Cogs solve this by letting you group related commands, listeners, and shared state into a self-contained class. You can load a cog to activate all of its features, unload it to disable them, and swap it at runtime without restarting your bot. This makes cogs the natural building block for organising bots of any size.

## Defining a Cog

A cog is a class that extends `alterself.Cog`. You decorate each command method with `@alterself.cmd()` and each listener method with `@alterself.listen()` just as you would on the top-level client. alterself discovers them automatically when the cog is registered.

```python theme={null}
import alterself

class GreetCog(alterself.Cog):

    @alterself.cmd(name="greet", aliases=["hello"], brief="Greet someone")
    async def greet(self, ctx, name="World"):
        await ctx.reply(f"Hello, {name}!")

    @alterself.listen("GUILD_CREATE")
    async def on_guild_join(self, guild):
        print(f"Joined guild: {guild.name}")
```

<Note>
  Command and listener methods inside a cog always receive `self` as the first argument, followed by the usual `ctx` (for commands) or event arguments (for listeners).
</Note>

### Lifecycle Hooks

Cogs support two optional lifecycle hooks that alterself calls automatically:

| Method | When it is called |
| - | - |
| `async def cog_load(self)` | After the cog is successfully added to the client via `bot.add_cog()` |
| `async def cog_unload(self)` | Before the cog is removed from the client via `bot.remove_cog()` |

Use these hooks to open database connections, start background tasks, or clean up resources:

```python theme={null}
import asyncio
import alterself

class BackgroundCog(alterself.Cog):

    def __init__(self):
        self._task = None

    async def cog_load(self):
        self._task = asyncio.create_task(self._background_loop())
        print("BackgroundCog loaded, task started.")

    async def cog_unload(self):
        if self._task:
            self._task.cancel()
        print("BackgroundCog unloaded, task cancelled.")

    async def _background_loop(self):
        while True:
            await asyncio.sleep(60)
            print("Background tick.")

    @alterself.cmd(brief="Show background task status")
    async def status(self, ctx):
        running = self._task and not self._task.done()
        await ctx.reply(f"Background task running: {running}")
```

## Registering Cogs

Add a cog instance to your client with `bot.add_cog()`. Remove it with `bot.remove_cog()`, passing the cog's class name as a string.

```python theme={null}
bot = alterself.Client(token="...", prefix=".")

bot.add_cog(GreetCog())
bot.add_cog(BackgroundCog())

# Later, remove by class name
bot.remove_cog("GreetCog")
```

<Tip>
  You can call `bot.add_cog()` at any time, before or after `bot.run()`. Adding a cog while the bot is running immediately makes its commands and listeners available.
</Tip>

<Warning>
  Calling `bot.add_cog()` with a cog whose class name is already registered raises `CogAlreadyLoaded`. Remove the existing instance first if you want to hot-reload a cog.
</Warning>

## Accessing Cogs

The `bot.cogs` property returns a dictionary of all currently loaded cogs, keyed by class name. Use it to inspect loaded cogs or to call methods on a cog from outside the cog itself:

```python theme={null}
# List all loaded cog names
print(list(bot.cogs.keys()))

# Retrieve a specific cog and call a method on it
admin = bot.cogs.get("AdminCog")
if admin:
    await admin.some_method()
```

## Worked Example: AdminCog

The following cog implements two owner-only admin utilities: `purge` to bulk-delete your own messages, and `sinfo` to display server information.

```python theme={null}
import asyncio
import alterself
from alterself.commands.checks import owner_only


class AdminCog(alterself.Cog):

    @alterself.cmd(brief="Purge N of your messages")
    @alterself.check(owner_only)
    async def purge(self, ctx, n="10"):
        count = min(int(n), 100)
        msgs  = await ctx.client.http.fetch_messages(
            ctx.channel_id, limit=count
        )
        my_ids = [
            int(m["id"]) for m in msgs
            if m.get("author", {}).get("id") == str(ctx.client.me.id)
        ]
        for mid in my_ids:
            await ctx.client.http.delete_message(ctx.channel_id, mid)
            await asyncio.sleep(0.4)
        notice = await ctx.send(f"Deleted {len(my_ids)} messages.")
        await asyncio.sleep(3)
        await ctx.client.http.delete_message(
            ctx.channel_id, int(notice["id"])
        )

    @alterself.cmd(brief="Show server info")
    async def sinfo(self, ctx):
        g = ctx.guild
        if not g:
            await ctx.reply("Not in a server.")
            return
        await ctx.reply(
            f"**{g.name}**\n"
            f"ID: `{g.id}`\n"
            f"Members: {g.member_count}\n"
            f"Boost tier: {g.premium_tier}"
        )


bot = alterself.Client(token="TOKEN", prefix=".")
bot.add_cog(AdminCog())
bot.run()
```

Let's walk through what each command does:

<Steps>
  <Step title="purge: delete your own messages">
    `purge` accepts an optional count `n` (default `10`, capped at `100`). It fetches the most recent messages in the current channel, filters for messages authored by you, deletes each one with a short sleep to avoid hitting the rate limit, and then sends a confirmation notice that auto-deletes after three seconds.

    The `@alterself.check(owner_only)` decorator ensures only you (or user IDs listed in `owner_ids`) can invoke this command.
  </Step>

  <Step title="sinfo: display server information">
    `sinfo` reads `ctx.guild` from the cache. If called in a DM where no guild is present, it replies with a helpful error. Otherwise it formats the guild name, ID, member count, and Nitro boost tier into a reply.
  </Step>
</Steps>

<Note>
  The `purge` command deletes messages one at a time with a `0.4 s` delay between each deletion. Discord's self-bot rate limits are stricter than bot rate limits, so be conservative with deletion speed to avoid triggering automated flagging.
</Note>
