Files
icq/docs/slidgram/main/contributing.html
T
estorozhenko 3c4190402b Telegram bridge: slidgram + SOCKS5 proxy, mod_privilege (XEP-0356), XEP audit
- docker-compose: сервис slidgram (Slidge->Telegram, внешний компонент XEP-0114)
- кастомный образ slidgram-proxy: SOCKS5-патч (SLIDGRAM_PROXY -> Pyrogram) для маршрутизации через VPS01
- prosody: component telegram.nixg.ru (5347), component_secret в секции Component (0.11!),
  mod_privilege + privileged_entities (roster sync мостов), mod_pubsub включён
- modules/mod_privilege.lua (community, hg.prosody.im)
- docs/slidgram/: офлайн-копия документации slidgram (slidge.im)
- README: секции 'Функциональность (XEP)' и 'Мост Telegram'; XEP-AUDIT.md (полный аудит XEP)
- STATUS.md: мост ПОДКЛЮЧЁН, privilege, аудит
2026-08-29 14:38:25 +00:00

437 lines
26 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html class="no-js" lang="en" data-content_root="./">
<head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="color-scheme" content="light dark"><meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="index" title="Index" href="genindex.html"><link rel="search" title="Search" href="search.html"><link rel="prev" title="Features" href="user/features.html">
<!-- Generated with Sphinx 9.1.0 and Furo 2025.12.19 -->
<title>Contributing - slidgram documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=7bdb33bb" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?v=8dab3a3b" />
<style>
body {
--color-code-background: #f2f2f2;
--color-code-foreground: #1e1e1e;
}
@media not print {
body[data-theme="dark"] {
--color-code-background: #202020;
--color-code-foreground: #d0d0d0;
}
@media (prefers-color-scheme: dark) {
body:not([data-theme="light"]) {
--color-code-background: #202020;
--color-code-foreground: #d0d0d0;
}
}
}
</style></head>
<body>
<script>
document.body.dataset.theme = localStorage.getItem("theme") || "auto";
</script>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-toc" viewBox="0 0 24 24">
<title>Contents</title>
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024">
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/>
</svg>
</symbol>
<symbol id="svg-menu" viewBox="0 0 24 24">
<title>Menu</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</symbol>
<symbol id="svg-arrow-right" viewBox="0 0 24 24">
<title>Expand</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
<polyline points="9 18 15 12 9 6"></polyline>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24">
<title>Light mode</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24">
<title>Dark mode</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
</svg>
</symbol>
<symbol id="svg-sun-with-moon" viewBox="0 0 24 24">
<title>Auto light/dark, in light mode</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
class="icon-custom-derived-from-feather-sun-and-tabler-moon">
<path style="opacity: 50%" d="M 5.411 14.504 C 5.471 14.504 5.532 14.504 5.591 14.504 C 3.639 16.319 4.383 19.569 6.931 20.352 C 7.693 20.586 8.512 20.551 9.25 20.252 C 8.023 23.207 4.056 23.725 2.11 21.184 C 0.166 18.642 1.702 14.949 4.874 14.536 C 5.051 14.512 5.231 14.5 5.411 14.5 L 5.411 14.504 Z"/>
<line x1="14.5" y1="3.25" x2="14.5" y2="1.25"/>
<line x1="14.5" y1="15.85" x2="14.5" y2="17.85"/>
<line x1="10.044" y1="5.094" x2="8.63" y2="3.68"/>
<line x1="19" y1="14.05" x2="20.414" y2="15.464"/>
<line x1="8.2" y1="9.55" x2="6.2" y2="9.55"/>
<line x1="20.8" y1="9.55" x2="22.8" y2="9.55"/>
<line x1="10.044" y1="14.006" x2="8.63" y2="15.42"/>
<line x1="19" y1="5.05" x2="20.414" y2="3.636"/>
<circle cx="14.5" cy="9.55" r="3.6"/>
</svg>
</symbol>
<symbol id="svg-moon-with-sun" viewBox="0 0 24 24">
<title>Auto light/dark, in dark mode</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
class="icon-custom-derived-from-feather-sun-and-tabler-moon">
<path d="M 8.282 7.007 C 8.385 7.007 8.494 7.007 8.595 7.007 C 5.18 10.184 6.481 15.869 10.942 17.24 C 12.275 17.648 13.706 17.589 15 17.066 C 12.851 22.236 5.91 23.143 2.505 18.696 C -0.897 14.249 1.791 7.786 7.342 7.063 C 7.652 7.021 7.965 7 8.282 7 L 8.282 7.007 Z"/>
<line style="opacity: 50%" x1="18" y1="3.705" x2="18" y2="2.5"/>
<line style="opacity: 50%" x1="18" y1="11.295" x2="18" y2="12.5"/>
<line style="opacity: 50%" x1="15.316" y1="4.816" x2="14.464" y2="3.964"/>
<line style="opacity: 50%" x1="20.711" y1="10.212" x2="21.563" y2="11.063"/>
<line style="opacity: 50%" x1="14.205" y1="7.5" x2="13.001" y2="7.5"/>
<line style="opacity: 50%" x1="21.795" y1="7.5" x2="23" y2="7.5"/>
<line style="opacity: 50%" x1="15.316" y1="10.184" x2="14.464" y2="11.036"/>
<line style="opacity: 50%" x1="20.711" y1="4.789" x2="21.563" y2="3.937"/>
<circle style="opacity: 50%" cx="18" cy="7.5" r="2.169"/>
</svg>
</symbol>
<symbol id="svg-pencil" viewBox="0 0 24 24">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-pencil-code">
<path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" />
<path d="M13.5 6.5l4 4" />
<path d="M20 21l2 -2l-2 -2" />
<path d="M17 17l-2 2l2 2" />
</svg>
</symbol>
<symbol id="svg-eye" viewBox="0 0 24 24">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-eye-code">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
<path
d="M11.11 17.958c-3.209 -.307 -5.91 -2.293 -8.11 -5.958c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6c-.21 .352 -.427 .688 -.647 1.008" />
<path d="M20 21l2 -2l-2 -2" />
<path d="M17 17l-2 2l2 2" />
</svg>
</symbol>
</svg>
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation" aria-label="Toggle site navigation sidebar">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc" aria-label="Toggle table of contents sidebar">
<label class="overlay sidebar-overlay" for="__navigation"></label>
<label class="overlay toc-overlay" for="__toc"></label>
<a class="skip-to-content muted-link" href="#furo-main-content">Skip to content</a>
<div class="page">
<header class="mobile-header">
<div class="header-left">
<label class="nav-overlay-icon" for="__navigation">
<span class="icon"><svg><use href="#svg-menu"></use></svg></span>
</label>
</div>
<div class="header-center">
<a href="index.html"><div class="brand">slidgram documentation</div></a>
</div>
<div class="header-right">
<div class="theme-toggle-container theme-toggle-header">
<button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
<svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
<svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
</button>
</div>
<label class="toc-overlay-icon toc-header-icon" for="__toc">
<span class="icon"><svg><use href="#svg-toc"></use></svg></span>
</label>
</div>
</header>
<aside class="sidebar-drawer">
<div class="sidebar-container">
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
<span class="sidebar-brand-text">slidgram documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
<input type="hidden" name="check_keywords" value="yes">
<input type="hidden" name="area" value="default">
</form>
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
<ul class="current">
<li class="toctree-l1 has-children"><a class="reference internal" href="admin/index.html">For admins</a><input aria-label="Toggle navigation of For admins" class="toctree-checkbox" id="toctree-checkbox-1" name="toctree-checkbox-1" role="switch" type="checkbox"/><label for="toctree-checkbox-1"><span class="icon"><svg><use href="#svg-arrow-right"></use></svg></span></label><ul>
<li class="toctree-l2"><a class="reference internal" href="admin/install.html">Installation</a></li>
<li class="toctree-l2"><a class="reference internal" href="admin/quickstart.html">Quick start</a></li>
<li class="toctree-l2"><a class="reference internal" href="admin/attachments.html">Attachments</a></li>
<li class="toctree-l2"><a class="reference internal" href="admin/privileges.html">Privileges</a></li>
<li class="toctree-l2"><a class="reference internal" href="admin/config.html">Configuration</a></li>
<li class="toctree-l2"><a class="reference internal" href="admin/examples/index.html">XMPP server configs examples</a></li>
</ul>
</li>
<li class="toctree-l1 has-children"><a class="reference internal" href="user/index.html">For users</a><input aria-label="Toggle navigation of For users" class="toctree-checkbox" id="toctree-checkbox-2" name="toctree-checkbox-2" role="switch" type="checkbox"/><label for="toctree-checkbox-2"><span class="icon"><svg><use href="#svg-arrow-right"></use></svg></span></label><ul>
<li class="toctree-l2"><a class="reference internal" href="user/registration.html">Registration</a></li>
<li class="toctree-l2"><a class="reference internal" href="user/usage.html">Usage</a></li>
<li class="toctree-l2"><a class="reference internal" href="user/features.html">Features</a></li>
</ul>
</li>
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Contributing</a></li>
</ul>
</div>
</div>
</div>
</div>
</aside>
<div class="main">
<div class="content">
<div class="article-container">
<a href="#" class="back-to-top muted-link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path>
</svg>
<span>Back to top</span>
</a>
<div class="content-icon-container">
<div class="view-this-page">
<a class="muted-link" href="https://codeberg.org/slidge/slidgram/src/branch/main/docs/source/contributing.rst" title="View this page">
<svg><use href="#svg-eye"></use></svg>
<span class="visually-hidden">View this page</span>
</a>
</div><div class="edit-this-page">
<a class="muted-link" href="https://codeberg.org/slidge/slidgram/_edit/main/docs/source/contributing.rst" rel="edit" title="Edit this page">
<svg><use href="#svg-pencil"></use></svg>
<span class="visually-hidden">Edit this page</span>
</a>
</div><div class="theme-toggle-container theme-toggle-content">
<button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
<svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
<svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
</button>
</div>
<label class="toc-overlay-icon toc-content-icon" for="__toc">
<span class="icon"><svg><use href="#svg-toc"></use></svg></span>
</label>
</div>
<article role="main" id="furo-main-content">
<section id="contributing">
<h1>Contributing<a class="headerlink" href="#contributing" title="Link to this heading"></a></h1>
<p>We are really happy to welcome new contributors to slidgram!
Before starting anything, please join <a class="reference external" href="xmpp:dev&#64;rooms.slidge.im?join">our chat room</a>
to say hi and see if anyone is already working on the bug you want to fix or
the feature you want to implement.</p>
<section id="quickstart">
<h2>Quickstart<a class="headerlink" href="#quickstart" title="Link to this heading"></a></h2>
<p>To start hacking on slidgram, you need to:</p>
<ol class="arabic simple">
<li><p>Clone the repository: <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">clone</span> <span class="pre">https://codeberg.org/slidge/slidgram</span></code>.</p></li>
<li><p>Install the required dependencies. (see below)</p></li>
<li><p>Spin up a development XMPP server for slidgram to connect to. (see below)</p></li>
</ol>
<section id="easy-mode-docker-compose">
<h3>Easy mode: docker-compose<a class="headerlink" href="#easy-mode-docker-compose" title="Link to this heading"></a></h3>
<p>The easiest way to achieve 2 and 3 at the same time is to use the provided
<code class="docutils literal notranslate"><span class="pre">docker-compose.yml</span></code> file. Run <code class="docutils literal notranslate"><span class="pre">docker</span> <span class="pre">compose</span> <span class="pre">up</span></code> (or <code class="docutils literal notranslate"><span class="pre">podman-compose</span> <span class="pre">up</span></code>)
in the directory of the repository you just cloned. It will:</p>
<ul class="simple">
<li><p>spin up a <a class="reference external" href="https://prosody.im">prosody</a> instance configured for development;</p></li>
<li><p>launch slidgram in a dedicated container, with hot code reload.</p></li>
</ul>
<p>You will then be able to connect to that prosody using any XMPP client, using
“<a class="reference external" href="mailto:test&#37;&#52;&#48;localhost">test<span>&#64;</span>localhost</a>” as JID and “password” as password. We recommended
<a class="reference external" href="https://gajim.org">gajim</a> which lets you start a different profile than your
main profile: <code class="docutils literal notranslate"><span class="pre">gajim</span> <span class="pre">-p</span> <span class="pre">slidge</span> <span class="pre">-c</span> <span class="pre">~/.local/share/gajim-slidge</span></code>.</p>
<p>To avoid having to accept self-signed certificates, you can add prosody’s
certificate to your local store. In debian, you can do that with:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="c1"># download the certificate</span>
curl<span class="w"> </span>https://codeberg.org/slidge/prosody-dev-container/raw/branch/main/localhost.crt<span class="w"> </span><span class="p">|</span><span class="w"> </span>sudo<span class="w"> </span>tee<span class="w"> </span>/usr/local/share/ca-certificates/localhost.crt
<span class="c1"># set the right perms</span>
sudo<span class="w"> </span>chmod<span class="w"> </span><span class="m">600</span><span class="w"> </span>/usr/local/share/ca-certificates/localhost.crt
<span class="c1"># import it</span>
sudo<span class="w"> </span>update-ca-certificates
</pre></div>
</div>
</section>
<section id="slightly-harder-mode-setting-up-a-virtualenv">
<h3>Slightly harder mode: setting up a virtualenv<a class="headerlink" href="#slightly-harder-mode-setting-up-a-virtualenv" title="Link to this heading"></a></h3>
<p>In some situations, developing in containers is not optimal, for instance if
you want to attach an interactive debugger to the slidgram process.</p>
<p>slidgram defines its dependencies in a <a class="reference external" href="https://peps.python.org/pep-0517/">PEP 517</a>-compliant
<code class="docutils literal notranslate"><span class="pre">pyproject.toml</span></code> file. This means that you can use different tools to set up a
virtualenv with the appropriate dependencies.</p>
<p>We recommend using <a class="reference external" href="https://docs.astral.sh/uv/">uv</a> which is fast and has some
nice features. By running <code class="docutils literal notranslate"><span class="pre">uv</span> <span class="pre">sync</span> <span class="pre">--frozen</span> <span class="pre">--all-groups</span> <span class="pre">--all-extras</span></code>, a
standard virtualenv will be installed in <code class="docutils literal notranslate"><span class="pre">./.venv</span></code>. You can then activate it
with <code class="docutils literal notranslate"><span class="pre">source</span> <span class="pre">.venv/bin/activate</span></code> and launch <code class="docutils literal notranslate"><span class="pre">slidgram</span> <span class="pre">--help</span></code>.</p>
<p>NB: you will need to set up a local XMPP server. An easy way to do that is to
use the <code class="docutils literal notranslate"><span class="pre">slidge-prosody-dev</span></code> container: <code class="docutils literal notranslate"><span class="pre">docker</span> <span class="pre">run</span> <span class="pre">--network</span> <span class="pre">host</span> <span class="pre">codeberg.org/slidge/prosody-slidge-dev</span></code>.
With it you will be able to launch slidgram with
<code class="docutils literal notranslate"><span class="pre">slidgram</span> <span class="pre">--jid</span> <span class="pre">slidge.localhost</span> <span class="pre">--secret</span> <span class="pre">secret</span> <span class="pre">--debug</span> <span class="pre">--home-dir</span> <span class="pre">./persistent</span></code>.</p>
</section>
<section id="hacking-on-slidge-core-simultaneously">
<h3>Hacking on slidge core simultaneously<a class="headerlink" href="#hacking-on-slidge-core-simultaneously" title="Link to this heading"></a></h3>
<p>Maybe you will discover that what you want to change, add or fix is not part
of slidgram but part of slidge core. To modify slidge core, first you
need to clone <a class="reference external" href="https://codeberg.org/slidge/slidge">the slidge repo</a> somewhere
on your computer.</p>
<p>Let’s assume you cloned <code class="docutils literal notranslate"><span class="pre">slidge</span></code> in the same root dir as <code class="docutils literal notranslate"><span class="pre">slidgram</span></code>,
e.g., <code class="docutils literal notranslate"><span class="pre">~/src/slidgram</span></code> and <code class="docutils literal notranslate"><span class="pre">~/src/slidge</span></code>.
With the <code class="docutils literal notranslate"><span class="pre">docker-compose</span></code>-based dev setup, you will need to add an additional
mount for the slidge dir, e.g., <code class="docutils literal notranslate"><span class="pre">../slidge:/build/slidge</span></code>. If you opted for
the virtualenv solution, you can install slidge in your virtualenv in editable
mode with <code class="docutils literal notranslate"><span class="pre">[uv]</span> <span class="pre">pip</span> <span class="pre">install</span> <span class="pre">-e</span> <span class="pre">../slidge</span></code>.</p>
</section>
</section>
<section id="guidelines">
<h2>Guidelines<a class="headerlink" href="#guidelines" title="Link to this heading"></a></h2>
<p>slidgram uses these tools to ensure some level of code quality:</p>
<ul class="simple">
<li><p><a class="reference external" href="https://www.mypy-lang.org/">mypy</a>
for static type checking,</p></li>
<li><p><a class="reference external" href="https://docs.astral.sh/ruff/">ruff</a>
to detect common python mistakes and enforce a consistent style,</p></li>
<li><p><a class="reference external" href="https://docs.pytest.org/en/stable/">pytest</a>
for automated tests.</p></li>
</ul>
<p>Commit messages should be in the form of
<a class="reference external" href="https://www.conventionalcommits.org/en/v1.0.0/">conventional commits</a>, with
some additional types defined in <a class="reference external" href="https://codeberg.org/slidge/slidgram/src/branch/main/commitlint.config.js">./commitlinx.config.js</a>.
This makes it possible to automatically generate changelogs on releases, it
is worth it! We use <a class="reference external" href="https://git-cliff.org/">git-cliff</a> for this. You don’t have
to install git-cliff locally, the magic happens in CI.</p>
<p>We recommended setting up <a class="reference external" href="https://pre-commit.com/">pre-commit</a> to ensure that
these pass for each commit: <code class="docutils literal notranslate"><span class="pre">pre-commit</span> <span class="pre">install</span> <span class="pre">&amp;&amp;</span> <span class="pre">pre-commit</span> <span class="pre">install</span> <span class="pre">--hook-type</span> <span class="pre">commit-msg</span></code>.</p>
<p>Make a new git branch, commit your changes, push it to your fork and open a
pull request!</p>
<p>NB: we also accept contributions without pull requests. Just push your changes
somewhere and tell us where to pull via the group chat.</p>
</section>
</section>
</article>
</div>
<footer>
<div class="related-pages">
<a class="prev-page" href="user/features.html">
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
<div class="page-info">
<div class="context">
<span>Previous</span>
</div>
<div class="title">Features</div>
</div>
</a>
</div>
<div class="bottom-of-page">
<div class="left-details">
<div class="copyright">
Copyright &#169; 2026, the slidgram contributors
</div>
Made with <a href="https://www.sphinx-doc.org/">Sphinx</a> and <a class="muted-link" href="https://pradyunsg.me">@pradyunsg</a>'s
<a href="https://github.com/pradyunsg/furo">Furo</a>
</div>
<div class="right-details">
<div class="icons">
<a class="muted-link " href="https://codeberg.org/slidge/slidgram" aria-label="Codeberg"><svg xmlns="http://www.w3.org/2000/svg"
aria-label="Codeberg" role="img"
viewBox="55 65 400 390">
<defs>
<linearGradient id="A" x1="259.804" x2="383.132" y1="161.4" y2="407.835" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#ffffff" stop-opacity="0"/>
<stop offset=".5" stop-color="#71c2ff"/>
<stop offset="1" stop-color="#39aaff"/>
</linearGradient>
</defs>
<path fill="url(#A)"
d="M259.804 161.4c-.44 0-1.1 0-1.32.44l-.44 1.1L332.04 440.21a192.039 192.039 0 0 0 86.77-74.437L261.125 162.06a1.762 1.762 0 0 0-1.321-.661z"
opacity=".5" paint-order="stroke markers fill"/>
<path fill="#2185d0"
d="M255.3 71.8a192 192 0 0 0-162 294l160.1-207c.5-.6 1.5-1 2.6-1s2 .4 2.6 1l160 207a192 192 0 0 0 29.4-102c0-106-86-192-192-192a192 192 0 0 0-.7 0z"
paint-order="stroke markers fill"/>
</svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<aside class="toc-drawer">
<div class="toc-sticky toc-scroll">
<div class="toc-title-container">
<span class="toc-title">
On this page
</span>
</div>
<div class="toc-tree-container">
<div class="toc-tree">
<ul>
<li><a class="reference internal" href="#">Contributing</a><ul>
<li><a class="reference internal" href="#quickstart">Quickstart</a><ul>
<li><a class="reference internal" href="#easy-mode-docker-compose">Easy mode: docker-compose</a></li>
<li><a class="reference internal" href="#slightly-harder-mode-setting-up-a-virtualenv">Slightly harder mode: setting up a virtualenv</a></li>
<li><a class="reference internal" href="#hacking-on-slidge-core-simultaneously">Hacking on slidge core simultaneously</a></li>
</ul>
</li>
<li><a class="reference internal" href="#guidelines">Guidelines</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</aside>
</div>
</div><script src="_static/documentation_options.js?v=5929fcd5"></script>
<script src="_static/doctools.js?v=fd6eb6e6"></script>
<script src="_static/sphinx_highlight.js?v=6ffebe34"></script>
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
</body>
</html>