Sandbox
@bahni-m/code-with-quran

Qur'an reader hook for Claude Code

This project adds a Claude Code hook that advances a Qur'an reader one ayah on each prompt. A shell wrapper starts the session with `claude --cwq`, and the reader can appear in a terminal pane or a local browser page.

48 stars3 forksJavaScriptUpdated 12d ago
Who it's for

Builders who use Claude Code and want a reader that follows their session.

What it delivers

You can keep reading the Qur'an alongside your Claude Code session without losing your place.

What it does

Session hook

Runs on Claude Code prompt submission and advances the current ayah when the session is activated.

Shell wrapper

Adds `claude --cwq` and `claude --cwq-browser` so one session can start the reader automatically.

Terminal reader

Shows the current ayah in a full-screen pane and lets you move with `j`, `k`, `g`, `f`, and `r`.

Browser reader

Serves the text from `127.0.0.1` in a local page that follows the same pointer as the terminal reader.

Offline Qur'an text

Ships the full Uthmani text and surah metadata in the `data/` folder, so it works without network access.

State and config storage

Stores progress and settings under `~/.code-with-quran/` so the reader resumes where you left off.

How to get it

  1. 1Node.js ≥ 18. No runtime dependencies.
    git clone https://github.com/bahni-m/code-with-quran.git
    cd code-with-quran
    npm link                              # puts `code-with-quran` (and `cwq`) on your PATH
    
    code-with-quran shell-init --append   # add the `claude --cwq` wrapper to your shell
    code-with-quran install               # add the Claude Code hook
    source ~/.bashrc                       # or ~/.zshrc — or open a new shell
  2. 2Now start Claude through the wrapper
    claude --cwq            # the reader follows this session

README

📖 code-with-quran

Read the Qur'an while Claude Code works.

Start a session with claude --cwq and a reader beside it walks forward through the Qur'an — one ayah per prompt, resuming from wherever you left off. Read it in a terminal pane or a browser tab.

license node runtime deps tests


Claude starts working, the ayah in your other pane moves forward, and you read a few lines instead of watching a spinner. The whole Uthmani text ships with the tool (Tanzil Project, ~1.3 MB), so the reader is instant and works offline.

                          Al-Baqarah · البقرة · The Cow · Medinan

              وَمَا خَلْفَهُمْ ۖ وَلَا يُحِيطُونَ بِشَىْءٍۢ مِّنْ عِلْمِهِۦٓ إِلَّا بِمَا شَآءَ ۚ
                        وَسِعَ كُرْسِيُّهُ ٱلسَّمَٰوَٰتِ وَٱلْأَرْضَ ۖ وَلَا يَـُٔودُهُۥ
                              حِفْظُهُمَا ۚ وَهُوَ ٱلْعَلِىُّ ٱلْعَظِيمُ ۝٢٥٥

                       █████████░░░░░░░░░░░  34.5%   2150 / 6236
                   j/k move · g goto · f follow · r reload · q quit

Quickstart

Node.js ≥ 18. No runtime dependencies.

git clone https://github.com/bahni-m/code-with-quran.git
cd code-with-quran
npm link                              # puts `code-with-quran` (and `cwq`) on your PATH

code-with-quran shell-init --append   # add the `claude --cwq` wrapper to your shell
code-with-quran install               # add the Claude Code hook
source ~/.bashrc                       # or ~/.zshrc — or open a new shell

Now start Claude through the wrapper:

claude --cwq            # the reader follows this session

Both writers back up the file they touch (*.bak-<timestamp>).

Reading it

Two readers — same text, same pointer, same keys. Pick whichever you'll actually look at:

  • Browser — a quiet local page. The safe choice: right-to-left Arabic always renders correctly. Turn it on with code-with-quran config surface web, or for a single session start with claude --cwq-browser.

  • Terminal — a full-screen pane (the default). Good in a terminal that lays out right-to-left text — but not through tmux or zellij (why). Inside tmux/zellij, claude --cwq splits the pane for you; otherwise open one yourself in a spare pane:

    code-with-quran read
    

Starting a session

CommandWhat happens
claude --cwqthe reader follows this session — one ayah per prompt
claude --cwq-browsersame, but read in the browser this session (no config change)
claude --cwq-dgr · claude --cwq-dgr-browseras above, plus --dangerously-skip-permissions
claudeuntouched — the reader stays where it is

