## 1. Project Overview & Quickstart (giampaolo/psutil)

## File: docs/DEVGUIDE.rst

Development guide
=================

.. seealso:: `Contributing to psutil project <https://github.com/giampaolo/psutil/blob/master/CONTRIBUTING.md>`_

Build, setup and test
---------------------

- psutil makes extensive use of C code, so a C compiler and the Python
  development headers are required. First clone the repository:

  .. code-block:: bash

     git clone https://github.com/giampaolo/psutil.git
     cd psutil

  On Linux, FreeBSD, OpenBSD, NetBSD and Solaris, install the system deps:

  .. code-block:: bash

     make install-sysdeps       # compiler + python headers
     make install-sysdeps-test  # CLI tools used by tests

  On macOS, AIX and Windows there's no such target, see
  :ref:`install_from_source`. Then, everywhere:

  .. code-block:: bash

     make install-pydeps-dev    # python development deps (linters, etc)
     make build                 # compile the C extension in place
     make test

- ``make`` (via the :src:`Makefile`) is used for building, testing and general
  development tasks, including on Windows (see below):

  .. code-block:: bash

     make clean
     make test
     make test-parallel
     make test-memleaks
     make coverage
     make lint-all
     make fix-all
     make uninstall
     make help

- To run a specific test:

  .. code-block:: none

     make test ARGS=tests/test_system.py

- ``make build`` compiles the extension in place, so you can import psutil
  straight from the repo. No need to install it.

- Don't use ``sudo``, except for the ``install-sysdeps-*`` targets, which
  invoke it themselves when needed.

- To target a specific Python version, pass ``PYTHON`` to every step, so that
  the extension is built by the same interpreter that runs the tests:

  .. code-block:: none

     make install-pydeps-dev PYTHON=python3.13
     make build PYTHON=python3.13
     make test PYTHON=python3.13

Windows
-------

- The recommended way to develop on Windows is to use ``make``.
- For the build tools, Git Bash and GNU Make setup see :ref:`install_windows`.
- Once inside a Git Bash shell, run:

  .. code-block:: bash

     make install-pydeps-dev
     make build
     make test-parallel

.. _devguide_debug_mode:

Debug mode
----------

If you need to debug unusual situations or report a bug, you can enable debug
mode via the :envvar:`PSUTIL_DEBUG` environment variable. In this mode, psutil
may print additional information to stderr. Usually these are non-severe error
conditions that are ignored instead of causing a crash. Unit tests
automatically run with debug mode enabled. To enable debug mode in UNIX (or on
Windows + Bash):

.. code-block:: none

  $ PSUTIL_DEBUG=1 python3 test_script.py
  psutil-debug [psutil/_psutil_linux.c:150]> setmntent() failed (ignored)

On Windows using cmd.exe:

.. code-block:: none

  set PSUTIL_DEBUG=1 && python.exe test_script.py
  psutil-debug [psutil/arch/windows/proc.c:56]> ReadProcessMemory -> ERROR_NOACCESS (ignored)

Coding style
------------

All style and formatting checks are enforced locally on each ``git commit`` and
via a GitHub Actions pipeline.

- Python: follows `PEP-8`_, formatted and linted with ``black`` and ``ruff``.
- C: generally follows `PEP-7`_, formatted with ``clang-format``.
- Other files (``.rst``, ``.toml``, ``.md``, ``.yml``): validated by linters.

The pipeline re-runs all checks for consistency (``make lint-all``).

Run ``make fix-all`` before committing; it usually fixes Python issues (via
``black`` and ``ruff``) and C issues (via ``clang-format``).

Code organization
-----------------

Not every API reaches C: many are implemented in python alone (on Linux, by
parsing ``/proc``). For those that do, a call travels down through the
platform-specific layers. Linux is used here as an example:

