whystaleچرا کهنه است
GitHubگیت‌هاب

for developers and AI coding agentsبرای برنامه‌نویس‌ها و ایجنت‌های کدنویسی · v0.1.0

Changed the code. Still the old behaviour?کد را عوض کردی. هنوز رفتار قبلی؟

The fix is right, but something is older than what it was built from: a dev server that started before .env changed, a build older than its sources, node_modules older than the lockfile, a client older than its schema. whystale finds it, says why, and prints the exact command to refresh it.اصلاح درست است ولی چیزی قدیمی‌تر از منبعی است که از آن ساخته شده: سرور توسعه‌ای که پیش از تغییر .env راه افتاده، بیلدی قدیمی‌تر از سورس، node_modules قدیمی‌تر از lockfile، کلاینتی قدیمی‌تر از اسکیمایش. whystale آن را پیدا می‌کند، دلیلش را می‌گوید و دستور دقیق تازه‌سازی را چاپ می‌کند.

  • Python
  • MIT
  • 0 deps
  • v0.1.0
shop-webledger of stale thingsدفتر چیزهای کهنه
  1. process

    python3 -u server.py (pid 195089 :48345): started before the files it reads changed

    started 17:29:46 → .env + package-lock.json changed +4s$ kill 195089 && python3 -u server.pySTALEکهنهFRESHتازه
  2. deps

    node_modules installed state is older than package-lock.json

    installed 15:29:47 → package-lock.json +2h 00m$ npm ciSTALEکهنهFRESHتازه
  3. build

    dist is older than its sources

    built 15:59:47 → src/checkout.js +1h 00m$ npm run buildSTALEکهنهFRESHتازه
  4. generated

    Prisma client is older than its schema

    generated 15:29:47 → prisma/schema.prisma +1h 45m$ npx prisma generateSTALEکهنهFRESHتازه

The hourglass is time since you changed the source. Click a line to run its fix.ساعت شنی زمانِ گذشته از تغییر منبع است. روی یک سطر بزنید تا راه‌حلش اجرا شود.

The problemمسئله

Changed the code but it still behaves the old way? whystale finds what is older than what it was built from.کد را عوض کردید ولی هنوز مثل قبل رفتار می‌کند؟ whystale پیدا می‌کند چه چیزی از منبعش قدیمی‌تر است.

The problemمسئله

The fix is correct, but "it did not work": the dev server never restarted after .env changed, dist/ was not rebuilt, node_modules was not reinstalled after a git pull, the Prisma, protobuf or OpenAPI client was not regenerated. People and AI coding agents guess, then "fix" correct code again and again.اصلاح درست است ولی «کار نکرد»: سرور توسعه بعد از تغییر .env دوباره راه نیفتاده، dist/ دوباره ساخته نشده، node_modules بعد از git pull دوباره نصب نشده یا کلاینت Prisma، protobuf و OpenAPI دوباره تولید نشده. آدم‌ها و ایجنت‌های کدنویسی حدس می‌زنند و بارها کد درست را «درست» می‌کنند.

What it doesچه می‌کند

A read-only scan that finds what is older than what it was built from and says why: processes that started before an env file, lockfile or config they read changed; build output older than its sources; installed dependencies older than the lockfile (compared by version); generated code older than its schema (Prisma, protobuf, OpenAPI, GraphQL codegen). Content checks clear false alarms such as a touched but identical file. It prints the exact refresh command and exits 3 when something is stale.یک اسکن فقط‌خواندنی که پیدا می‌کند چه چیزی از منبعش قدیمی‌تر است و دلیلش را می‌گوید: فرایندی که پیش از تغییر فایل env، قفل یا پیکربندی‌ای که می‌خواند شروع شده؛ خروجی بیلد قدیمی‌تر از سورس؛ وابستگی‌های نصب‌شده قدیمی‌تر از lockfile (با مقایسهٔ نسخه)؛ کد تولیدشده قدیمی‌تر از اسکیما (Prisma، protobuf، OpenAPI، GraphQL codegen). بررسی محتوا هشدار اشتباه را پاک می‌کند، مثل فایلی که فقط touch شده ولی یکسان است. دستور دقیق تازه‌سازی را چاپ می‌کند و وقتی چیزی کهنه باشد با کد ۳ خارج می‌شود.

  • 4۴kinds of staleness: process, build, deps, generatedنوع کهنگی: فرایند، بیلد، وابستگی، کد تولیدشده
  • 140۱۴۰tests, with real processes and a real serverآزمون، با فرایند و سرور واقعی
  • 0۰dependencies, read-onlyوابستگی، فقط‌خواندنی

Demoنمایش

A real scan of a real (temporary) projectاسکن واقعی یک پروژهٔ واقعی (موقت)

whystale --demo builds a temp project, starts a real server that reads .env once, edits .env and the lockfile, shows the server still serving the old value, and runs the scan. The timeline below is drawn from the times in that run (docs/demo.txt).‎whystale --demo‎ یک پروژهٔ موقت می‌سازد، سرور واقعی‌ای راه می‌اندازد که .env را یک بار می‌خواند، .env و lockfile را ویرایش می‌کند، نشان می‌دهد سرور هنوز مقدار قدیمی را می‌دهد و اسکن را اجرا می‌کند. خط زمانِ زیر از زمان‌های همان اجرا (docs/demo.txt) کشیده شده است.

Bars use a log scale; times are from the demo run.نوارها در مقیاس لگاریتمی‌اند؛ زمان‌ها از همان اجرای نمایش‌اند.

Full unedited output of the demoخروجی کامل و ویرایش‌نشدهٔ نمایش
$ whystale --demo
whystale demo - everything below is real: files in a temp dir and a spawned process.

1. creating a tiny project in /tmp/whystale-demo-da_febxi/shop-web
2. started its dev server (pid 195089, port 48345); it read .env once, at startup
   GET / -> API_URL=http://localhost:8000
3. you edit .env (API_URL ...:9000) and `npm install` rewrites package-lock.json
   GET / -> API_URL=http://localhost:8000   <- the server still serves the OLD value
4. whystale shop-web

whystale 0.1.0 · /tmp/whystale-demo-da_febxi/shop-web
checked 7 files (walk) · 1 process(es) in project (proc)

STALE (4)

✗ process · python3 — `/usr/bin/python3 -u server.py` (pid 195089 :48345)
    why:    started 17:29:46, but 2 file(s) it reads at startup changed afterwards (latest 4s later)
    newer:  package-lock.json (lockfile) changed 4s after start
    newer:  .env (env file) changed 4s after start
    proof:  process start time vs file modification times
    note:   no reload behaviour is known for this process, so it most likely read the file(s) once at startup
    fix:    kill 195089
            cd /tmp/whystale-demo-da_febxi/shop-web && /usr/bin/python3 -u server.py

✗ deps · node_modules installed state (.package-lock.json) is older than package-lock.json
    why:    package-lock.json was modified 2h 00m after the last install (15:29:47); 1 package(s) differ, e.g. express locked 4.19.2 / installed 4.18.2
    newer:  package-lock.json (lockfile) changed 2h 00m after install
    proof:  file contents + modification times
    fix:    npm ci

✗ build · dist is older than its sources
    why:    dist was last written 15:59:47; 1 source file(s) changed after that (newest 1h 00m later)
    newer:  src/checkout.js (source) changed 1h 00m after build
    proof:  modification times
    fix:    npm run build

✗ generated · Prisma client is older than its schema
    why:    prisma/schema.prisma changed 1h 45m after node_modules/.prisma/client was generated (15:29:47); the schema stored with the generated client differs from the current one
    newer:  prisma/schema.prisma (schema/source) changed 1h 45m after generation
    proof:  file contents + modification times
    fix:    npx prisma generate

note: not a git work tree (or git missing): used a built-in .gitignore approximation to list files

4 stale, 0 maybe. Exit code 3.

(The demo always exits 0 when it works. Real scans exit 3 when something is stale.)
[exit code: 0]

Featuresامکانات

What it does, precisely.دقیقاً چه می‌کند.

01

A process older than its filesفرایندی قدیمی‌تر از فایل‌هایش

Finds dev servers and runtimes in the project that started before an env file, lockfile or config they read at startup changed. On Linux it also reads the process start environment, so a touched .env with unchanged values is cleared.سرورها و runtimeهای پروژه را پیدا می‌کند که پیش از تغییر فایل env، قفل یا پیکربندیِ خوانده‌شده در شروع راه افتاده‌اند. روی لینوکس محیط شروع فرایند را هم می‌خواند، پس .env ای که فقط touch شده و مقدارش عوض نشده پاک می‌شود.

02

Builds older than sourcesبیلد قدیمی‌تر از سورس

dist, build, out, .next, .nuxt, .output, .svelte-kit for Node packages and target/ for Rust, against the newest real source file. Tests, docs, .d.ts and git-ignored files do not count.‏dist، build، out، ‏.next، ‏.nuxt، ‏.output و ‏.svelte-kit برای بسته‌های Node و ‏target/ برای Rust در برابر تازه‌ترین سورس واقعی. آزمون‌ها، مستندات، ‏.d.ts و فایل‌های نادیده‌گرفته‌شدهٔ git حساب نمی‌شوند.

03

Installs older than the lockfileنصب قدیمی‌تر از lockfile

node_modules against package-lock, pnpm-lock or yarn.lock, and virtualenvs against requirements, poetry.lock or uv.lock, down to versions: "express locked 4.19.2 / installed 4.18.2".‏node_modules در برابر package-lock، pnpm-lock یا yarn.lock و virtualenv در برابر requirements، poetry.lock یا uv.lock، تا سطح نسخه: «express قفل 4.19.2 / نصب 4.18.2».

04

Generated code older than its schemaکد تولیدشده قدیمی‌تر از اسکیما

Prisma (also compares the schema stored with the client), protobuf, OpenAPI clients and GraphQL Code Generator, plus your own source-to-output pairs in .whystale.toml.Prisma (اسکیمای ذخیره‌شده کنار کلاینت را هم مقایسه می‌کند)، protobuf، کلاینت‌های OpenAPI و GraphQL Code Generator، به‌علاوهٔ جفت‌های سورس و خروجی خودتان در .whystale.toml.

05

Evidence, not proofشواهد، نه اثبات

Grace periods, content checks that can only clear a finding, and a "maybe" level for tools that reload themselves (Vite, Next.js, Django runserver). A clean project must produce zero findings; that is tested over random mtimes.مهلت تحمل، بررسی محتوا که فقط می‌تواند یافته را پاک کند، و سطح «maybe» برای ابزارهایی که خودشان بارگذاری دوباره می‌کنند (Vite، Next.js، Django runserver). پروژهٔ سالم باید صفر یافته بدهد؛ این روی mtimeهای تصادفی آزموده می‌شود.

06

Read-only and agent-readyفقط‌خواندنی و آمادهٔ ایجنت

No network, no daemons, nothing written. --json, --markdown for an agent, --watch to see transitions, exit code 3 when stale, and a ready AGENTS.md snippet.بدون شبکه، بدون سرویس پس‌زمینه و بدون نوشتن. ‎--json‎، ‎--markdown‎ برای ایجنت، ‎--watch‎ برای دیدن تغییر وضعیت، کد خروج ۳ وقتی کهنه باشد و قطعهٔ آمادهٔ AGENTS.md.

  • Python
  • /proc
  • git
  • Prisma
  • lockfiles

Install & quick startنصب و شروع سریع

Up and running in a minute.در یک دقیقه راه بیندازید.

  1. Install (Python 3.9+, Linux or macOS)نصب (پایتون ۳٫۹ به بالا، لینوکس یا مک)

    pipx install git+https://github.com/mrzroot/whystale
    # or run without installing:
    uvx --from git+https://github.com/mrzroot/whystale whystale --demo
  2. Try it offlineامتحان آفلاین

    whystale --demo     # a temp project, a real server that read .env once, real edits
  3. Scan a projectاسکن پروژه

    whystale                  # scan the current directory
    whystale ~/code/shop      # scan another project
    whystale --markdown --no-fail > /tmp/stale.md   # context for an AI agent
    whystale --watch          # re-scan every 2 s
  4. Use it as a gateاستفاده به‌عنوان گیت

    whystale --only deps,artifacts,generated   # exit 3 while anything is stale

How it worksچطور کار می‌کند

Four steps, no magic.چهار گام، بدون جادو.

List the filesفهرست فایل‌ها

With git when available (git ls-files --cached --others --exclude-standard), so ignored files never count; otherwise it walks the tree with a built-in .gitignore approximation.با git در صورت وجود (‏git ls-files --cached --others --exclude-standard)، پس فایل‌های نادیده‌گرفته‌شده هرگز حساب نمی‌شوند؛ وگرنه درخت را با تقریبی از .gitignore پیمایش می‌کند.

Find the processesیافتن فرایندها

On Linux it reads /proc (start time, cwd, cmdline, listening sockets). Elsewhere ps and lsof. Wrappers (npm run dev, sh, node vite) are grouped into one finding, judged by the newest member.روی لینوکس /proc را می‌خواند (زمان شروع، cwd، cmdline، سوکت‌های شنوا) و در جاهای دیگر ps و lsof. لفاف‌ها (‏npm run dev، ‏sh، ‏node vite) در یک یافته گروه می‌شوند و بر اساس تازه‌ترین عضو داوری می‌شوند.

