> ## 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 Client: Gateway, HTTP, State, and Commands

> The Client class is the heart of alterself. It owns the gateway connection, HTTP layer, state cache, event bus, and command registry.

The `Client` class is the central object in every alterself application. When you instantiate it, you get a single object that manages your Discord gateway WebSocket connection, sends and receives HTTP API requests, maintains an in-memory state cache of guilds, channels, users, and messages, routes raw gateway payloads through the event bus, and dispatches prefix commands to your registered handlers. You interact with Discord almost entirely through this one object.

## Constructor Parameters

Create a client by passing your token and any optional configuration:

```python theme={null}
import alterself

bot = alterself.Client(
    token="your-user-token",
    prefix="!",
    owner_ids=[123456789012345678],
)
```

| Parameter | Type | Default | Description |
| - | - | - | - |
| `token` | `str` | required | Discord user token |
| `prefix` | `str \| Callable` | `"!"` | Command prefix. A callable receives `(client, message)` and returns a `str` |
| `owner_ids` | `list[int]` | `None` | User IDs that can use owner-only commands. Automatically includes `me.id` after `READY` |
| `proxy` | `str` | `None` | HTTP proxy URL, e.g. `"http://user:pass@host:8080"` |

<Warning>
  Your token is a user account credential, not a bot token. Never commit it to source control. Load it from an environment variable or a secrets manager.
</Warning>

## Static vs Dynamic Prefix

You can supply a plain string prefix, or a coroutine (or regular function) that computes the prefix per message. Dynamic prefixes let you use different prefixes in different guilds, for different users, or based on any other runtime condition.

<CodeGroup>
  ```python Static prefix theme={null}
  import alterself

  bot = alterself.Client(token="...", prefix="!")
  ```

  ```python Dynamic prefix theme={null}
  import alterself

  async def get_prefix(client, message):
      # Use "?" in one guild, "!" everywhere else
      if message.guild_id == 123456789:
          return "?"
      return "!"

  bot = alterself.Client(token="...", prefix=get_prefix)
  ```
</CodeGroup>

<Tip>
  Dynamic prefix callables can be `async` or plain synchronous functions. alterself awaits them automatically when they are coroutines.
</Tip>

## Running the Client

alterself gives you two ways to start the client: a blocking helper for simple scripts, and async entry points for when you need fine-grained lifecycle control.

<Steps>
  <Step title="Blocking run (recommended for simple bots)">
    Call `bot.run()` at the bottom of your script. It creates an event loop, connects to the gateway, and blocks until the process is interrupted.

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

    bot = alterself.Client(token="...", prefix="!")

    # ... register commands and events ...

    bot.run(log_level=logging.INFO)
    ```
  </Step>

  <Step title="Async start and close">
    Use `await bot.start()` and `await bot.close()` inside your own async entry point when you need to run other coroutines alongside the bot.

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

    bot = alterself.Client(token="...", prefix="!")

    async def main():
        await bot.start()
        # bot is now connected; do other async work here
        await bot.close()

    asyncio.run(main())
    ```
  </Step>

  <Step title="Waiting until ready">
    After calling `await bot.start()`, the client is connected but may not have finished processing the initial `READY` payload and populating the cache. Await `bot.wait_until_ready()` before accessing guilds, channels, or `bot.me`.

    ```python theme={null}
    await bot.start()
    await bot.wait_until_ready(timeout=30.0)
    print(f"Logged in as {bot.me.username}")
    ```

    Raises `asyncio.TimeoutError` if the bot does not become ready within the given number of seconds.
  </Step>
</Steps>

## Properties

Once the client is running and ready, the following read-only properties are available:

| Property | Type | Description |
| - | - | - |
| `bot.me` | `User \| None` | The logged-in user object, populated after `READY`; `None` before the session is established |
| `bot.guilds` | `list[Guild]` | All guilds currently in the cache |
| `bot.latency` | `float` | WebSocket heartbeat latency in seconds |
| `bot.commands` | `list[Command]` | All registered top-level commands |
| `bot.cogs` | `list[Cog]` | All registered cogs |

## Changing Presence

You can update your user's online status and activity at any time after `READY` using `bot.change_presence()`.

```python theme={null}
import alterself

bot = alterself.Client(token="...", prefix="!")

@bot.on_event
async def on_ready():
    await bot.change_presence(
        status="dnd",                          # "online" | "idle" | "dnd" | "invisible"
        activities=[alterself.playing("with fire")],
        afk=False,
    )
    print(f"Ready as {bot.me.username}")

bot.run()
```

<Note>
  Presence updates are sent over the gateway. Discord rate-limits presence updates to a few per minute, so avoid calling `change_presence()` in a tight loop.
</Note>

## Cache Access

alterself keeps an internal state cache that is populated and updated as gateway events arrive. You can read from it directly when you need an object that was not passed to your handler:

```python theme={null}
# Retrieve a guild by ID
guild = bot._cache.get_guild(123456789012345678)

# Retrieve a channel by ID
channel = bot._cache.get_channel(987654321098765432)

# Retrieve a cached message by ID
message = bot._cache.get_message(111222333444555666)

# Retrieve a user by ID
user = bot._cache.get_user(444555666777888999)
```

All getters return `None` when the object is not present in the cache. Objects may be absent if they arrived before the cache was ready, or if they fall outside the configured cache limits.

<Note>
  The underscore prefix on `_cache` signals that it is an internal implementation detail. Its API may change between minor versions. For most use cases, prefer accessing objects through event handler arguments or context attributes.
</Note>

## Direct HTTP Access

For Discord API calls that are not wrapped by a high-level method, you can use the underlying HTTP client directly:

```python theme={null}
# Fetch a list of messages from a channel
messages = await bot.http.fetch_messages(channel_id=987654321, limit=50)

# Send a message to a channel
await bot.http.send_message(channel_id=987654321, content="Hello!")
```

`bot.http` is an instance of `alterself.http.HTTPClient`. It handles authorization headers, rate-limit buckets, and automatic retries on `429` responses. You can also call `bot.http.request(endpoint)` with a raw `Endpoint` object for any Discord API call not covered by a named helper. For a full list of available methods, see the [HTTP Methods reference](/api/http-messages).