The --cwq… flag must come first, before any other argument.

Keys

The reader assumes you read what it showed you, so the pointer only drifts if you skim. Steer it any time — the same keys in the terminal reader and the browser page:

KeyAction
j / / spacenext ayah
k / previous ayah
gjump to a reference (2:255, Al-Kahf, baqarah 255)
ffollow on/off (whether the view jumps when Claude advances)
rreload from disk
q / Escquit (a browser tab may need a manual close)

From anywhere

code-with-quran status          # progress, which readers are up, activation state
code-with-quran set 2:255       # move the pointer
code-with-quran now             # print the current ayah (handy in a tmux status line)

Settings

Config lives in ~/.code-with-quran/config.json; set values with code-with-quran config <key> <value>.

KeyDefaultMeaning
surfacetuiWhere an advance shows up: tui (terminal pane), web (bundled browser page), browser (an external site), or both (tui + web).
ayatPerSession1Ayat to advance per prompt.
cooldownMinutes0Minimum minutes between advances. 0 means every prompt advances. Raise it if quick bursts of prompts run you ahead of what you've read.
looptrueWrap 114:6 → 1:1 instead of stopping at the end.
enabledtrueMaster switch. false makes advancing a no-op (the reader still works manually).
autopaneautoAuto-open the terminal reader pane on claude --cwq: auto splits a pane when you're in tmux or zellij, off never does, tmux/zellij pin it to one.
directionlogicalHow the terminal reader emits Arabic. logical sends raw text for the terminal to shape and reorder; visual reshapes and reverses it in code for a bare terminal with no bidi. See If the Arabic looks scrambled.
sourcequran.comExternal site for surface browserquran.com, tanzil, quranwbw, alquran.cloud.
browser""Explicit browser command. Empty = your OS default.
browserArgs""Extra arguments for that command.
code-with-quran config surface web       # browser reader — best under tmux/zellij
code-with-quran config surface both      # terminal pane *and* the browser page
code-with-quran config surface browser   # an external site (quran.com etc.), a tab per advance

The browser page binds 127.0.0.1 only, opens one tab, follows the pointer, and shuts itself down a few minutes after you close the tab.

If the Arabic looks scrambled

You're almost certainly reading in a terminal, under tmux or zellij. A terminal grid can't lay out right-to-left Arabic reliably, and tmux and zellij make it worse: they paint text cell by cell with no bidi algorithm, so the terminal underneath never gets to reorder a whole line. You'll see words in left-to-right order, the ayah-end marker on the wrong side, or — with direction: visual — half-reversed text.

Don't fight it. Read in the browser:

code-with-quran config surface web       # persistent
claude --cwq-browser                     # or just this session

Same text, same pointer, same keys — rendered the way a browser always gets right.

The terminal reader is fine outside a multiplexer, in a terminal that runs the bidi algorithm itself — most modern ones do (direction: logical, the default). direction: visual reshapes and reverses each line in code for a bare terminal with no bidi at all, like plain xterm; it is not a tmux workaround.

Uninstalling

code-with-quran config enabled false   # just pause advancing, keep everything installed
code-with-quran uninstall               # remove the Claude Code hook
code-with-quran shell-init --remove      # remove the shell wrapper

How it works

flowchart LR
    A["claude --cwq"] -->|exports CODE_WITH_QURAN=1| B[Claude Code session]
    B -->|on each prompt| C[UserPromptSubmit hook]
    C --> D{activated?}
    D -->|yes| E[advance the pointer<br/>one ayah]
    D -->|no| F[do nothing]
    E -.->|state.json watch / poll| G["the reader<br/>(terminal pane or browser page)"]

