Read receipts, story views, typing and online status are held back per the options; read on interact, scheduled and silent sending as in AyuGram. Every option resolves chat -> account -> global; forum topics follow their group. Settings live in the plugin page, a chat/profile menu popup, and a drawer row for the current account. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.9 KiB
Development
Writing your own plugin
- Run
python3 tools/bundle.py --checkonce. It enables the git hooks that auto-bump the version on commit (see Git hooks and versioning). - Edit
plugin.json(id, name, description, etc.). - Write your plugin under
src/, withsrc/main.pyas the entry module (absolute imports only — it's executed at plugin-module top level, not inside a package). python3 tools/bundle.py --release && python3 tools/verify_bundle.py dist/<id>.plugin(substitute youridfromplugin.json).bash scripts/deploy.sh --enablewith a device connected.
Repo layout
plugin.json single source of truth for plugin metadata
src/ the plugin, written as an ordinary Python package
main.py entry module — exactly one BasePlugin subclass, absolute imports only
features.py the ghost mode options and their defaults
prefs.py storage and resolution: chat -> account -> global
network.py request hooks: reads, stories, typing, online status, read on interact
sending.py scheduled and silent sending, forward hook, scheduled-screen guard
menus.py chat/profile/message/drawer menu items, the chat and account dialogs
drawer.py the drawer row for drawer layouts without a Plugins entry
settings_page.py the plugin settings screen and the per-account pages
peers.py accounts, dialog ids and names
hooking.py Xposed and UI-thread helpers
tools/
bundle.py compiles plugin.json + src/ into dist/<id>.plugin
devclient.py speaks the on-device dev-server protocol (127.0.0.1:42690)
verify_bundle.py offline harness that proves a built bundle behaves correctly, no phone needed
release.py publishes a built bundle to a Gitea release (used by CI)
icon_png.py renders images/icon.svg to a square PNG
images/icon.svg the plugin icon, source of truth for any PNG export
.gitea/workflows/ CI that builds, verifies and publishes the .plugin to Releases
scripts/ ADB debug-loop automation and the git hooks
docs/ these notes + sdk-notes.md, the condensed SDK API surface
The three commands that matter
python3 tools/bundle.py --release # compile src/ -> dist/<id>.plugin
python3 tools/verify_bundle.py dist/<id>.plugin # offline proof the bundle works, no device needed
bash scripts/deploy.sh --enable # build (--dev) + push to a connected device + enable + reload
bundle.py walks src/ recursively, embeds every .py file's source and dotted module name
into a compressed, base64-encoded payload, and appends a small runtime preamble that installs
a private import hook (scoped to a per-module __builtins__ dict, never touching
sys.modules) so cross-module and cross-package imports resolve exactly as they would if the
files were still on disk. --dev (the default) embeds absolute local paths so a debugger
resolves breakpoints against your real source files; --release embeds repo-relative paths
for distribution. Both modes produce byte-reproducible output for a given src/ + plugin.json.
Its first run in a clone also enables the repo's git hooks (see
Git hooks and versioning).
Exporting the icon as PNG
tools/icon_png.py renders images/icon.svg to images/icon.png, 512x512 by default.
--resolution sets the size of both sides, so --resolution 1024 gives 1024x1024:
python3 tools/icon_png.py # images/icon.png, 512x512
python3 tools/icon_png.py --resolution 1024 # images/icon.png, 1024x1024
python3 tools/icon_png.py some.svg -o out.png
The output is always PNG; any other -o extension is rejected. The script itself is stdlib
only and hands the rendering to the first renderer it finds: the cairosvg Python package,
rsvg-convert (librsvg), ImageMagick or Inkscape. Install any one of them.