npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gpambrozio/paseo-github-board

v0.9.0

Published

Paseo plugin: a GitHub sidebar board of your issues, draft and open pull requests, and discussions

Downloads

305

Readme

paseo-github-board

A Paseo plugin that adds a GitHub sidebar surface showing your work — and the work waiting on you — in four columns:

| Column | Source | | --- | --- | | Issues | gh api graphql, search(type: ISSUE) for is:issue state:open | | Draft PRs | gh api graphql, search(type: ISSUE) for is:pr state:open, filtered to isDraft | | Open PRs | the same search, filtered to non-draft | | Discussions | gh api graphql, search(type: DISCUSSION) |

Every column runs its search more than once and unions the results: once for author:<login>, once for user:<login> — everything in the repositories that login owns, whoever opened it — and, for issues and pull requests, once for assignee:<login>. Those last two are why work somebody else opened shows up here: an issue filed on your own repository, or one handed to you anywhere on GitHub. The card names its author when it is not you. Discussions get the first two only, since a discussion has no assignee. GitHub search ANDs its qualifiers, so they cannot be folded into one query; they are aliased searches sharing one gh api graphql request instead.

Both pull request columns come from one search, so the four columns cost three gh calls per refresh, not four or six — plus one more for the check runs on the open pull requests, and one for how far each pull request's branch is behind, when there are any. Everything goes through GraphQL rather than gh search, because only GraphQL exposes closingIssuesReferences and statusCheckRollup — see below.

The GitHub board: Issues, Draft PRs and Open PRs columns of cards, with the repository
filter, the settings gear and the refresh button in the header.

Issues folded into their pull requests

An issue that already has an open pull request against it is the same piece of work as that pull request, so it gets one card, not two: the issue drops out of the Issues column and shows up as an accent-coloured Issue #123 pill on the pull request card. Drafts count — the work exists either way — so a draft pull request claims its issue too.

The link is GitHub's own closingIssuesReferences, which sees both closing keywords in the pull request body (Closes #123) and issues attached by hand from the Development panel. A pill reads Issue owner/name#123 when the issue lives in another repository.

The fold happens after the repository filter, so hiding a pull request's repository puts its issue back on the board rather than taking both cards away.

Empty columns come off the board

A column with nothing in it is left out: the remaining columns share the full width, and on a phone the tab bar lists only the tabs that lead somewhere. It is counted after the repository filter and the issue fold, so filtering a repository down to nothing, or a pull request claiming the last issue, takes that column with it.

A column that failed to load stays, error and all — it is empty because the query broke, not because there is no work. And when every column is empty the whole board comes back, four "Nothing here." columns saying it loaded and found nothing.

Checks on open pull requests

An open pull request card leads its footer with the state of CI on the head commit, the same three counts Paseo's own sidebar shows on a workspace:

| Pill | Means | | --- | --- | | ✓ 12 | checks that passed | | ✕ 1 | checks that failed, timed out, or need action — in the theme's danger colour | | ● 3 | checks still queued or running, in the accent colour |

An outcome nobody has is left out, so a green pull request shows one pill rather than two zeroes, and a pull request whose head commit nothing reported on shows none at all. Skipped and cancelled checks are counted nowhere: they are neither a result nor something to wait for. Where a check has been re-run, only the latest attempt counts.

Draft pull requests show no checks. A draft says the work is not finished, so its CI is not yet anyone's business — and asking for fewer pull requests keeps the extra request small.

The checks are a separate gh call from the search on purpose. A token without permission to read checks — a fine-grained PAT, usually — makes GitHub fail the whole GraphQL request, and folding the rollup into the search would turn that into two blank pull request columns. On its own, it costs only the pills, and the reason lands in paseo plugin logs github-board.

Checks are cached with the rest of the board for five minutes; Refresh is what re-reads a run that has finished since.

Out-of-date pull requests

A draft or open pull request whose base branch has moved on since the branch was last updated shows an Out of date pill, in the theme's warning colour, next to its checks — or Conflicts, in the danger colour, when the branch and its base change the same lines and someone has to resolve them by hand. The base is whatever the pull request targets — main for most, another branch for a stacked one. The detail panel shows the same pill and says how far behind on the branch line: feature → main · 12 commits behind.

Where GitHub would let you bring it up to date, the card and the panel also offer Update branch — on a card it appears on hover beside Send to chat, and on a phone it sits in the card's button row. In a tablet's browser, where nothing hovers, open the card and use the button in the panel. It does what GitHub's own button does, merging the base branch into the pull request's branch on GitHub; it never rebases, so a checkout of the branch elsewhere still pulls cleanly. The pill goes away once GitHub accepts the update.

A pull request with conflicts never offers the button, since an automatic update cannot succeed there. GitHub only works out whether a branch has conflicts once somebody asks, so the first time the board loads a pull request it may not know yet; pressing Update branch checks again first, and if it finds conflicts it merges nothing, switches the pill to Conflicts and says so.

Other out-of-date pull requests can show the pill and no button too. That is GitHub's answer, not the plugin's: it offers no update when your login cannot push to the branch, or when the repository has Always suggest updating pull request branches turned off — which is the default for a new repository — and branch protection does not require an up-to-date branch. Turn that setting on under the repository's Settings → General → Pull Requests to get the button there.

