Skip to content
/ gnaw Public

Latest commit

 

History

88 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

#+title: gnaw — GNAW is Not Another Workflow
#+author: Bastien Guerry

[[https://intver.org/][https://img.shields.io/badge/versioning-intver.org-blue.svg?style=for-the-badge]]

*gnaw* (what you do to a bone) is a standalone [[https://github.com/babashka/babashka][Babashka]]
script for browsing [[https://codeberg.org/bzg/bone][BONE]] reports. When [[https://github.com/junegunn/fzf][fzf]] is available, gnaw lets you
browse BONE reports interactively.

[[file:gnaw.png]]

* Install

Assuming [[https://github.com/babashka/bbin][bbin]] is installed:

: bbin install io.github.bzg/gnaw

* Configure

Create =~/.config/gnaw/config.edn=:

#+begin_src clojure
{:my-addresses ["you@example.com" "alias@example.com"]
 :text-browser "w3m"          ;; "w3m", "lynx" or "links"
 :diff-pager   "delta"        ;; "delta", "bat" or "diff-so-fancy"
 :sources      [{:urls ["https://example.com/reports/all.json"]
                 :name "Example ML"
                 :repo "https://example.com/repo"}
                {:urls ["https://example.com/reports/all-open.json"
                        "https://example.com/reports/all-closed.json"]
                 :name "Another ML"}]}
#+end_src

- =:my-addresses= — your email address(es), used by =-m= to filter reports
  involving you. Can be a single string or a vector of strings.
- =:text-browser= — terminal browser for viewing reports on =RET=. When
  unset, gnaw probes for =w3m=, =lynx=, =links=, then falls back to
  =xdg-open=.
- =:diff-pager= — pager for viewing patches on =C-v=. When unset, gnaw
  probes for =delta=, =bat=, then falls back to =$PAGER= or =less=.
- =:sources= — vector of report sources. Each source is a map with:
  - =:urls= — a non-empty vector of URLs/paths to BONE =reports.json= files
    whose reports are merged into one source (e.g. an =all-open.json= and an
    =all-closed.json=).
  - =:name= — the source's name. It is the *unique key* of a source: two
    sources may not share a =:name=, and it overrides the =source= of every
    report the source yields so the grouped files appear unified.
    =--add-source= fills it in from the sibling =meta.json='s =source= field.
  - =:repo= — (optional) public URL or local path of the associated code
    repository.

When adding an HTTP source, you may pass the full reports URL
(=.../reports/all.json=), another report file (=.../reports/all-open.json=),
or just the base URL (=https://tracker.orgmode.org=): gnaw resolves a bare
base to =reports/all.json= and reads =reports/meta.json= to record =:name=.
- =:skip-columns= — vector of column names to hide by default (e.g.
  =["priority" "score"]=).
- =:report= — configuration for =gnaw report= (see [[*Triage report][Triage report]]).

* Usage

: gnaw [options]
: gnaw report [options]
: gnaw clear
: gnaw update

** Options

| Option                    | Description                                       |
|---------------------------+---------------------------------------------------|
| =-f=, =--file FILE=           | Read reports from a JSON file                     |
| =-u=, =--url URL=             | Fetch reports from a URL                          |
| =-U=, =--urls-file FILE=      | Fetch and merge from URLs listed in FILE          |
| =-M=, =--my-addresses EMAILS= | Your email(s), comma-separated (overrides config) |
| =-n=, =--source NAME=         | Filter by source name                             |
| =-p=, =--min-priority N=      | Only show reports with priority >= N (1, 2 or 3)  |
| =-s=, =--min-score N=         | Only show reports with score >= N (0–7)           |
| =-S=, =--skip-columns COLS=   | Columns to hide, comma-separated                  |
| =-m=, =--mine=                | Show only reports involving your address(es)      |
| =-c=, =--closed=              | Include closed reports                            |
| =-=                         | Read JSON from stdin                              |

** Triage report

=gnaw report= prints a text triage report to stdout.  It accepts the
same filtering options as interactive mode (=-f=, =-u=, =-m=, =-c=, etc.).

The report includes the following sections: overview, stale patches,
stale bugs, active threads, recent reports, and owned reports.

The report can be configured in =config.edn= under the =:report= key:

#+begin_src clojure
{:report {:sections    ["overview" "stale-patches" "stale-bugs"
                        "active-threads" "recent" "owned"]
          :stale-days  14   ;; threshold for "stale" (default: 14)
          :recent-days 7    ;; threshold for "recent" (default: 7)
          :top-n       10}} ;; max items per section (default: 10)
#+end_src

- =:sections= — list of sections to include in the report.
- =:stale-days= — number of days after which a report is considered stale.
- =:recent-days= — number of days to look back for recent reports.
- =:top-n= — maximum number of items shown in stale and active-threads sections (=recent= and =owned= are not capped).

** Source management

| Command                         | Description               |
|---------------------------------+---------------------------|
| =-a=, =--add-source URL_OR_PATH=    | Add a reports.json source |
| =-r=, =--remove-source URL_OR_PATH= | Remove a source           |
| =-l=, =--list-sources=              | List configured sources   |

Sources are stored in =~/.config/gnaw/config.edn= under the =:sources= key.

=--add-source= accepts either a direct =reports.json= URL/path, which is
added as-is, or a tracker /base URL/ (e.g. =https://tracker.orgmode.org=).
Given a base URL, gnaw reads =reports/meta.json= for the source name and the
list of available report files, then lets you pick which to add (via fzf, or
a numbered prompt when fzf is absent). The chosen files are grouped into one
named source:

#+begin_src clojure
{:urls ["https://tracker.orgmode.org/reports/all-open.json"
        "https://tracker.orgmode.org/reports/all-closed.json"]
 :name "Org mode ML"}
#+end_src

** Cache management

| Command | Description                           |
|---------+---------------------------------------|
| =clear=   | Empty the cache                       |
| =update=  | Fetch/update reports from all sources |

By default, gnaw reads cached reports if available. If no cache
exists, it fetches from sources once and caches the result. Use =gnaw
update= to refresh.

** Interactive keys (fzf)

| Key | Action                          |
|-----+---------------------------------|
| =C-n= | Move to the next line           |
| =C-p= | Move to the previous line       |
| =RET= | View report in terminal browser |
| =C-o= | Open report in system browser   |
| =C-v= | View patch (fetched to cache)   |
| =C-s= | Change sort order               |
| =C-r= | Filter by report type           |
| =C-b= | Filter by source                |
| =C-t= | Filter by topic                 |
| =C-u= | Update cache and reload         |
| =C-h= | Show help                       |
| C-x | Remove current filters          |

* Examples

Browse your reports from a local file:

: gnaw -f reports.json -m

Browse all reports from a remote URL:

: gnaw -u https://example.com/reports.json

Merge reports from multiple BONE instances:

: gnaw -U my-urls.txt

The URLs file (=-U=) lists one URL per line; blank lines and =#=
comments are ignored.

Add a source and browse:

: gnaw -a https://example.com/reports.json

Update cached reports and browse only yours:

: gnaw update
: gnaw -m

* Files

| Path                          | Purpose                        |
|-------------------------------+--------------------------------|
| =~/.config/gnaw/config.edn=     | User configuration and sources |
| =~/.config/gnaw/cache/patches/= | Cached patches                 |
| =~/.config/gnaw/cache/reports/= | Cached reports.json files      |

* Contributing

- Send a [[mailto:~bzg/boneyard@lists.sr.ht][bug report]] with =[BUG] gnaw: <SHORT EXPLICIT BUG DESCRIPTION>=
- Send a [[mailto:~bzg/boneyard@lists.sr.ht][patch]] with =[PATCH] gnaw: <COMMIT SUMMARY>=
- Send a [[mailto:~bzg/boneyard@lists.sr.ht][feature request]] with =[FR] gnaw: <FEATURE REQUEST>=
- Share any [[mailto:~bzg/boneyard@lists.sr.ht][other question or idea]]

You can also [[mailto:bzg@bzg.fr][send me an email]] and support my work on [[https://liberapay.com/bzg/][liberapay]].

* Intentional Versioning

This project uses [[https://intver.org][Intentional Versioning]], here are the three audiences:

- =Users= : end users who browse BONE reports with gnaw
- =Integrators= : external packagers
- =Maintainers= : maintainers of the codebase

* Support the Clojure(script) ecosystem

If you like Clojure(script), please consider supporting maintainers by
donating to [[https://clojuriststogether.org][clojuriststogether.org]].

* License

Copyright © 2026 Bastien Guerry

Distributed under the [[https://www.eclipse.org/legal/epl-2.0/][Eclipse Public License 2.0]].

About

GNAW is Not Another Workflow

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages