Niajee is Sheng for "what's up?". It is a Claude Code session-start hook that greets you with where you left off, then asks how you want to begin.
Claude Code starts every session with no memory of the last one. The usual fix is --resume, which replays the entire previous conversation. That works, but it is expensive, and most of what it replays has no value the next morning.
Niajee hands the model a small breadcrumb instead, and then gets out of the way.
The breadcrumb is invisible to you. A SessionStart hook writes to the model's
context, not to your terminal, so nothing is printed and nothing interrupts you.
You just start typing, and the reply already knows where things stood:
> the probe is still failing
Picking up from yesterday: Stage 2 finished and the model was chosen, and
Stage 3 was blocked on adb pending a probe rebuild. Let me look at the
current failure rather than assume it is the same one.
No menu, no recap, no "how would you like to start?". If you open with something
contentless like hi and there is genuinely mid-flight work, then it offers a
short picker. Otherwise it stays quiet.
The honest version first. If your habit is to type plain claude and start
working, Niajee does not save you anything. It adds about 350 tokens and one
line of orientation. The comparison below is against --resume, and it only
counts if resuming is something you actually do.
What Niajee is really for is the cold start. On a fresh session the model knows nothing about yesterday, so it either asks you what you were doing, or acts on a stale memory file and states something that is no longer true. The breadcrumb closes both for 350 tokens and about 200 ms. That is the claim: fewer confident wrong answers on the first turn, not a cheaper bill.
If you do resume habitually, the arithmetic below is the second reason.
Measured on a real 4.14 MB transcript:
What gets replayed on --resume |
Tokens | Share |
|---|---|---|
| Assistant prose and tool calls | ~83,400 | 59% |
| Your actual words | ~12,100 | 8.5% |
| Tool results (file dumps, command output) | ~45,800 | 32% |
| Total | ~141,300 |
You resume to avoid re-explaining yourself, but the part that is you explaining yourself is 8.5 percent of the bill. Niajee's breadcrumb costs roughly 350 tokens, and the expensive load becomes something you opt into with one keypress.
On a subscription plan this is not a dollar invoice. It is context you no longer have for the actual work, and rate limit budget spent on a conversation you already had.
A SessionStart hook cannot prompt you. Its stdin is the event payload and its stdout becomes context, with no terminal attached. So Niajee uses two hops:
SessionStart hook (Node, ~200ms)
├─ finds the previous transcript for this project
├─ extracts your last real prompt + the assistant's last reply
├─ adds git branch and uncommitted count
├─ emits a ~350 token breadcrumb
└─ emits an instruction: "orient yourself, then stay quiet"
│
▼
You type your task. The reply is already oriented.
│
▼
Mid-task, if Claude needs a fact the breadcrumb lacks,
it runs `askpast` on demand. Nothing expensive loads
until something is actually missing.
The hook deliberately does not summarise. It retrieves raw text and leaves the "Left at" inference to the model, which is why it runs in milliseconds instead of needing an LLM call at startup.
The escalation is the model's call, not yours. This is the design point. At session start neither of you knows which history will matter; that is discovered mid-task, by the model, when it catches itself guessing. So a startup menu asks the wrong person at the wrong time. Niajee's default is silence, and askpast is reached for on need.
Claude Code already has good session tooling, and you should know what it does before adding anything.
The session picker shows AI-generated titles, conversation summaries, git branch and file size, with Space to preview, Ctrl+B to filter by branch and Ctrl+A to search every project. It is genuinely good.
There is also a built-in resume dialog. On a Pro or Max plan, resuming a session that has been idle over an hour and exceeds 100,000 tokens offers Resume from summary, Resume full session as-is, or Don't ask me again. That covers a lot of what Niajee does.
Three things Niajee adds on top:
- It runs when you were not going to resume at all. Both the picker and the resume dialog require you to have already decided to resume, and to pick a session. Niajee greets you on a plain
claude. It changes the default rather than improving a path you already chose. - It never processes the history. The docs are explicit that on resume, "the next request processes the full history once no matter which of the dialog's options you pick". Resume-from-summary saves you on later requests, not on entry. Niajee reads 350 tokens off disk and sends nothing else.
- It has no thresholds. The built-in dialog needs Pro or Max, over an hour idle, and over 100k tokens. A 60k-token session from this morning silently full-replays with no dialog at all. Niajee has no gates.
Niajee produces context. Resume restores state. These are not the same thing, and the gap is large:
/resume |
Niajee | |
|---|---|---|
| Full history with tool results | yes | no, text only |
| Which files were read, what commands returned | yes | no |
| Model, permission mode, active goal, scheduled tasks | restored | not restored |
| Any session, searchable and filterable | yes | most recent only |
| Rewind, branch, fork | yes | no |
| Cannot misremember | yes | no, the summary is inferred and can be wrong |
So Niajee does not replace any of that. It routes to it.
The breadcrumb is triage, not an answer. Depending on what it tells you, the right move is one of four things, and Niajee's job is to make the cheap ones reachable and the expensive ones obvious:
| What you need | Use | Cost |
|---|---|---|
| Nothing, you remember | just start typing | 0 |
| To re-read the last reply | lastreply |
0, never touches Claude |
| One specific fact with tool results behind it | askpast "..." |
~one resume, context stays clean |
| The whole state back | claude --resume <id> |
full history in context |
Without something like this, the default is binary: resume everything, or remember nothing. The picker prints the claude --resume <id> handle so the fourth option is one paste away.
Requires Node.js and Claude Code. Tested on Windows with PowerShell 5.1.
git clone https://github.com/SeedeXR/niajee.git
cd niajee
./install.ps1The installer copies the files into ~/.claude, backs up your settings.json, and adds the hook entry without touching anything else. It is idempotent, so running it twice is safe.
Restart Claude Code, and the picker appears on your next new session.
Copy niajee.js to ~/.claude/hooks/, then add to ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{ "type": "command", "command": "node \"<HOME>/.claude/hooks/niajee.js\"; exit 0", "timeout": 10 }
]
}
]
}
}Use startup only. resume, clear and compact are not new sessions, so firing there is wasted work.
./install.ps1 -UninstallA companion command for the most common reason people resume: you walked away and never read the last answer.
lastreply # most recent session
lastreply -Back 1 # the one before (use this from inside a live session)It reads the transcript straight off disk and prints the reply to your terminal. It never involves Claude, so it costs nothing at all.
install.ps1 adds it to your PowerShell profile.
The breadcrumb carries no tool results, so it cannot tell you which files were read or what a command actually returned. When you hit that gap, do not guess and do not reload the whole session. Ask it.
askpast "what was the exact adb error?"
askpast -Back 2 "which files did we edit?"This runs claude -p --resume against the earlier transcript. That subprocess has the full history including tool results, and returns only the answer. Your current session's context stays clean.
A real example, asked of a 4.14 MB session whose breadcrumb knew none of it:
Q: name the exact llama-server behaviour that broke temp-0 determinism, and the exact numThreads value proven best on device
A: llama-server's prefix cache reuses cached KV instead of recomputing the prompt, which changes the floating-point reduction order and flips the argmax on near-ties, so greedy temp-0 decoding stopped being reproducible until
cache_prompt=false. The device value proven best isnumThreads=2(4.2 to 4.4 tok/s under load, ~5.5 bare).
[359,899 in / 163 out tokens, $3.37, 11.7s]
Be honest about the cost. That is roughly what one resume costs, and in raw tokens it is more, because the subprocess rebuilds the cache from scratch. What you save is not tokens, it is your context window.
So the rule is: one precise factual question, good trade. Three questions, just resume. Ask for a fact, not a summary. askpast suppresses transcript writes, so the session you query is not modified.
Things that cost real debugging time, in case you are writing anything that scrapes Claude Code transcripts:
- The current session's
.jsonlalready exists and is the newest by mtime. Exclude it bysession_id, or your breadcrumb describes the empty session you just opened. Get-Content -Tailis unusable on transcripts. Records holding tool results are frequently megabytes long, so materialising 600 of them as .NET strings took over 120 seconds. Seeking to a byte offset and decoding once takes about 290 ms. Roughly a 400x difference.- Strip the UTF-8 BOM before
JSON.parse. Some shells prepend one when piping, and the parse failure is silent. - The last user prompt is often filler like "continue" or "yes". Walk back for one that actually states intent.
- The last assistant record is often a
tool_useblock, not text. Walk back for actual prose. - Use local time, not
toISOString. A breadcrumb read at a glance should match the clock on the wall. - A SessionStart hook must never be load-bearing. Every failure path here exits 0 with no output. A hook that throws degrades every session in every project.
- This parses an internal format. The Claude Code docs state that the transcript entry format "is internal to Claude Code and changes between versions, so scripts that parse these files directly can break on any release". Niajee does exactly that. It is built to fail safe: every error path exits 0 with no output, so a format change costs you the breadcrumb, never the session. But it is unsupported and will need occasional maintenance.
- The breadcrumb is lossy and can be wrong. The "Left at" line is inferred from a text tail with no tool results in it. Treat it as orientation, not as truth.
- Niajee only ever looks at the most recent session. If you worked on two things yesterday, or want something from last week, use the session picker.
lastreplyis PowerShell, so it is Windows only for now. The hook itself is plain Node and is platform independent.- Claude Code deletes transcripts after
cleanupPeriodDays(default 30). Niajee can only see what survives. Raise it insettings.jsonif you want a longer tail. - The picker is skipped if your opening message is already a clear task, which is usually what you want but is not configurable yet.
MIT