This works for pull requests from forks too. How far behind a branch is comes from its own gh call, so if that fails the pills and buttons are left off and the reason lands in paseo plugin logs github-board; the pull requests themselves still load. Like checks, it is cached with the board for five minutes, and Refresh reads it again.

Configuring the prompts

The gear button in the header opens the settings view. It holds the GitHub login the board queries for, and the first message each kind of card is sent with:

| Column | Default prompt | | --- | --- | | Issues | Read issue {url}, investigate and give me ways to address it. | | Draft PRs | Read draft pull request {url} and help me finish it. | | Open PRs | Review pull request {url} and tell me what needs attention. | | Discussions | Read discussion {url} and summarise what is being decided. |

Templates can use {url}, {title}, {number} and {repository}. Anything else in braces is passed through untouched. A template is only the starting point — the launch dialog lets you rewrite the message before it is sent.

Pick a Paseo project from the row of chips to override those four prompts for that project alone; a dot on a chip means it has overrides. Cards are matched to a project by the repository's git remote, the same way sending one is — so a fork and the repository it was forked from share one set of prompts, and a repository with no project needs none, since it cannot be sent anywhere either.

Clearing a field is how you reset it — a blank project prompt falls back to the one for all projects, and a blank prompt for all projects falls back to the built-in default above. Nothing is saved until you press Save prompts.

Filtering by repository

The header dropdown next to Set lists every repository with a card anywhere on the board and filters all four columns at once. Everything starts selected; All and None set the whole list.

The selection is saved by Paseo, per daemon, because the surface unmounts on every workspace switch and component state would not survive it. Changing it on one device shows up on the others without a reload. It is stored as the hidden repositories rather than the visible ones, so a repository the filter has never seen — a new one, or one whose first card only appears on a later refresh — arrives selected rather than silently filtered out.

Reading a card

Click a card and it opens in a panel beside the board — the right half of the surface, or the whole of it on a phone. The panel shows the title, who opened it, the comment count, the labels, a pull request's branches, and the description rendered the way GitHub renders it — including the HTML a bot like Dependabot writes, whose release notes show as collapsible sections — followed by the assignees. A pill in the panel's header says whether the item is still open, or has been closed or merged since the board was fetched.

Open on GitHub is in the panel, next to Send to chat, so nothing the card used to do is gone — it is one press further away. Refresh reloads the description if it was edited on GitHub in the meantime; otherwise the panel remembers what it fetched for five minutes.

A Load comments button at the foot of the panel fetches the conversation — the comments on an issue or pull request, or a discussion's comments with their replies indented under them. It shows the first 50 and says so if there are more; pull request review comments on the diff are not included. Refresh reloads the comments too once they have been loaded.

Screenshots pasted into the description or a comment are shown in the panel, including attachments on private repositories, which the plugin fetches through gh on the daemon. Press one to open the original.

On a desktop the panel's left edge can be dragged to make it wider or narrower. The width is saved as a share of the board, so it comes back the same after a restart and scales with the window.

While the panel is open the board behind it is blurred, and clicking it closes the panel. The open card is outlined so you can see which one you are reading.

A pull request open in the detail panel: repository and state at the top, the title, who opened
it and when, its branches, Send to chat and Open on GitHub buttons, and the description below,
with the board blurred behind it.

Labels

Right-click an issue or pull request card — long-press on a phone or tablet — and its repository's labels open where you clicked. Press a label to add it, press it again to remove it. Each press is applied to GitHub straight away and the card's pills update with whatever GitHub reports back, so a label a teammate added in the meantime shows up rather than being wiped by your edit.

Discussions have no label menu. Cards show three labels and then a +2, so an edit past the third is still visible as a change.

Editing labels needs a gh login with write access to the repository; without it the menu says so and leaves the label alone. The menu lists the repository's first 100 labels by name, with a filter box once there are more than eight.

Send to chat

Hover a card and a Send to chat button appears in its bottom-right corner. It opens a New workspace dialog, the same choices Paseo asks for when you start a chat yourself:

  • Which computer it runs on, when the app is connected to more than one — the board's own, or any other that is online. Only shown when there is a choice.
  • Local or New worktree — a worktree is offered only for git projects.
  • The agent, picked the way Paseo picks one: a menu of providers with their model counts, then that provider's models behind a back arrow, with a search box that ranks across every provider.
  • Thinking, for models that have levels, and the permission mode, for providers that have modes. Both follow the model you pick.
  • The first message, pre-filled from that column's prompt template and yours to rewrite.

Press Send and the plugin creates the workspace on the project checked out from that card's repository, titled after the issue, pull request or discussion, starts the agent you chose in it, sends your message, and opens the new workspace in the app.

The conversation opens with the card itself — repository and number, title, author and labels — as the first thing under your message. Click it to open the original on GitHub. It is saved with the conversation, so it is still there after a restart and on your other devices, and it does not depend on your prompt template having mentioned the issue.

Your choices are remembered, so the next card opens on the same agent. A model or provider that has since disappeared quietly falls back to what the host actually offers.