.. code-block:: none

   import psutil
        │
        ▼
   psutil/__init__.py          public API, Process class
        │
        ▼
   psutil/_pslinux.py          python layer: parses /proc, calls into C
        │
        ▼
   psutil/_psutil_linux.c      C extension entry point (arg parsing)
        │
        ▼
   psutil/arch/linux/*.c       platform-specific C implementation
                               + arch/posix/*.c   shared by POSIX
                               + arch/all/*.c     shared by everything

Where things live:

.. code-block:: bash

   psutil/__init__.py                   # Public API ("import psutil")
   psutil/_common.py                    # Generic utilities
   psutil/_ntuples.py                   # Named tuples returned by psutil APIs
   psutil/_enums.py                     # Enum containers
   psutil/_ps{platform}.py              # OS-specific python wrapper
   psutil/_psutil_{platform}.c          # OS-specific C extension (entry point)
   psutil/arch/all/*.c                  # C code common to all OSes
   psutil/arch/posix/*.c                # C code common to POSIX OSes
   psutil/arch/bsd/*.c                  # C code common to the BSDs
   psutil/arch/{platform}/*.c           # OS-specific C implementation
   tests/test_process.py                # Main process API tests
   tests/test_system.py                 # Main system API tests
   tests/test_{platform}.py             # OS-specific tests

Adding a new API
----------------

- Define the public API in :src:`psutil/__init__.py`.
- Implement it for each applicable platform in ``psutil/_ps{platform}.py``
  (e.g. :src:`psutil/_pslinux.py`).
- If needed, add C code in ``psutil/arch/{platform}/file.c``.
- Add a generic test in :src:`tests/test_system.py` or
  :src:`tests/test_process.py`.
- Add a platform-specific test in ``tests/test_{platform}.py``.
- Update :src:`docs/api.rst`.
- Open a pull request.

Make a pull request
-------------------

- Fork psutil on GitHub.
- Clone your fork: ``git clone git@github.com:YOUR-USERNAME/psutil.git``
- Create a branch: ``git checkout -b new-feature``
- Stage and commit: ``git add <files>`` then
  ``git commit -m 'Add some feature'``
- Push: ``git push origin new-feature``
- Open a pull request (see :src:`CONTRIBUTING.md`).

Continuous integration
----------------------

Tests run automatically on pull requests and on relevant pushes, covering all
regularly tested platforms except AIX. See
`.github/workflows <https://github.com/giampaolo/psutil/tree/master/.github/workflows>`_.

Documentation
-------------

- Source is in the :src:`docs/ <docs/>` directory.
- To build HTML:

  .. code-block:: bash

     make install-pydeps-docs
     cd docs/
     make html

- The documentation is hosted at https://psutil.io. It's a single version,
  rebuilt and deployed automatically on every push to ``master``.

Releases
--------

For project maintainers:

- Releases are uploaded to `PyPI`_ via ``make release``.
- Git tags use the ``vX.Y.Z`` format (e.g. ``v7.2.2``).
- The version string is defined in :src:`psutil/__init__.py` (``__version__``).

.. _`PEP-7`: https://www.python.org/dev/peps/pep-0007/
.. _`PEP-8`: https://www.python.org/dev/peps/pep-0008/
.. _`PyPI`: https://pypi.org/project/psutil/

---

## File: docs/index.rst

.. module:: psutil
   :synopsis: psutil module
.. moduleauthor:: Giampaolo Rodola <grodola@gmail.com>
.. title:: Home

.. ============================================================================
.. Hero
.. ============================================================================

.. raw:: html

   <script>document.body.classList.add('home-page');</script>

   
     <h1 class="hero-title">psutil</h1>
     Process and System Utilities for Python
   

.. container:: home-intro

   Psutil is a cross-platform library for retrieving information about running
   processes and system utilization in Python. It is useful mainly for system
   monitoring, profiling, limiting process resources, and managing running
   processes. Psutil implements many functionalities offered by UNIX command
   line tool such as *ps, top, free, iotop, netstat, ifconfig, lsof* and
   others.

.. ============================================================================
.. Install one-liner
.. ============================================================================

.. raw:: html

   
     $
     <code class="home-install-cmd">pip install psutil</code>
     
       <svg class="home-install-icon-copy" viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">
         <rect x="4" y="4" width="9" height="9" rx="1.2"></rect>
         
       </svg>
       <svg class="home-install-icon-check" viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
         
       </svg>
     
     Copied
   

.. ============================================================================
.. Platform pills
.. ============================================================================

.. raw:: html

   
     <a class="home-platforms-label" href="platform/">Runs on</a>
     
       <a class="home-platform-pill" href="platform/">Linux</a>
       <a class="home-platform-pill" href="platform/">Windows</a>
       <a class="home-platform-pill" href="platform/">macOS</a>
       <a class="home-platform-pill" href="platform/">FreeBSD</a>
       <a class="home-platform-pill" href="platform/">OpenBSD</a>
       <a class="home-platform-pill" href="platform/">NetBSD</a>
       <a class="home-platform-pill" href="platform/">Solaris</a>
       <a class="home-platform-pill" href="platform/">AIX</a>
     
   

.. ============================================================================
.. Feature cards
.. ============================================================================

.. raw:: html

   Explore the API
   
     <a class="home-feature-card" href="api/#cpu">
       
       CPU
     </a>
     <a class="home-feature-card" href="api/#memory">
       
       Memory
     </a>
     <a class="home-feature-card" href="api/#disks">
       
       Disks
     </a>
     <a class="home-feature-card" href="api/#network">
       
       Network
     </a>
     <a class="home-feature-card" href="api/#sensors">
       
       Sensors
     </a>
     <a class="home-feature-card" href="api/#processes">
       
       Processes
     </a>
   

.. ============================================================================
.. Quickstart code preview (tabs by category)
.. ============================================================================

.. raw:: html

   Try it

.. container:: home-quickstart

   .. tab-set::

      .. tab-item:: CPU

         .. code-block:: pycon

            >>> import psutil
            >>> psutil.cpu_times()
            scputimes(user=3961.46, nice=169.72, system=2150.65, idle=16900.54, iowait=629.59, ...)
            >>> psutil.cpu_percent(interval=1)
            4.0
            >>> psutil.cpu_count(logical=False)
            2
            >>> psutil.cpu_freq()
            scpufreq(current=931.42, min=800.0, max=3500.0)

         .. container:: home-tab-more

            :ref:`See more → <api-overview-cpu>`

      .. tab-item:: Memory

         .. code-block:: pycon

            >>> import psutil
            >>> psutil.virtual_memory()
            svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, ...)
            >>> psutil.swap_memory()
            sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)

         .. container:: home-tab-more

            :ref:`See more → <api-overview-memory>`

      .. tab-item:: Disks

         .. code-block:: pycon

            >>> import psutil
            >>> psutil.disk_partitions()
            [sdiskpart(device='/dev/sda1', mountpoint='/',     fstype='ext4', opts='rw,nosuid'),
             sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext4', opts='rw')]
            >>> psutil.disk_usage('/')
            sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
            >>> psutil.disk_io_counters()
            sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220, write_bytes=24081764, ...)

         .. container:: home-tab-more

            :ref:`See more → <api-overview-disks>`

      .. tab-item:: Network

         .. code-block:: pycon

            >>> import psutil
            >>> psutil.net_io_counters(pernic=True)
            {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, ...),
             'lo':   netio(bytes_sent=2838627,   bytes_recv=2838627,   ...)}
            >>> psutil.net_connections(kind='tcp')
            [sconn(family=2, type=1, laddr=addr('10.0.0.1', 48776), raddr=addr('93.186.135.91', 80), status='ESTABLISHED', pid=1254), ...]
            >>> psutil.net_if_addrs()['wlan0']
            [snicaddr(family=2,  address='192.168.1.3', netmask='255.255.255.0', ...), ...]
            >>> psutil.net_if_stats()['wlan0']
            snicstats(isup=True, duplex=2, speed=100, mtu=1500, flags='up,broadcast,running')

         .. container:: home-tab-more

            :ref:`See more → <api-overview-network>`

      .. tab-item:: Sensors

         .. code-block:: pycon

            >>> import psutil
            >>> psutil.sensors_temperatures()
            {'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
                          shwtemp(label='Core 0',        current=45.0, high=100.0, critical=100.0)],
             'acpitz':   [shwtemp(label='',              current=47.0, high=103.0, critical=103.0)]}
            >>> psutil.sensors_fans()
            {'asus': [sfan(label='cpu_fan', current=3200)]}
            >>> psutil.sensors_battery()
            sbattery(percent=93, secsleft=16628, power_plugged=False)

         .. container:: home-tab-more

            :ref:`See more → <api-overview-sensors>`

      .. tab-item:: Processes

         .. code-block:: pycon

            >>> import psutil
            >>> p = psutil.Process(7055)
            >>> p.name(), p.exe(), p.cmdline()
            ('python3', '/usr/bin/python3', ['/usr/bin/python3', 'main.py'])
            >>> p.status()
            
            >>> p.cpu_percent(interval=1.0)
            12.1
            >>> p.memory_info()
            pmem(rss=3164160, vms=4410163, shared=897433, text=302694, data=2422374)
            >>> p.parent(), p.children(recursive=True)
            (psutil.Process(pid=4699, name='bash'), [psutil.Process(pid=29835, name='python3'), ...])

         .. container:: home-tab-more

            :ref:`See more → <api-overview-processes>`

.. ============================================================================
.. Adoption stats. Numbers kept in sync with adoption.rst and README.rst
.. by scripts/internal/docs/refresh_adoption_stats.py.
.. ============================================================================

.. raw:: html

   Stats
   
     <a class="home-stat" href="https://clickpy.clickhouse.com/dashboard/psutil">
       390+ million
       downloads per month
     </a>
     <a class="home-stat" href="https://github.com/giampaolo/psutil/network/dependents">
       780,000+
       GitHub repositories
     </a>
     <a class="home-stat" href="timeline/">
       {{years_in_development}} years
       in active development
     </a>
   

.. ============================================================================
.. Sponsors
.. ============================================================================

.. raw:: html

   
     Sponsors

.. raw:: html
   :file: _sponsors.html

.. raw:: html

   

.. ============================================================================
.. TOC: hidden via CSS, needed by Sphinx for sidebar nav
.. ============================================================================

.. toctree::
   :maxdepth: 2
   :caption: Documentation

   Install 
   API overview <api-overview>
   API Reference <api>
   FAQ <faq>
   Performance 
   Recipes <recipes>

.. toctree::
   :maxdepth: 2
   :caption: Reference

   Shell equivalents <shell-equivalents>
   Stdlib equivalents <stdlib-equivalents>
   Glossary <glossary>
   Platform support 
   Migration <migration>

.. toctree::
   :maxdepth: 2
   :caption: About

   Who uses psutil <adoption>
   Alternatives <alternatives>
   Funding <funding>
   Credits <credits>

.. toctree::
   :maxdepth: 2
   :titlesonly:
   :caption: Project

   Blog 
   Changelog <changelog>
   Timeline <timeline>
   Development guide <devguide>
   General Index <genindex>

---

## File: README.rst

.. 

.. raw:: html

    

    

    

    

.. 

About
=====

psutil is a cross-platform library for retrieving information about running
**processes** and **system utilization** (CPU, memory, disks, network, sensors)
in Python. It is useful mainly for **system monitoring**, **profiling**,
**limiting process resources**, and **managing running processes**. It
implements many functionalities offered by UNIX command line tool such as
*ps, top, free, iotop, netstat, ifconfig, lsof* and others (see
`shell equivalents`_). Psutil supports the following platforms:

- **Linux**
- **Windows**
- **macOS**
- **FreeBSD, OpenBSD**, **NetBSD**
- **Sun Solaris**
- **AIX**

Adoption
========

psutil is among the
`top 100 <https://clickpy.clickhouse.com/dashboard/psutil>`__ most-downloaded
packages on PyPI, with **390+ million** downloads per month and **780,000+**
`GitHub repositories <https://github.com/giampaolo/psutil/network/dependents>`__
using it. See also `adoptions <https://psutil.io/adoption/>`__ and
`alternatives <https://psutil.io/alternatives/>`__.

Install
=======

.. code-block::

    pip install psutil

For platform-specific details see `installation <https://psutil.io/install/>`_.

Documentation
=============

psutil documentation is available at https://psutil.io.

.. 

Sponsors
========

.. raw:: html

    

| [](https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme) | [](https://sansec.io/) | [](https://www.apivoid.com/) |
| --- | --- | --- |



    <sup>[add your logo](https://psutil.io/funding/)</sup>

.. 

Example usages
==============

For the full API with more examples, see the
`API overview <https://psutil.io/api-overview/>`_ and
`API reference <https://psutil.io/api/>`_.

**CPU**

.. code-block:: python

    >>> import psutil
    >>> psutil.cpu_percent(interval=1, percpu=True)
    [4.0, 6.9, 3.7, 9.2]
    >>> psutil.cpu_count(logical=False)
    2
    >>> psutil.cpu_freq()
    scpufreq(current=931.42, min=800.0, max=3500.0)

**Memory**

.. code-block:: python

    >>> psutil.virtual_memory()
    svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, ...)
    >>> psutil.swap_memory()
    sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)

**Disks**

.. code-block:: python

    >>> psutil.disk_partitions()
    [sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
     sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext', opts='rw')]
    >>> psutil.disk_usage('/')
    sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)

**Network**

.. code-block:: python

    >>> psutil.net_io_counters(pernic=True)
    {'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, ...),
     'lo': netio(bytes_sent=2838627, bytes_recv=2838627, ...)}
    >>> psutil.net_connections(kind='tcp')
    [sconn(fd=115, family=2, type=1, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
     ...]

**Sensors**

.. code-block:: python

    >>> psutil.sensors_temperatures()
    {'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
                  shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0)]}
    >>> psutil.sensors_battery()
    sbattery(percent=93, secsleft=16628, power_plugged=False)

**Processes**

.. code-block:: python

    >>> p = psutil.Process(7055)
    >>> p.name()
    'python3'
    >>> p.exe()
    '/usr/bin/python3'
    >>> p.cpu_percent(interval=1.0)
    12.1
    >>> p.memory_info()
    pmem(rss=3164160, vms=4410163, shared=897433, text=302694, data=2422374)
    >>> p.net_connections(kind='tcp')
    [pconn(fd=115, family=2, type=1, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED')]
    >>> p.open_files()
    [popenfile(path='/home/giampaolo/monit.py', fd=3, position=0, mode='r', flags=32768)]
    >>>
    >>> for p in psutil.process_iter(['pid', 'name']):
    ...     print(p.pid, p.name())
    ...
    1 systemd
    2 kthreadd
    3 ksoftirqd/0
    ...

.. _`shell equivalents`: https://psutil.io/shell-equivalents/

.. 

License
=======

BSD-3

---

## File: docs/README.md

# psutil documentation

This directory is a self-contained Sphinx project that builds the psutil docs
published at https://psutil.io/. It has grown well past a plain API reference
(custom theme, a blog, social cards, its own test suite and deploy pipeline),
so this file is the map.

## Build & preview

    make html          # one-off build into _build/html
    make autoreload    # live-reload server at 127.0.0.1:8000

`make html` turns warnings into errors, same as CI.

## Layout

- `*.rst`: the doc sources. `api.rst` is the hand-written API reference;
  `index.rst` is the home page.
- `blog/`: blog posts, managed by the ablog extension + comments provided via
  giscus.
- `conf.py`: Sphinx config: extensions, the theme, `html_baseurl`, OpenGraph /
  sitemap / feed settings.
- `_templates/`: the custom theme, built on Sphinx's `basic` theme (topbar,
  sidebar, footer, layout).
- `_static/css/`, `_static/js/`: styles and vanilla JS (no framework).
- `_ext/`: small local Sphinx extensions.
- `_extra/robots.txt`: copied verbatim to the site root.
- `versions.json`: the version selector's menu (see below).

## Notable choices

- master is served at the site root (no `/en/`, no `/latest/`); frozen past
  releases live under `/<version>/`, listed in `versions.json`.
- Built with the `dirhtml` builder, so URLs are extensionless directories
  (`psutil.io/faq/`, no `.html`).
- Self-hosted on GitHub Pages under the custom domain psutil.io.
- Fonts, CSS and JS are all self-hosted; no external assets.
- Social cards, sitemap and Atom feed are generated at build time and rooted at
  `html_baseurl`.

## Freezing a doc version

Add an entry to `versions.json`:

    { "name": "8.0", "url": "/8.0/", "note": "release", "ref": "v8.0.0" }

Entries with a `ref` are rebuilt from it on every deploy and get an "old
version" banner. Nothing is stored, and tags publish nothing on their own.
Deleting the entry unpublishes it.

## Tests

- `test_docs.py`: offline checks on the built HTML (canonical / OG tags,
  sitemap, feed, blog metadata, no external assets, ...). Run with `make test`.
- `test_docs_online.py`: smoke tests against the live site (reachability,
  http->https, 404 page, metadata). Run with `make test-online-doc` (sets
  `PSUTIL_DOCS_ONLINE=1`).

## Deploy

`.github/workflows/docs.yml` runs on pushes / PRs that touch `docs/`: lint
(`make lint-rst`) -> offline tests -> build -> build past versions -> deploy to
GitHub Pages -> live-site tests. Deploy and the live tests run only on push to
master, never on PRs.

## 2. Official Technical Reference & Guides (giampaolo/giampaolo.github.io)

## File: README.md

Source code for <https://gmpy.dev/> / <https://giampaolo.github.io/>.

Everything lives on the `master` branch. On every push a GitHub Actions
workflow builds the Pelican site and deploys it to GitHub Pages, so no
generated HTML is stored in the repo.

Note: `content/extra/htaccess` is Apache-only and applies to
<https://gmpy.dev/>. GitHub Pages ignores it; the `.github.io` mirror
relies on Pelican's own URL layout.

# Setup

- Install python deps:

```
make install-pydeps
```

- Run server locally (<http://127.0.0.1:8000>):

```
make serve
```

# Make a new blog post

- create a new file, e.g. `content/blog/2020/new-blog-post.rst`; use
  `make create-blogpost`

```
New blog post
#############

:date: 2020-06-26
:tags: announce, python

Hello world!
```

- test it:

```bash
# after this connect to http://127.0.0.1:8000/
make clean html serve
```

- commit and push it:

```bash
git add content/blog/2020/new-blog-post.rst
git ci -am "new blog post"
git push
```

- the push triggers a GitHub Actions build that deploys to Pages; within a
  minute or so gmpy.dev updates automatically.

# Link to an internal blog post

```
`blog post <../2013/making-constants-part-of-your-api-is-evil>`_
```

# Image

```
.. raw:: html

    
        <a href="/images/me-with-jay.jpg">
        
        </a>
    
```

---

## File: content/blog/2025/a-brave-chrome-extension-to-reorder-tabs.md

Title: A Brave / Chrome extension to reorder new tabs
Date: 2025-04-02
Tags: js, brave, dotfiles
Authors: Giampaolo Rodola

While browsing, I almost always keep three tabs open: Gmail, Slack, and
Microsoft Teams (for work). I find it convenient to have them always in the
same position (1, 2, and 3), so I can quickly switch to them using keyboard
shortcuts (`alt+1`, `alt+2`, `alt+3`). While the Gmail tab remains in place,
Slack and Teams frequently move because I use them for work, closing them in
the evening and reopening them the next morning. And each time I have to
manually reposition them. To automate this process, I started looking for a
Brave (Chrome) extension but couldn't find one that fully met my needs. So, I
decided to spend a little time writing my own. It turns out it's incredibly
easy. Here's how you can create a simple Brave extension. The same process
should also work for Chrome.

- Put these 2 files in a folder:

`manifest.json`:

```json
{
    "manifest_version": 3,
    "name": "Tab repositioner",
    "version": "1.0",
    "description": "Set position of new tabs",
    "permissions": ["tabs"],
    "background": {
        "service_worker": "background.js"
    }
}
```

`background.js`:

```js
function move_tab(tab, index) {
    if (tab.index != index) {
        console.log(`moving tab '${tab.url}' to position ${index}`);
        chrome.tabs.move(tab.id, { index: index });
    }
}

function move_new_tabs(changeInfo, tab) {
    if ((changeInfo.status === "loading" || changeInfo.status === "complete") && tab.url) {
        if (tab.url.includes("mail.google.com")) { move_tab(tab, 0); }
        if (tab.url.includes("app.slack.com")) { move_tab(tab, 1); }
        if (tab.url.includes("teams.microsoft.com")) { move_tab(tab, 2); }
    }
}

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
    move_new_tabs(changeInfo, tab);
});
```

- Go to `brave://extensions/` (`chrome://extensions/` for Chrome).
- Enable `Developer Mode` (top right).
- Click `Load unpacked` and select your folder.
- To observe debug messages printed in the console, click on `Service Worker`.
- After editing `background.js`, click the refresh icon to apply the changes.