{"id":31605634,"url":"https://github.com/gvolpe/niri-scratchpad","last_synced_at":"2026-01-17T11:16:18.106Z","repository":{"id":314658548,"uuid":"1056314853","full_name":"gvolpe/niri-scratchpad","owner":"gvolpe","description":"Scratchpad support for Niri","archived":false,"fork":false,"pushed_at":"2025-10-01T17:11:13.000Z","size":21,"stargazers_count":23,"open_issues_count":1,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-10-10T19:33:18.042Z","etag":null,"topics":["niri","scratchpad","wayland"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gvolpe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-13T20:35:01.000Z","updated_at":"2025-10-10T17:39:57.000Z","dependencies_parsed_at":"2025-10-01T19:05:33.851Z","dependency_job_id":null,"html_url":"https://github.com/gvolpe/niri-scratchpad","commit_stats":null,"previous_names":["gvolpe/niri-scratchpad"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/gvolpe/niri-scratchpad","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Fniri-scratchpad","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Fniri-scratchpad/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Fniri-scratchpad/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Fniri-scratchpad/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gvolpe","download_url":"https://codeload.github.com/gvolpe/niri-scratchpad/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gvolpe%2Fniri-scratchpad/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28506748,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T10:25:30.148Z","status":"ssl_error","status_checked_at":"2026-01-17T10:25:29.718Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["niri","scratchpad","wayland"],"created_at":"2025-10-06T08:02:22.937Z","updated_at":"2026-01-17T11:16:18.098Z","avatar_url":"https://github.com/gvolpe.png","language":"Shell","funding_links":[],"categories":["Python","Tools"],"sub_categories":["Window and Workspace Management"],"readme":"# niri-scratchpad\n\n[![ci](https://github.com/gvolpe/niri-scratchpad/actions/workflows/ci.yml/badge.svg)](https://github.com/gvolpe/niri-scratchpad/actions/workflows/ci.yml)\n\nScratchpad support for [Niri](https://github.com/YaLTeR/niri): a scrollable-tiling Wayland compositor.\n\nhttps://github.com/user-attachments/assets/6911e9b3-0a3c-4657-a564-7fcc3f0037b1\n\n## Install\n\nAdd this flake to your inputs.\n\n```nix\ninputs = {\n  niri-scratchpad-flake = {\n    url = \"github:gvolpe/niri-scratchpad\";\n    inputs.nixpkgs.follows = \"nixpkgs\";\n  };\n}\n```\n\nInstall the package via `niri-scratchpad` or `default`, e.g.\n\n```nix\nlet\n  inherit (inputs.ns-flake.packages.${system}) niri-scratchpad;\nin\n{\n  home.packages = [ niri-scratchpad ];\n}\n```\n\nOnly available for Linux systems, see `nix flake show` for more.\n\nIf Nix is not your jam, simply copy the [ns.py](./src/ns.py) script into your system and give it execution permissions (`chmod +x ns.py`). You'll need Python 3 installed.\n\n## Usage\n\nSee `nscratch --help` for the available commands.\n\n```console\n$ nscratch --help\nusage: nscratch [-h] (-id APP_ID | -t TITLE) [-s SPAWN] [-a] [-m]\n\nNiri Scratchpad support\n\noptions:\n  -h, --help            show this help message and exit\n  -id, --app-id APP_ID  The application identifier\n  -t, --title TITLE     The application title\n  -s, --spawn SPAWN     The process name to spawn when non-existing\n  -a, --animations      Enable animations\n  -m, --multi-monitor   Multi-monitor support\n```\n\nScratchpad windows can be searched either by `app-id` or `title`.\n\n## Niri Configuration\n\nThe workspace \"scratch\" must exist, the rest is optional.\n\n```kdl\nworkspace \"scratch\"\n\nwindow-rule {\n    match app-id=r#\"^spotify|nemo$\"#\n    open-on-workspace \"scratch\"\n    open-floating true\n}\n\nspawn-at-startup \"spotify\"\nspawn-at-startup \"nemo\"\n```\n\nFor a better experience, *declare all your workspaces explicitly* and add the \"scratch\" one last. [Example](https://github.com/gvolpe/nix-config/blob/7cc8c60c41a73f30c5c11957a1780496dec265d4/home/wm/niri/config.kdl#L611).\n\nIn this example, we create a window rule so that both `spotify` and `nemo` are spawned in the \"scratch\" workspace. Additionally, we spawn these processes at startup. \n\nNext, we have our scratchpad keybindings.\n\n```kdl\nbinds {\n    Mod+Ctrl+S { spawn-sh \"nscratch -id spotify\"; }\n    Mod+Ctrl+F { spawn-sh \"nscratch -id nemo\"; }\n}\n```\n\nBoth `spotify` and `nemo` are spawned at startup by Niri (via `spawn-at-startup`).\n\nTo further enhance your experience, consider setting the size of your scratchpad windows, e.g.\n\n```kdl\nwindow-rule {\n    match app-id=\"nemo\"\n    open-on-workspace \"scratch\"\n    open-floating true\n    default-column-width { fixed 1157; }\n    default-window-height { fixed 736; }\n}\n```\n\n### Spawn\n\nIn the following example, we have a keybinding for the Audacious application, which is not spawned by Niri. So we can indicate that if the process does not yet exist, it should be spawned by `nscratch` (internally done via `niri msg spawn`).\n\n```kdl\nbinds {\n    Mod+Ctrl+A { spawn-sh \"nscratch -id Audacious -s audacious\"; }\n}\n```\n\n**NOTE**: a spawned window via the `--spawn` (or `-s`) flag can't be made floating the first time it's brought up, but it will be from the second time onwards, due to a known limitation. If you would like to avoid this, you can either fix it via a window rule, or by letting Niri start the process at startup instead.\n\n### Animations\n\nScratchpad animations are disabled by default. To enable them, set the `--animations` or `-a` flag, e.g.\n\n```console\n$ nscratch -id nemo -a\n```\n\nThe animation is achieved by switching the scratchpad window to tiling mode when it's moved to the scratch workspace, and subsequently making it a floating window when it's summoned.\n\n### Multiple monitors\n\nMulti-monitor support can be enabled via the `--multi-monitor` or `-m` flags, e.g.\n\n```console\n$ nscratch -id nemo -m\n```\n\nIt is disabled by default because it requires an extra IPC command, which is best to avoid on a single screen.\n\n## Known Limitations\n\nGiven the fact that Niri doesn't support \"hidden\" workspaces, this solution imposes a few caveats. First of all, the \"scratch\" workspace will always be visible if you scroll all the way down to your last workspace; it can't be hidden.\n\n### Dynamic workspaces\n\nIf you rely on accessing your workspaces by index (e.g. `Mod+2`, `Mod+3`) and don't explicitly declare your workspaces in your configuration, then it means you're relying on dynamic workspaces, which is the default in Niri.\n\nDeclaring only the \"scratch\" workspace and leaving everything else as dynamic *still works*, but you can't expect your indices to remain the same. So always declare all your workspaces explicitly (see [Named Workspaces](https://yalter.github.io/niri/Configuration%3A-Named-Workspaces.html)) if you'd like the indices to be predictable.\n\nNevertheless, a better approach is to access your workspaces by name instead, e.g.\n\n```kdl\nworkspace \"web\"\nworkspace \"dev\"\nworkspace \"scratch\"\n\nbinds {\n    Mod+1 { focus-workspace \"web\"; }\n    Mod+2 { focus-workspace \"dev\"; }\n    Mod+Shift+1 { move-window-to-workspace \"web\"; }\n    Mod+Shift+2 { move-window-to-workspace \"dev\"; }\n}\n```\n\nBy using named workspaces, we also get to enjoy dynamic workspaces. See [addressing workspaces by index](https://yalter.github.io/niri/Workspaces.html#addressing-workspaces-by-index) in the official docs for more.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgvolpe%2Fniri-scratchpad","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgvolpe%2Fniri-scratchpad","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgvolpe%2Fniri-scratchpad/lists"}