Compare the pairsمقایسهٔ جفت‌ها

Pairs are plain data (file classes, runners that reload themselves, output directories) plus small per-ecosystem functions. A file must be newer by a grace period (2 s for processes, 5 s for files) before anything is reported.جفت‌ها داده‌ی ساده‌اند (کلاس فایل‌ها، اجراکننده‌هایی که خودشان بارگذاری دوباره می‌کنند، پوشه‌های خروجی) به‌علاوهٔ تابع‌های کوچک برای هر اکوسیستم. هر فایل باید به‌اندازهٔ یک مهلت تحمل تازه‌تر باشد (۲ ثانیه برای فرایندها، ۵ ثانیه برای فایل‌ها) تا چیزی گزارش شود.

Clear false alarms, then reportپاک‌کردن هشدار اشتباه، سپس گزارش

Cheap content checks can only clear a finding (touched .env with the same values, a lockfile whose versions match, an identical Prisma schema). What remains is stale (solid) or maybe (heuristic) with the exact fix; exit code 3 when stale.بررسی‌های ارزان محتوا فقط می‌توانند یافته را پاک کنند (‏.env که فقط touch شده، lockfile با نسخه‌های هم‌خوان، اسکیمای یکسان Prisma). آنچه می‌ماند stale (قطعی) یا maybe (حدسی) با راه‌حل دقیق است؛ کد خروج ۳ وقتی کهنه باشد.

Honest limitsمحدودیت‌های صادقانه

What it does not do. Please read.چه کارهایی نمی‌کند. لطفاً بخوانید.

  • Evidence, not proof. Everything starts from modification times; editors, touch, git checkout or restoring a cache can move an mtime without changing content. Content checks clear the common cases, not all (build output and most generated code have none).شواهد، نه اثبات. همه‌چیز از زمان تغییر فایل شروع می‌شود؛ ویرایشگرها، touch، git checkout یا بازیابی کش می‌توانند بدون تغییر محتوا mtime را جابه‌جا کنند. بررسی محتوا موارد رایج را پاک می‌کند، نه همه را (خروجی بیلد و بیشتر کدهای تولیدشده آن را ندارند).
  • Only processes whose working directory is inside the project are seen. A server started elsewhere, inside a Docker container, or one that changed its cwd is invisible.فقط فرایندهایی دیده می‌شوند که پوشهٔ کاری‌شان داخل پروژه است. سروری که جای دیگر یا داخل کانتینر داکر راه افتاده یا cwd خود را عوض کرده دیده نمی‌شود.
  • Edits to source code are not compared with process start in v0.1: many processes legitimately re-read source on every request.ویرایش سورس‌کد در v0.1 با زمان شروع فرایند مقایسه نمی‌شود: بسیاری از فرایندها هر درخواست سورس را دوباره می‌خوانند.
  • Builds: Node (dist, build, out, .next, .nuxt, .output, .svelte-kit) and Rust (target/) only. Deps: bun, composer, bundler, Cargo and Go caches are not checked. Add your own [[artifact]] rules in .whystale.toml.بیلدها: فقط Node (‏dist، ‏build، ‏out، ‏.next، ‏.nuxt، ‏.output، ‏.svelte-kit) و Rust (‏target/). وابستگی‌ها: کش bun، composer، bundler، Cargo و Go بررسی نمی‌شود. قاعدهٔ [[artifact]] خودتان را در .whystale.toml بیفزایید.
  • Linux is the primary target. The macOS ps/lsof path is unit-tested against recorded output, and CI has a macOS job, but it has not been run on a real Mac. Windows is unsupported.لینوکس هدف اصلی است. مسیر ps/lsof در مک با خروجی ضبط‌شده آزموده شده و CI یک کار macOS دارد ولی روی مک واقعی اجرا نشده است. ویندوز پشتیبانی نمی‌شود.

How it comparesمقایسه با ابزارهای دیگر

Closest things, and the difference.نزدیک‌ترین‌ها و تفاوت‌شان.

No existing tool found as of Oct 2026تا مهر ۱۴۰۵ (اکتبر ۲۰۲۶) ابزار مشابهی پیدا نشد that gives a read-only, cross-ecosystem report of what is older than what it was built from, tied to running processes.که گزارش فقط‌خواندنیِ چندزبانه از «چه چیزی از منبعش قدیمی‌تر است» را در ارتباط با فرایندهای در حال اجرا بدهد.

This is the outcome of searches of GitHub, npm, PyPI and the web on 18 Oct 2026, not a guarantee: search indexes are incomplete and this space changes weekly. If you know one, please open an issue and it will be linked here.این نتیجهٔ جست‌وجو در گیت‌هاب، npm، PyPI و وب در ۲۶ مهر ۱۴۰۵ است، نه تضمین: نمایه‌های جست‌وجو ناقص‌اند و این حوزه هر هفته عوض می‌شود. اگر موردی می‌شناسید لطفاً یک issue باز کنید تا اینجا پیوند شود.

ToolابزارWhat it doesچه می‌کندHow it differsتفاوت
devpilotSupervises dev servers (reload, health, file changes)سرورهای توسعه را نظارت می‌کند (بارگذاری مجدد، سلامت، تغییر فایل)Does not judge staleness from .env, lockfile, config or artifact times; whystale is a read-only report, not a supervisorکهنگی را از زمان .env، lockfile، پیکربندی یا خروجی نمی‌سنجد؛ whystale گزارش فقط‌خواندنی است، نه ناظر
nodemon, Vite, Next.js watchersEach reloads on its own set of filesهرکدام روی مجموعهٔ فایل‌های خودش بارگذاری دوباره می‌کندNone tells you what did not reload; whystale does, across stacksهیچ‌کدام نمی‌گوید چه چیزی بارگذاری نشد؛ whystale می‌گوید، روی همهٔ پشته‌ها
needrestartFinds system services still using outdated shared librariesسرویس‌های سیستمی را که هنوز از کتابخانه‌های مشترک قدیمی استفاده می‌کنند پیدا می‌کندSystem libraries only; whystale looks at your project's env, lockfiles, builds and codegenفقط کتابخانه‌های سیستم؛ whystale محیط، lockfile، بیلد و کدتولیدشدهٔ پروژهٔ شما را می‌بیند
npm ci, uv sync --lockedEnforce lockfile sync when you run themوقتی اجرا کنید همگامی با lockfile را اجباری می‌کنندThey do not reveal that a running process, a build or a generated client is behind; whystale tells you when to run themنشان نمی‌دهند فرایند در حال اجرا، بیلد یا کلاینت تولیدشده عقب است؛ whystale می‌گوید کی اجرایشان کنید

FAQپرسش‌های متداول

Questions people ask.پرسش‌هایی که می‌پرسند.

Will it cry wolf?آیا هشدار اشتباه می‌دهد؟

It tries not to. A file must be newer by a grace period, content checks clear touched-but-identical files, tools that reload themselves (Vite, Next.js, Django runserver) are downgraded to "maybe", and a clean project must give zero findings (tested over random mtimes). Use whystale -v to see what was cleared and why.سعی می‌کند ندهد. فایل باید به‌اندازهٔ مهلت تحمل تازه‌تر باشد، بررسی محتوا فایل‌های touch‌شدهٔ یکسان را پاک می‌کند، ابزارهایی که خودشان بارگذاری دوباره می‌کنند (Vite، Next.js، Django runserver) به «maybe» تنزل می‌یابند و پروژهٔ سالم باید صفر یافته بدهد (روی mtimeهای تصادفی آزموده شده). با ‎whystale -v‎ ببینید چه چیزی پاک شد و چرا.

Does it change anything?آیا چیزی را تغییر می‌دهد؟

No. It is read-only: no network, no daemons, nothing written. It prints the refresh command; you run it.نه. فقط‌خواندنی است: بدون شبکه، بدون سرویس پس‌زمینه و بدون نوشتن. دستور تازه‌سازی را چاپ می‌کند؛ شما اجرایش می‌کنید.

How does an AI agent use it?ایجنت هوش مصنوعی چطور از آن استفاده کند؟

whystale --markdown --no-fail gives a paste-ready report, --json is machine-readable, and exit code 3 means something is stale. Paste docs/AGENTS.snippet.md into AGENTS.md or CLAUDE.md so the agent checks before it "fixes" correct code again.‎whystale --markdown --no-fail‎ گزارش آمادهٔ چسباندن می‌دهد، ‎--json‎ ماشین‌خوان است و کد خروج ۳ یعنی چیزی کهنه است. فایل docs/AGENTS.snippet.md را در AGENTS.md یا CLAUDE.md بگذارید تا ایجنت پیش از اینکه دوباره کد درست را «درست» کند بررسی کند.