If no project has a git remote pointing at the repository, the dialog says so and creates nothing.

Sending to another computer

The board always comes from the computer it is installed on — that is where gh runs — but the agent does not have to. Pick another computer in the dialog and the workspace, the agent and its models are that computer's; the plugin does not need to be installed there. Two things work differently:

  • The repository has to be the project's own there. On the board's computer a card also finds a fork that keeps the repository as a second remote; on another one it only finds a project whose main remote is the card's repository.
  • The conversation does not open with the card. Paseo only lets the plugin add it on the board's own computer, so on another one the issue is only as present as your message makes it — the default prompts include its link.

On phones and tablets there is no hover, so the button is always visible.

Caching

Revisiting the board does not re-run gh. Two caches sit in front of it, both in memory and both five minutes:

  • The surface keeps the last board at module scope, so a workspace switch — which unmounts it — repaints instantly. Past the window the stale board stays on screen while a refresh runs underneath it.
  • The handler keeps the last board per login, so even a cold mount usually skips the gh calls. A board with a failed column is not cached, so the retry is not held off for five minutes.

Refresh bypasses both. The repository filter is not part of the cached board at all — Paseo keeps it separately — so changing it cannot be undone by a cache hit.

Requirements

  • Paseo 0.9.0 or newer, for the daemon and the app that shows the board. Both check the version themselves, so an older one reports the plugin as incompatible rather than loading part of it.
  • gh installed and authenticated on the daemon machine, not the device running the app. Handlers run in a subprocess next to the daemon.

Install

paseo plugin install npm:@gpambrozio/paseo-github-board

That is the shortest route on Paseo 0.9 or newer, which installs plugins straight from npm; add @<version> to pin one. On 0.8, install the last release that supported it from this repository instead:

paseo plugin add gpambrozio/paseo-plugins --path github-board

This repository holds five plugins, hence --path. The daemon clones it under $PASEO_HOME/plugins and runs no package manager — the plugin is source only, and everything it imports at runtime the host provides. Pin a release with --ref <tag>; later, paseo plugin status and paseo plugin update github-board follow the branch.

To hack on it instead, install from a clone of your own:

git clone https://github.com/gpambrozio/paseo-plugins.git
cd paseo-plugins/github-board
npm install
npm run typecheck
paseo plugin install "$PWD"

install records the directory, so keep that clone where it is — the daemon loads the plugin from that path every time it starts. npm install is for the typecheck; installing needs none of it.

The daemon needs "pluginsEnabled": true in its config.json. Run paseo reload after changing it. Plugin code is trusted and unsandboxed: the server half shells out to gh on the daemon machine and the client half runs inside the Paseo app.

Develop

npm run typecheck
paseo plugin reload github-board   # after any source change
paseo plugin logs github-board     # load errors and stderr

Which account the board follows

The login resolves in this order:

  1. the login typed into the header field (persisted on Set),
  2. the saved login at $PASEO_HOME/plugins/github-board/settings.json,
  3. the account gh is authenticated as.

The settings file holds login, hiddenRepositories, the prompts, and the launch defaults the send dialog reopens on, and each handler merges rather than overwrites, so saving one never drops the others. A file from an older version with only login is read and upgraded in place.

@me is always resolved to a concrete login before any query runs, because GitHub's search types disagree about the alias and an unresolved @me in the header tells you nothing about which account you are looking at.

Known limits

  • Nothing you merely participated in appears. Every column is what you authored, what is open on repositories you own, and — for issues and pull requests — what is assigned to you; a thread you only commented on elsewhere is none of those. GitHub's discussion search silently returns nothing for involves: and commenter:, so a "discussions I participated in" column cannot be built at all; for issues and pull requests it would mean one more aliased involves:<login> search in server/board.ts.
  • Assigned means assignee:, not review-requested. A pull request somebody asked you to review, without assigning it to you, is not on the board unless you own the repository. That would be another aliased review-requested:<login> search.
  • "Repositories you own" means user:<login>. An organisation whose repositories you maintain but do not own contributes only what you authored yourself. Widening that means an org: search per organisation, and a list of organisations to keep somewhere.
  • Each column caps at limit (default 30, max 100) items — every half of the search is allowed that many rows, and the merged column is cut back to one budget's worth of the most recently updated. An issue whose pull request falls past that cap keeps its own card, since nothing on the board claims it.
  • A column that fails renders its own error; the other three still load.
  • The label menu offers existing labels only, the first 100 by name. Creating a label, or renaming one, still happens on GitHub.
  • Only a provider that names its models can be picked. Paseo creates agents as provider/model, so a provider that offers no selectable model is left out of the agent list rather than shown and then refused.
  • Send to chat matches a repository against every git remote of every project — origin first, then the rest. A pull request you opened from a fork lives in the upstream repository, so it matches the fork you have checked out only if that checkout keeps the upstream as a remote, which gh repo clone and gh repo fork both set up. A project with no remote pointing at the card's repository will not match.
  • Sending to another computer is narrower. Only a project whose main remote is the card's repository matches there, and the conversation starts without the card at the top of it.