> ## Content Index
> Fetch the complete content index at: https://www.autodidacts.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# A basic way to hotreload an AppImage
- URL: https://www.autodidacts.io/hotreload-an-appimage-extract-modify-repack-with-entr/
- Published: 2026-01-24T07:25:55.000Z
- Updated: 2026-01-24T07:34:00.000Z
- Description: Repack and run every time you hit save
- Author: Curiositry
- Tags: 100DaysToOffload, KOReader, Lua, AppImage, Tutorial, Kobo, Read-it-later, Bash

****Note:** this post is part of [#100DaysToOffload](https://www.autodidacts.io/100daystooffload/), a challenge to publish 100 posts in 365 days. These posts are generally shorter and less polished than our normal posts; expect typos and unfiltered thoughts! [View more posts in this series.](https://www.autodidacts.io/tag/100daystooffload/)

  
I have been going down a read-it-later app rabbit hole — Pocket, Instapaper, Wallabag, Readeck: I’ve tinkered with them all — and I have reached the depth where I start to hack on the software to make it work how I want.

At first, it was API scripts for Instapaper and Wallabag. Then, [I patched the KOReader Wallabag plugin to add star support](https://www.autodidacts.io/star-wallabag-entry-from-koreader/). Then, I [tried Readeck](https://www.autodidacts.io/readeck-open-source-read-it-later-app-with-kobo-support/), and tinkered with [OPDS](https://opds.io/?ref=autodidacts.io). Then, [I ported my Wallabag patch over to the Readeck KOReader plugin](https://github.com/curiositry/readeck.koplugin?ref=autodidacts.io).

The KOReader maintainers, understandably, [wanted there to be a way to disable](https://github.com/koreader/koreader/pull/14793?ref=autodidacts.io) my lightly-tested feature.

It wrote the patches blind, loaded them onto my Kobo, and they worked first try. But writing *UI* code that way, in a language I’ve never used? Not likely!

I looked into [setting up a KOReader development environment](https://github.com/koreader/koreader/blob/master/doc/Building.md?ref=autodidacts.io) (in an emulator). But it turns out this isn’t necessary:

> If you only want to work with Lua frontend stuff, you can grab the AppImage and run it with `–appimage-extract`.

I know nothing about AppImages, and nothing about Lua; I even haven’t read a single tutorial. Let’s go, this sounds like fun!

I downloaded the latest KOReader AppImage from [https://github.com/koreader/koreader/releases/latest](https://github.com/koreader/koreader/releases/latest?ref=autodidacts.io).

Now I had `koreader-appimage-ARCHITECTURE-vYYYY.MM.AppImage` (in my case, `koreader-appimage-x86_64-v2025.10.AppImage`) in my working directory.

I ran `./koreader-appimage-x86_64-v2025.10.AppImage –appimage-extract`

A directory appeared called `squashfs-root`, with KOReader things in it. Cool!

I dropped in my modified Readeck.koplugin:

```bash
cp -r path/to/readeck.koplugin/readeck.koplugin/ path/to/squashfs-root/plugins/

```

Now, how to sew the thing back up and run it?

With [appimagetool](https://github.com/AppImage/appimagetool/releases/tag/continuous?ref=autodidacts.io), which is itself (fittingly) an AppImage.

I downloaded `appimagetool-x86_64.AppImage` and ran:

```bash
./appimagetool-x86_64.AppImage squashfs-root/

```

Boom! `KOReader-x86_64.AppImage` appeared, and when I ran it (`./KOReader-x86_64.AppImage`), a KOReader appeared, with the Readeck plugin I had added.

I got hacking on the plugin UI, but that’s a story for another post. Because first, I wanted to get an efficient development environment and [shorten the feedback loop](https://autodidacts.io/troubleshooting/?ref=autodidacts.io#shorten-the-feedback-loop).

I often use the handy `entr` utility for hot-reloading. In this case it was slightly more complicated, for a few reasons:

1. It was strangely hard to find a process ID to quit the old KOReader  
  1. you can’t run `killall koreader`, or `pgrep -i koreader`, or `pkill –full -i koreader` even though there *is* a process with the short name `KOReader-x86_64` running. You want the ./**luajit** process running **reader.lua**.
2. I made various dumb mistakes  
  1. we won’t go into it
3. `entr` doesn’t work with a build command that never exits (duh)  
  1. I thought I should be able to background the process with `./KOReader-x86_64.AppImage &` but that didn’t work and I don’t really understand why. Redirecting all output, running it in the background, and disowning it did work.

**Dependencies**: awk, xargs, entr, fish (optional). Install ’em all on Debian-based distros (if you’re lucky) using:

```
sudo apt install awk xargs entr

```

**The Script**

Create a script called `build-appimage.sh` (or something smarter) with the following contents:

```bash
#!/bin/bash
# remove the old appimage (can't remember if this is needed)
rm KOReader-x86_64.AppImage

# Send SIGTERM to the right KOreader process 
ps -ef | grep -i 'reader.lua' |  awk {'print $2'} | xargs kill
# ^ this was half the work, because there are a bunch of different processes,
# and this is the one that will actually get rid of the running KOReader

# Pack the new AppImage
./appimagetool-x86_64.AppImage squashfs-root/

# Run it, then get free of its sticky fingers
./KOReader-x86_64.AppImage > /dev/null 2>&1 &
disown

```

(You may need to run `chmod +x build-appimage.sh`, and also possibly chmod +x the AppImages themselves.)

You probably want to also download the runtime(s) for the architectures you need from [https://github.com/AppImage/type2-runtime/releases](https://github.com/AppImage/type2-runtime/releases?ref=autodidacts.io), and pass them to appimagetool so they don’t get downloaded every time it builds. Like this:

```
./appimagetool-x86_64.AppImage --runtime-file="runtime-x86_64" squashfs-root/

```

Then, in Fish Shell, run:

```bash
ls squashfs-root/** | entr ./build-appimage.sh

```

The \*\* is a fish-ism, which is a lazy way of making it watch *all* files in the directory. There are other ways to achieve the same result. (It would probably work to use the same syntax with Bash if you set `setopt globstar`.) Or you can just use the path to the file you’re mainly editing:

```
ls squashfs-root/plugins/readeck.koplugin/main.lua | entr ./build-appimage.sh

```

Now, KOReader restarts with fresh code every time you hit save in your editor.

Check it out!

0:00 

/0:32 

1× 

pay absolutely no attention to the spelling of "entries"