{"id":22372523,"url":"https://github.com/annikav9/usv3-framework","last_synced_at":"2025-07-25T03:18:24.327Z","repository":{"id":265788659,"uuid":"860857268","full_name":"AnnikaV9/usv3-framework","owner":"AnnikaV9","description":"An extensible and modular bot framework for hack.chat","archived":false,"fork":false,"pushed_at":"2024-12-01T15:28:37.000Z","size":144,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T04:49:47.415Z","etag":null,"topics":["asyncio","hackchat","hackchat-bot","poetry","python","uvloop","websockets"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AnnikaV9.png","metadata":{"files":{"readme":"docs/README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"docs/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-21T10:58:34.000Z","updated_at":"2024-12-01T15:28:40.000Z","dependencies_parsed_at":"2024-12-02T00:15:14.077Z","dependency_job_id":null,"html_url":"https://github.com/AnnikaV9/usv3-framework","commit_stats":null,"previous_names":["annikav9/usv3-framework"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnnikaV9%2Fusv3-framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnnikaV9%2Fusv3-framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnnikaV9%2Fusv3-framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnnikaV9%2Fusv3-framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AnnikaV9","download_url":"https://codeload.github.com/AnnikaV9/usv3-framework/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245699263,"owners_count":20657987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asyncio","hackchat","hackchat-bot","poetry","python","uvloop","websockets"],"created_at":"2024-12-04T20:43:15.790Z","updated_at":"2025-03-26T17:19:54.889Z","avatar_url":"https://github.com/AnnikaV9.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# usv3\nAn extensible and modular bot framework for [hack.chat](https://hack.chat)\n\n\n## Setting up\nusv3 requires Python ^3.10 and [Poetry](https://python-poetry.org/)\n1. Set up the project with `poetry install`\n2. Configure the bot in [config](../config)\n3. Run the bot with `poetry run usv3`\n\nWhen testing, you can override the options in [config/core_config.yml](../config/core_config.yml) with flags:\n```bash\npoetry run usv3 --debug --server ws://127.0.0.1:6060 --channel testing\n```\n\n\n## Adding your own stuff\nusv3 can be extended by adding modules that get triggered on various events.\n\nA few useful dev tools ([flake8](https://github.com/PyCQA/flake8), [icecream](https://github.com/gruns/icecream) and [line_profiler](https://github.com/pyutils/line_profiler)) can be installed with `poetry install -E dev`. See the [Managing dependencies](#managing-dependencies) section for adding your own.\n\nA basic module for the command event looks like this:\n```python\nclass Module:\n    \"\"\"\n    # Module specific configuration in yaml.\n    # All optional, valid options are:\n    #  - desc\n    #  - usage\n    #  - min_args (Sends usage if not met)\n    #  - max_args (Sends usage if exceeded)\n    #  - alias\n    #  - cooldown (in seconds)\n    #  - groups (list of groups that can access the command)\n    desc: 'Your command's help text'\n    usage: '\u003carg1\u003e [arg2] [arg3]'\n    min_args: 1\n    max_args: 3\n    \"\"\"\n\n    @staticmethod\n    async def run(bot, namespace, text, args, sender, trip, ulevel):\n```\nIf your module needs to do stuff on load, use `on_load()`:\n```python\nclass Module:\n    ...metadata...\n\n    @staticmethod\n    def on_load(bot, namespace):\n        namespace.mylist = []\n        # Whatever else that needs to be done\n\n    @staticmethod\n    async def run(bot, namespace, text, args, sender, trip, ulevel):\n```\n\nDifferent events take different arguments for `run()`:\n|Events|Arguments|\n|--|--|\n|command, whisper|`bot` `namespace` `text` `args` `sender` `trip` `ulevel`|\n|message|`bot` `namespace` `text` `sender` `trip` `ulevel`|\n|join, leave|`bot` `namespace` `sender` `hash` `trip`|\n\nHere's a breakdown of all the arguments:\n|Argument|Description|\n|--|--|\n|`bot`|Main usv3 instance, see warning below.|\n|`namespace`|Module's namespace.|\n|`text`|Full message text without the command stripped.|\n|`args`|Text trailing the command split into a list of arguments.|\n|`sender`|Sender's nickname.|\n|`hash`|Sender's connection hash.|\n|`trip`|Sender's tripcode.|\n|`ulevel`|Sender's user level. See [hack-chat/main/commands/utility/_UAC.js](https://github.com/hack-chat/main/blob/752d172dd58022f5c65dc8d002ebc9da71949b1d/commands/utility/_UAC.js#L51-L60)|\n\n\u003e [!WARNING]\n\u003e The `bot` object is the main usv3 instance, messing with its attributes can result in crashes. Safe methods you can call from `bot` are `send()`, `reply()` and `whisper()`. These are documented in the next section.\n\nA namespace is created for each module. This can be used as a safe place to store data that needs to be accessed later or shared between different modules. Within the same module, this is available as `namespace`. A different module's namespace can be accessed with `bot.namespaces.\u003cevent\u003e.\u003cname\u003e`.\n\nA few example modules can found in a [separate repository](https://github.com/AnnikaV9/usv3-modules). You can use them as reference when creating your own.\n\nAfter creating a module, place it in its respective event in [usv3/events](../usv3/events). The module will be found and loaded automatically. If your module has any dependencies, add them to [pyproject.toml](../pyproject.toml) under `tool.poetry.group.cmd.dependencies` and run `poetry update`.\n\nFor chat/whisper commands, the name of the module will be the command that calls it. You can add an alias for each one if a shorter alternate command is needed.\n\nThe `reload` command live reloads all loaded modules and any new modules that have been added. Note that this will re-run `on_load()` in all modules that have it. The configuration file [config/extra_config.yml](../config/extra_config.yml) will also be reloaded.\n\n\n## Replying to the server\n`bot.send()` can be used to reply to the server. It's defined in the core framework as:\n```python\nasync def send(self, cmd: str = \"chat\", **kwargs) -\u003e None:\n    await self.ws.send(json.dumps({\"cmd\": cmd, **kwargs}))\n```\nTo send a chat message:\n```python\nawait bot.send(text=\"Hello World!\")\n```\nAn alternate command:\n```python\nawait bot.send(cmd=\"changecolor\", color=\"ff0000\")\n```\nTo reply to users in chat with a consistent format, use `bot.reply()`:\n```python\nawait bot.reply(sender, \"Hello!\")\n```\nA whisper shortcut is also provided:\n```python\nawait bot.whisper(sender, \"Don't tell anyone\")\n```\n\n\n## Useful attributes\nThe `bot` object manages a few useful attributes that can be read from within modules:\n|Attribute|Description|\n|--|--|\n|`online_users`|*List* of online nicknames.|\n|`online_trips`|*Dictionary* of online nicknames and their respective trips.|\n|`online_hashes`|*Dictionary* of online nicknames and their respective connection hashes.|\n\n\u003e [!WARNING]\n\u003e These attributes are meant to be read-only. Modifying them from a module can result in crashes.\n\n\n## Cython modules\nusv3 supports the building and loading of cython modules. Dependencies required for this are not installed by default, they can be with `poetry install -E cython`.  If you don't want dev dependencies to be uninstalled, run `poetry install --all-extras` instead.\n\nAdding a cython module is pretty much the same as adding a pure python module, just drop the pyx file into its respective event. After that, run `poetry run build_cython` to build all cython modules.\n\nTo get a list of modules that will be built without actually building them, pass `--dry-run` to the above command.\n\n\u003e [!NOTE]\n\u003e Unlike pure python modules, cython modules will not reflect changes after rebuilding when using the `reload` command. You will have to restart the bot to load the changes.\n\n\n## Managing dependencies\nusv3 uses [Poetry](https://python-poetry.org/) to manage dependencies.\n\n`poetry install` will install dependencies required by modules and the core framework, removing all extra dependencies. This is what you should run before deploying the bot.\n\nTo add a dependency required by a module, you can do one of the following:\n- Let Poetry handle it by running `poetry add -G cmd \u003cpackage\u003e`.\n- Manually add it to [pyproject.toml](../pyproject.toml) under `tool.poetry.group.cmd.dependencies` and run `poetry update`.\n\nTwo groups of extra dependencies are defined:\n- `dev` for optional tools useful for development and testing. ([flake8](https://github.com/PyCQA/flake8), [icecream](https://github.com/gruns/icecream) and [line_profiler](https://github.com/pyutils/line_profiler))\n- `cython` for dependencies required to build cython modules. ([cython](https://github.com/cython/cython) and [setuptools](https://github.com/pypa/setuptools))\n\nTo install these extra dependencies, run `poetry install --all-extras`.\n\nIf you have more dev tools to use, add them under `tool.poetry.dependencies` in [pyproject.toml](./pyproject.toml) as optional and inside the dev extras list.\n\n\n## Systemd\nIf you want to run usv3 as a systemd service, here's a sample unit file:\n```ini\n# usv3.service\n\n[Unit]\nDescription=usv3\nAfter=network-online.target\n\n[Service]\nExecStart=/path/to/poetry run -n usv3\nExecStartPre=/path/to/poetry check -n --lock\nWorkingDirectory=/home/\u003cuser\u003e/path/to/usv3/directory\nRestart=always\nRestartSec=60\nType=simple\n\n[Install]\nWantedBy=default.target\n```\nEdit to match your setup and place it in `~/.config/systemd/user/`.\n\nRun `systemctl --user daemon-reload` and `systemctl --user enable --now usv3` to start and enable the service.\n\nOnce the service is up, you can run `systemctl --user status usv3` or `journalctl --user -e -u usv3` to view resource usage or logs.\n\n\u003e [!NOTE]\n\u003e If you have issues with usv3 being killed when you log out, enable lingering with `sudo loginctl enable-linger $USER`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fannikav9%2Fusv3-framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fannikav9%2Fusv3-framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fannikav9%2Fusv3-framework/lists"}