Three moving parts:

  1. The shell wrapper replaces claude with a small function. claude --cwq sets CODE_WITH_QURAN=1 for that one invocation and runs the real binary via command claude — no recursion, and the variable never leaks into your shell. --cwq-browser additionally sets CODE_WITH_QURAN_SURFACE=web so that one session reads in the browser. It also runs code-with-quran start, which opens whatever the surface asks for — a tmux/zellij pane for tui, a browser tab for web, both for both — and is an instant no-op otherwise. shell-init writes a claude() function for bash/zsh and a function claude for fish; --shell=… overrides the $SHELL guess.
  2. The hook runs code-with-quran open --quiet --session-only on every UserPromptSubmit. --session-only makes it a no-op unless that variable is set. When it does run it advances the pointer in ~/.code-with-quran/state.json — once per prompt, or once per cooldownMinutes if you set one — and by default does nothing else (surface = tui).
  3. The reader watches state.json and jumps to the new ayah whenever the pointer moves — from the hook, or from another pane. code-with-quran read is the terminal reader (navigating with j/k/g writes the pointer back); code-with-quran serve is the browser reader — a zero-dependency local HTTP server on 127.0.0.1 that serves the bundled text as one page and polls the pointer. Both are deduped through a heartbeat file: one of each, shared across sessions.

Command reference

cwq is a short alias. --json on any command gives machine-readable output.

CommandDescription
readFull-screen terminal reader; follows the pointer
serveBrowser reader — local page on 127.0.0.1, RTL always right
startOpen the reader(s) for your surface (the wrapper runs this)
open-paneSplit off a terminal reader pane (tmux / zellij)
nowPrint the current ayah (Arabic + ref)
open (default)Advance the pointer (+ browser if surface includes it)
open --session-onlyNo-op unless started via claude --cwq (the hook uses this)
open --forceIgnore the cooldown
peekPrint the current ayah + URL without advancing
statusActivation state, reader state, progress, config
set <ref>Point at an ayah
next [n] / back [n]Move the pointer without rendering
resetBack to Al-Fatihah 1:1, counters cleared
config [key] [value]Get / set configuration
shell-init [--append | --remove] [--shell=…]Manage the claude wrapper
install / uninstallManage the Claude Code hook

The Qur'an text

  • data/quran-uthmani.json — the full Uthmani text, one entry per ayah (6236).
  • data/surahs.json — 114 surahs: names (transliterated + Arabic), meanings, ayah counts, revelation place.

Text: Tanzil Project (Uthmani), CC BY 3.0, retrieved via alquran.cloud. See data/QURAN-TEXT-LICENSE.txt. To rebuild:

curl -sS https://api.alquran.cloud/v1/quran/quran-uthmani -o /tmp/u.json
node scripts/build-quran-text.js /tmp/u.json

Development

npm test          # node:test — no network, no browser, no rc files touched
ModuleResponsibility
quran.jsSurah metadata, progression maths (advance/rewind, reference parsing, URLs)
quran-text.jsUthmani text lookup
arabic.jsZero-dep Arabic shaping + visual reordering for a bare terminal with no bidi
render.jsPure frame builder for the terminal reader (width-aware Arabic wrapping)
tui.jsThe terminal reader loop: raw input, state-file watch, alt-screen
web-reader.jsThe browser reader: local HTTP server + self-contained page
pane.jsSplit a reader pane in tmux / zellij (deduped)
state.js / config.jsJSON persistence under ~/.code-with-quran/
session.jsThe CODE_WITH_QURAN activation gate
reader-registry.js / web-registry.jsHeartbeat files so status knows a reader is running
open.jsCross-platform browser launch
shell.jsWrapper generation + rc-file editing
hook.jsClaude Code settings.json install / uninstall
index.jsOrchestration

License

Code: MIT. Qur'an text: CC BY 3.0 (Tanzil Project).

Files in the repo

Repository payload9 top-level entries
  • bin
  • data
  • scripts
  • src
  • test
  • .gitignore
  • LICENSE
  • package.json
  • README.md

Discussion (0)

Ask about usage, or say what you built with it

Sign in to join the discussion.

No comments yet. Be the first to say what this is good for.

More hooks

CLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies

80k

Warcraft III Peon voice notifications (+ more!) for Claude Code, Codex, IDEs, and any AI agent. Stop babysitting your terminal. Employ a Peon today.

5k
zachahn/
vomit

Clean up Claude's token vomit with a separate LLM. Save your tokens, Opus is hopeless

193

A pre-execution guard for AI coding agents. It blocks destructive Git and file system commands, plus common attempts to access sensitive files, before a tool call runs. Supports Amp Code, Antigravity CLI, Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot CLI, Grok Build, Hermes Agent, Kimi Code, OpenClaw, OpenCode, and Pi.

1.5k