An experiment for the reMarkable that watches what you write and, when prompted either with a gesture or some on-screen content, can write back to the screen. This is an exploration of various interactions through this handwriting+screen medium.


I wrote the handwritten prompt, GPT-4o drew the Chihuahua!!!

You need an OPENAI_API_KEY (or similar for other models) environment variable set. I did this by adding it to my ~/.bashrc file on the remarkable:
# In the remarkable's ~/.bashrc or before you run ghostwriter, set one or more of your keys
export OPENAI_API_KEY=your-key-here
export ANTHROPIC_API_KEY=your-key-here
export GOOGLE_API_KEY=your-key-here
Install by getting the binary to your remarkable. On your not-remarkable (ie. your laptop):
# For the reMarkable2
wget -O ghostwriter https://github.com/awwaiid/ghostwriter/releases/latest/download/ghostwriter-rm2
# For the reMarkable Paper Pro
wget -O ghostwriter https://github.com/awwaiid/ghostwriter/releases/latest/download/ghostwriter-rmpp
# Replace this ip address with your remarkable ip address
scp ghostwriter root@192.168.1.117:
Then you have to ssh over and run it. Here is how to install and run (run these on the remarkable):
# One time -- make it executable after the initial copy
chmod +x ./ghostwriter
./ghostwriter --help # Get the options and see that it runs at all
First you need to start ghostwriter on the reMarkable. SSH into your remarkable and run:
# Use the defaults, including claude-sonnet-4-0
./ghostwriter
# Use ChatGPT with the gpt-4o-mini model
./ghostwriter --model gpt-4o-mini
Draw some stuff on your screen, and then trigger the assistant by touching/tapping the upper-right corner with your finger. In the ssh session you'll see other touch-detections and there is a log of what happens while it is processing. You should see some dots drawn during processing and then a typewritten or drawn response!
Models & Engines:
* --model MODEL - Model to use (default: claude-sonnet-4-0)
* --engine ENGINE - Engine: openai, anthropic, google (auto-detected from model)
* --engine-api-key KEY - API key (or use env vars)
* --engine-base-url URL - Custom API base URL
Behavior:
* --prompt PROMPT - Prompt file to use (default: general.json)
* --trigger-corner CORNER - Touch trigger corner: UR, UL, LR, LL (default: UR)
Tools:
* --no-svg - Disable SVG drawing tool
* --no-keyboard - Disable text output
* --thinking - Enable model thinking (Anthropic)
* --web-search - Enable web search (Anthropic)
Testing/Debug/Experiments:
* --log-level LEVEL - Set log level (info, debug, trace)
* --no-loop - Run once and exit
* --input-png FILE - Use PNG file instead of screenshot
* --output-file FILE - Save output to file
* --save-screenshot FILE - Save screenshot
* --save-bitmap FILE - Save rendered output
* --no-submit - Don't submit to model
* --no-draw - Don't draw output
* --no-trigger - Disable touch trigger
* --apply-segmentation - Add image segmentation for spatial awareness
To run in the background, start it (on the remarkable) with nohup:
nohup ./ghostwriter --model gpt-4o-mini &
(TODO: figure out how to run it on boot!)
I've been developing in Ubuntu, but did get it working in OSX. Generally it goes (1) install dependencies, (2) build locally but cross-compile for the reMarkable, (3) scp it over and try it out.
sudo apt-get install gcc-arm-linux-gnueabihfbrew install arm-linux-gnueabihf-binutilscargo install cross --git https://github.com/cross-rs/crossrustup target add armv7-unknown-linux-gnueabihf aarch64-unknown-linux-gnucross build --release --target=armv7-unknown-linux-gnueabihfscp target/armv7-unknown-linux-gnueabihf/release/ghostwriter root@remarkable:cross build --release --target=aarch64-unknown-linux-gnuscp target/aarch64-unknown-linux-gnu/release/ghostwriter root@remarkable:build.sh./build.sh to build and send to my rm2./build.sh rmpp to build and send to my rmppMeanwhile I have another terminal where I have ssh'd to the remarkable. I ctrl-C the current running ghostwriter there, then on my host laptop I run my build script, and then back on the remarkable shell I run ghostwriter again.
When I want to do a build for others, I tag main with like v2026.09.21-01 and that kicks off a github action that creates the latest release.
./ghostwriter text-assist mode, uses a virtual keyboard to respond!tools so that it can contextually give back an SVG or text or start to trigger external scripts, like for TODO list management./build.sh local)
* Need to get some automation around the evaluations
* The segmenter has to be explicitly enabled with --apply-segmentation and it assumes that you have either --input-png or --save-screenshot because it (dumbly) re-parses the png file
* OMG this is the first time that the math prompt got even close to putting the answer where I want! It has been getting it right, but usually types the 10 with the keyboard or places it somewhere wrong. This time it actually put it where it should be!
* 2024-12-15 - Engine Unification
* With the usual help from claude/copilot and some tutorials I extracted out some polymorphic engine layer for OpenAI and Anthropic backends
* So now you can pass in engine and model
* A lot of other codebases take a model and then do a map; maybe I'll do that based on the model name or something
* I also got the prompt and tool definitions externalized (into a prompts/ directory) and unified, so each engine does whatever it needs to adjust for its own API
* In theory the prompts/ files are both bundled in the executable AND overridable at runtime with a local directory, but I haven't verified that much
* 2024-12-18 - System Upgrade Panic
* I auto-update my remarkable, usually fine
* But I just got 3.16.2.3 and ... screenshots stopped working!
* So I used codexctl to downgrade. It gave me a VERY scary "SystemError: Update failed!" and then the whole system locked up!
* ... but a reboot fixed it and the downgrade to 3.14.1.9 worked upon reboot
* So... I'm keeping an eye out for other reports of issues on the new version
* Oh yes. Now you can take prompts/general.json, rename it to james.json and go in and add "Your name is James" into the prompt. Then copy that to your reMarkable
* Now run ./remarkable --prompt james.json and it has a locally modified prompt!
* 2024-12-19 -- Not Quite Local
* On the internet they suggested a local-network Vision-LLM mode
* Ollama has that! So I tried...
* But it says that llama3.2-vision doesn't have tools :(
* But Groq llama-3.2 does!
* ... but it is not very good at tic-tac-toe (this is the 90b). Though it is very fast!


* Oops! I forgot to turn on segmentation. Here it is with that enabled which should give a better sense of space...


* Here are 3 runs from claude in contrast


* Well. The new ENV is OPENAI_BASE_URL, so OPENAI_BASE_URL=https://api.groq.com/openai ./ghostwriter --engine openai --model llama-3.2-90b-vision-preview for example
* 2024-12-22 -- Starting to Evaluate
* Starting to build out the evaluation system a bit more, including a basic script to kick it all off
* Right now it is a hard-wired set of parameters which basically turn on/off segmentation and use either Claude 3.5 Sonnet or ChatGPT 4o-mini
* See the initial evaluation report!
* I think markdown doesn't let me lay this out how I want, so will probably switch to html (maybe turn on github site hosting for it)
* This is starting to get into the terratory where it can take some time and money to execute ... running this a bunch of times and I sent like $1. Not sure how long it took. but there were 48 executions in this final report
* Oh -- I think it's rather important to run each set a few times assuming there is some temperature involved
* To scale this even further we of course would want to bring in a JUDGE-BOT!
* Then I could say things like "my new segmentation algorithm improved output quali
$ claude mcp add ghostwriter \
-- python -m otcore.mcp_server <graph>