Metadata-Version: 2.4
Name: yarno
Version: 0.2.0
Summary: write bots for we.yarno — cards, inline forms, server-counted polls, live values, voice
Author: alfa
License-Expression: MIT
Project-URL: docs, https://dev.we.yarno.lol/docs
Project-URL: source, https://github.com/alfaoz/yarno-sdk
Keywords: yarno,bot,chat,socketio
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Chat
Classifier: Framework :: AsyncIO
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-socketio[asyncio_client]>=5.11
Requires-Dist: aiohttp>=3.9
Provides-Extra: voice
Requires-Dist: livekit>=0.17; extra == "voice"
Dynamic: license-file

# yarno

write bots for [we.yarno](https://we.yarno.lol) — the invite-only
servers/channels/voice app.

```bash
pip install yarno
```

the shortest complete bot:

```python
from yarno import Bot

bot = Bot()                    # reads $YARNO_TOKEN

@bot.command("hi", "says hi")
async def hi(ctx):
    return f"hi {ctx.username}"

bot.run()
```

no intents, no command tree, no `sync()` step, no 3-second deadline. your bot
holds a live socket to the instance, so the decorator *is* the registration
and a handler can take as long as it needs.

## what you get

- **cards** — compose rows, columns, progress bars, images, buttons instead
  of filling in an embed
- **inline forms** — `ui.input` / `ui.select` / `ui.toggle` / `ui.slider`
  live in the card, in the channel; any click submits the whole form as
  `ctx.values`. no modals.
- **polls that outlive you** — `ui.button(collect="v:yes")` is counted by the
  server, so votes land while your process is down; read them back with
  `bot.tallies()`
- **live values** — `ui.ticker` / `ui.bar(rate=...)` advance on every
  viewer's screen; you push state changes, not frames
- **docked cards** — pin one card above the channel's scroll (now playing,
  scoreboards, countdowns)
- **autocomplete** — suggest argument values as someone types, over your
  already-open socket
- **dms, files, reactions, avatars, voice** — `@bot.on_message`,
  `send(files=[...])`, `bot.react()`, `bot.set_avatar()`, and
  `bot.voice_join()` with the `yarno[voice]` extra
- **buttons that survive restarts** — per-message state lives on the server
  and rides back with every click

## privacy, stated up front

a bot sees nothing by default: commands aimed at it, clicks on its own
cards, and dms it's part of. it does **not** receive channel messages, and
there is no intent to flip on. the read apis hold the same line.

## docs

- [quickstart](https://dev.we.yarno.lol/docs/quickstart) — token to working
  command in about two minutes
- [cards & components](https://dev.we.yarno.lol/docs/cards)
- [the full sdk reference](https://dev.we.yarno.lol/docs/sdk)
- [wire protocol](https://dev.we.yarno.lol/docs/protocol) — for writing a
  bot in another language

examples live in [`examples/`](examples/): `pingpong.py` is the core loop,
`lunchbot.py` is forms + polls + autocomplete + a docked countdown.

tokens come from the [dev console](https://dev.we.yarno.lol). we.yarno is
invite-only; the sdk is public so bots can be written for it.
