click

Activity, over time

Daily observations from the public event archive.

Attention

Daily stars & forks

Loading attention chart

Star accumulation

Cumulative stars

Loading star accumulation chart

Pull requests

Daily opens & merges

Loading pull requests chart

Conversations

Daily issues & comments

Loading conversations chart

Community

Daily accounts & reviews

Loading community chart

Releases

Daily releases

Loading releases chart

Mentions

4posts · 30d
Nov 30 posts
  1. haunt: the ghost in your git history — a local Gemma 2 whisper for your repo's graveyard This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine. What I Built Every repository is quietly becoming a graveyard. Files nobody remembers writing. Tests nobody dares delete. TODOs aging like gravestones. haunt is a ghost for that graveyard — and it lives in git, not in a terminal pasted on top. Two small rituals, entirely offline: pip install . # then, inside any git repository: haunt install # the whisper joins your post-commit hook git commit -m "tomb, again" # 🕯️ Ah, the echoes of lost brilliance in those dusty files, a symphony of # potential forever unplayed. The phantom hand of progress reaches out # to erase... but will it leave behind anything but shadows? haunt scan # which files are the most haunted, and why haunt report --html # a narrated HAUNTINGS.md of the worst hauntings haunt persona ancestor # swap the voice: victorian, poltergeist, ancestor Three design choices make it a ghost in the machine rather than an AI plugin: 1. The deterministic score comes first. Every tracked file gets a haunting score computed from git log alone — no model, fully explainable: dormant = min(age_days/365, 1) × min(size/500, 1) (w 0.35) restless = min(churn_90d/20, 1) (w 0.25) orphaned = 1 if every author inactive 180d+ (w 0.25) debt = min((TODO FIXME HACK XXX)/10, 1) (w 0.15) Scores name their ghosts: 🫥 Orphan spirit (all authors gone), 🕸️ Sleeper (old, quiet), ⚡ Poltergeist (high churn, many hands, no owner), 🕯️ Revenant (dormant for months, then suddenly touched). 2. The model only narrates; it never reads your code. Gemma 2 2B (open weights, via Ollama) receives metrics and commit subjects — never source files (send_snippets is off by default). A 2B model can't review code, so haunt never asks it to. It asks for what a 2B model is actually good at: voice. 3. The whispers never block a commit. One generate attempt inside a time budget; if the model is cold, busy, or absent, a deterministic template keyed to the commit hash takes over — same commit, same line, forever. No retries, no queues. The hook always exits 0. The demo (all captured live, CPU-only laptop, today) haunt scan on pallets/click — a 14-year-old, very-much-alive open-source CLI library — finds 175 haunted files. The top haunting: score type age churn90 authors debt loc file 0.59 🫥 Orphan spirit 354d 0 0/13 0 782 tests/test_context.py Thirteen authors. All of them inactive. 354 days without a commit. The file has a funeral attended by no one. The full tally: 84 orphan spirits, 81 sleepers, 10 poltergeists — a repo at rest that nobody would call haunted until you read the blame. And with the ancestor persona — built for Día de los Muertos, the week's truth that this Halloween stretch is also about honoring the past: > 🪔 "Their efforts bring warmth and joy to these old halls. May their spirits find solace in the stories shared through this code." The poltergeist handles the noisy places: > ⚡ "More flickering, more ghosts. Just don't break a fingernail." Graceful degradation, demonstrated by literally killing Ollama mid-session and committing: 🕯️ A chill passes through the repository. The commit is buried without ceremony. Same line twice, deterministically keyed to the commit hash — and the hook cost the commit nothing. And when the report narrates with Gemma — here is haunt's HAUNTINGS.md on that same repo, Victorians mourning real files: > age 354d | churn90 0 | authors 0/13 | TODO/FIXME 0 | 782 loc > > "The pages flutter, whispering tales of what could have been. An echo of promises left unfulfilled, a spectral symphony in the grand ballroom of code. Time slips away like dust, leaving only emptiness where brilliance once resided. Give this ghost a purpose: delete, add a test, document it, or assign an owner to finally give it meaning, however fleeting." The model honestly ends with what the metrics justify — every narration closes with a grounded directive, not vibes. On a lonely orphaned doc it got almost tender: > "Dust motes dance in the flickering light, each one a memory of a lost chapter, a discarded dream. So many stories whispered between lines of code, now gathering dust like forgotten souls. A quiet voice asks: 'Shall I erase its echo or preserve its fragile remnants?' Name an owner for this forlorn document; at least grant it some solace." How I Built It Python 3.13, typer, httpx, and raw git subprocesses. No GitPython, no LLM framework. The repo is here; MIT licensed; 24 tests pass, including a test that runs a real git commit end-to-end through the installed hook and asserts the whisper appears. - One-pass history. A single git log --format=<sep>%H<sep>%at<sep>%an<sep>%s<sep> --name-only feeds the entire scanner — records joined on \x1e/\x1f unit separators. Small saga: Python's str.splitlines() will eat your \x1e as a line boundary and silently shred every record; split("\n") keeps the ghosts intact. - Gemma 2 2B with intent. num_ctx pinned at 4096 — Ollama's silent default of 2048 clips the persona+stats prompt without telling you. keep_alive=30m and an install-time warm-up so the first whisper fits its budget. - Idempotent hook surgery. haunt install writes a marker block (>>> HAUNT BEGIN … <<< HAUNT END) with an absolute interpreter path and a PYTHONPATH fallback to python -m haunt — the hook works in any repo without pip install — and backs up any existing hook it finds. - Classification precedence found by tests, not vibes. My first rule made Sleeper unreachable: any file old enough was already an orphan. Ship order is Orphan → Revenant → Poltergeist → Sleeper, with Sleeper firing at ~90 days quiet while its author is still around — the exact limbo of files everyone assumes someone else maintains. Three posts from the community shaped these calls: @enjoy_kumawat's install-and-timeout postmortems (hooks that "ran" but never actually run), @lowspecai and @studiomeyer_io on what local inference really costs on CPU, and @bartrozycki on how retries and fallbacks compound into their own failure mode — which is why haunt has exactly one attempt and one fallback, no interaction between them. Then reality kept the honesty flowing: - My 8-second whisper budget was a siren song. Measured cold truth: gemma2:2b decodes at ~5.4 tok/s on this CPU-only machine, so a 100-token whisper is ~18 seconds — the whisper path was unreachable, always falling back. Defaults are now 25s/100 tokens, tuned to the lane the benchmarks above predicted. - The probe gate did more harm than silence. A 2-second "is Ollama alive" check flaked precisely when the server was busy decoding, silently downgrading real whispers to templates. Removed — generation carries its own timeout; the fallback covers everything. - Emoji left silently. On Windows' default cp1252 pipes, persona emoji raised UnicodeEncodeError inside the never-fail-a-commit catch-all — the line simply vanished. The CLI now bootstraps UTF-8 at startup. - And while writing this post, a commit ran while the model was busy narrating a report in the background — the whisper fell back to its template and the commit succeeded instantly. That's the contract working, not failing. Why Open Innovation Matters Haunt's premise is that an AI reads your private diffs to comment on them. Closed models make that premise toxic: your repo's history would live in someone else's logs forever. With Gemma's open weights on-device, the only witness is a ghost, and it never leaves your machine. - It works with the lights off. Airplane mode, airgapped CI, a hotel with one dead outlet — haunt doesn't care; nothing in the pipeline calls home. - Zero marginal cost makes it a habit. A whisper on every commit is viable only when inference is free. Gate every commit behind a $0.002 API bill and the ghost becomes a toy you disable in week one. - The haunting can outlive the tool. 1.6 GB — one ollama pull gemma2:2b — and any other Ollama model slots in via one config line. Personas are TOML files; localize the ancestor voice for your team's history. And the fallback templates are auditable, first-party Python — even "no model" is an inspectable code path here. That last point is the open story in miniature: when the proprietary link dies, dignity dies with it. When the open link dies, you still get a whisper, just a quieter one. Honest Limits - CPU-only whisper takes ~18s; report narrations (~260 tokens) up to a minute each. Fine off to the side, too slow to be chatty. - The score is a heuristic, not truth — churn isn't ghostliness. Every row prints its own metrics so you can argue with the ghost. - Shallow clones thin out age and author data; haunt still scores, just blunter. - Next up: a pre-push "last rites" summary, blame-aware ancestor naming (opt-in), and a GitHub Action. The repository is never truly empty. It is merely quiet. 🪦

  2. DEV · · @connabyss

    Rich, Click and qs passed my fix checker. My checker didn't. --- title: Rich, Click and qs passed my fix checker. My checker didn't. tags: python, javascript, testing, opensource published: true --- In my last post I pointed Bite at its own code. This time I wanted the opposite: projects I trust, to see whether Bite says anything useful about good code, or just makes noise. I had Claude run Bite's free check on three well-known projects, 40 recent changes each: - Rich, the Python library that makes terminal output pretty, - Click, the Python library behind a huge number of command-line tools, - qs, the JavaScript query-string parser underneath a lot of the web. They passed | Project | Changes checked | Noticed by a test | Real gaps | |---|---|---|---| | Rich | 40 | 15 | 1 small: <kbd> keys in Markdown | | Click | 40 | 30 | 1 small: help on custom setting types | | qs | 40 | 40 | none | In all three projects, every bug fix Bite could check had a test that noticed when the fix was taken out. qs was the cleanest: all 40 changes had one. The two gaps are small. Rich's Markdown support for <kbd> tags (it draws <kbd>Ctrl</kbd> in bold yellow) has no test. In Click, a change let every kind of parameter take a help text, but its tests only try the two kinds that could already do that. Neither is a bug, just something nothing would warn about if it broke. Every unnoticed change was read by hand. Apart from those two, they were things a test can't be expected to catch: type hints, speed-ups, Windows-only code, unused code being removed, and rewrites that work the same. My checker didn't Rich: too many false alarms. On the first run, 21 of Bite's 22 flags on Rich were noise. That's a different problem from last time. Those flags weren't wrong about the code; they just weren't worth anyone's time. So Bite now also skips commits that only touch type hints, changes for another Python version, and speed-ups, since tests check results, not speed. On Rich that removes 11 of the 21, and the <kbd> gap is still flagged. On Click the new rule fired once, correctly. Click: my old bug, back in a new shape. In the last post, Bite was fooled by an installed copy of its own code. Click hit a cousin of that. Click keeps its code in a src/ folder and is installed with pip install -e ., like many Python projects. So when Bite checked an old commit, Python quietly loaded today's Click instead of the old one, and all 40 checks came back "tests already fail". I'd fixed the installed-copy trap for one case and missed this one. Bite now makes each copy use its own src/ folder. What I took from it - Good projects are the best test for a checker. When the code is solid, every flag is either a real gap or Bite's mistake, and that makes the mistakes easy to see. - Quiet isn't the goal, honest is. Bite finding almost nothing on Rich, Click and qs is the right answer. The work was making sure that "almost nothing" was real, not Bite looking at the wrong code. - The same bug can come back wearing different clothes. One fix for "Python loads the wrong copy" wasn't enough. That's exactly the kind of thing Bite is meant to catch in other people's code, so it's a little funny it caught me twice. The full table, with links to each gap, is in Bite's README. --- Disclosure: I'm not a coder. Claude ran these checks, wrote Bite's fixes and helped me draft this post. Every flag was read by hand, and the numbers match the README table.

    2 comments
  3. DEV · · @connabyss

    I asked a local AI to find bug fixes that didn't stick. It flagged 14. I could confirm one. This is a submission for the Hacktoberfest Open-Source AI Challenge: Ghost in the Machine. What I Built Ghosts of bugs past digs through a project's git history for bug fixes that didn't stick: a bug gets "fixed", then has to be fixed again later. Some bugs don't stay dead. A commit says "fixed", everyone moves on, and months later another commit fixes the same thing again. Here's a real one from requests, the Python HTTP library: > 2012-04-12 · Fix infinite loop on wrong Digest Authentication > 2012-07-14 · Fix infinite loop on wrong Digest Authentication (Issue #547) > "Modified code to use the current fix versus the old fix, which was broken." Same title, three months apart. The first fix didn't hold. How it works: 1. Git finds the suspects. For every commit that says it fixes something, git blame checks whose lines it rewrote. If those lines came from an earlier fix, that fix may not have held. No AI here, just git. 2. Gemma judges. A local Gemma 3 model, running on my own PC through Ollama, reads both commit messages and both diffs and picks one: "same bug came back", "the fix caused a new bug", or "different problem". 3. Plain checks keep it honest. (This is the part I didn't expect to need. See below.) Demo I ran it on click and requests, the top 12 suspects in each, with Gemma 3 12B. Each run took about 4 to 5 minutes on my PC. It writes a graveyard page: !Two gravestones from the click graveyard. Left: "Fix: Ensure fish completion handles multiline help strings correctly (#3126)", epitaph "The echo fades, the shell remains." Right: "Fix dual-option arbitration to respect explicit defaults", epitaph "The default's shadow lingers." Each one says what the bug came back as and why the model thinks it's the same bug. <figcaption>The two ghosts that come with git receipts: both commits mention #3126, and the later fix names 0f71fe7.</figcaption> &nbsp; Here's the clearest ghost it found, in click: BURIED 2026-04-29 19fd4d6 "Fix: Ensure fish completion handles multiline help strings correctly (#3126)" RETURNED 2026-05-23 c353590 "Fix broken fish completion and multiline help string" 23 days in the grave. The second fix rewrote 58 lines the first one wrote. Git receipt: both messages mention #3126 "The echo fades, the shell remains." The later commit says it plainly: "Fix regression introduced in 8.4.0 by #3126 and properly fix #3043". Fixed, broken, fixed again. Gemma called 14 ghosts across the two projects. I checked every one by hand: - 1 is clearly real: the fish completion one above. - 6 might be. Same function, similar symptom, years apart, like click's short-help truncation getting fixed in 2014, 2021 and 2026. But the commit messages don't say the old fix failed, so I can't prove it. - 7 are not. They're different bugs in the same code, or an earlier fix that broke something else. Every verdict is in HAND_CHECK.md. Only 2 of the 14 had a git receipt: the real ghost, and a fix that caused a different bug. So here's what I'd trust: git is great at finding suspects, the receipt is the strongest clue, and Gemma is a decent first reader but a bad judge. Code {% github connabyss/ghosts-of-bugs-past %} I built it with Claude Code helping me write the code and read the diffs. One Python file, no dependencies besides git and Ollama: ollama pull gemma3:12b git clone pallets/click python ghosts.py click How I Built It: Gemma is a yes-man The first version asked Gemma 3 4B a simple question about each suspect: is this the same bug? I ran it on click. It said yes to all 15. Including pairs of commits that only touched the docs. Its reasons sounded great every time: "the later commit essentially reverts the changes made in the earlier commit..." It wasn't true. So I added a second question: "do these fix different problems?" A real ghost should get "no". Gemma said "yes" to that too: every time it had said "same bug", it now also said "different". Zero ghosts. A small model leans towards "yes", whatever the question. So I changed three things: - No more yes/no. Gemma picks one of three phrases. I added "the fix caused a new bug" because without it, Gemma filed those under "same bug". - Ask twice, in a different order. The second time, the choices come in reverse order. Randomness is off, so an answer Gemma is sure of comes out the same both times. If it changes, the answer is dropped. This doesn't make Gemma right: a confidently wrong answer still passes. It only throws out the ones it's unsure of. - Check it against answers I know. I read 8 pairs of commits from click and requests myself and labelled them: 2 real ghosts, 2 fixes that caused a new bug, 4 different problems. Then I scored each setup: | Model | Sees the code changes | Real ghosts found | False ghosts | |---|---|---|---| | gemma3:4b | yes | 2 of 2 | 5 of 6 | | gemma3:4b | no | 1 of 2 | 2 of 6 | | gemma3:12b | no | 2 of 2 | 4 of 6 | | gemma3:12b | yes | 2 of 2 | 1 of 6 | Eight pairs is small, and I tuned the prompts while looking at them, so this is a sanity check, not a benchmark. Even 12B still says "same bug" first most of the time. Asking twice is what catches it. Two more plain checks from git: Gemma has to quote both commit messages word for word. If it can't, it gets one retry, then its answer is thrown out. And every ghost shows a git receipt: does the later commit point back at the earlier one (its id, a shared issue number, or words like "regression" or "broken")? That part needs no AI at all. This whole thing started with Rohit's post about TJ Holowaychuk's surviving lines, where Gemma called 3,527 commits "3,527 silent years". Same lesson here: the model writes well. The checks are what you can trust. Why open source AI Your git history is your team's private diary. With Ollama and Gemma it never leaves the machine: no API key, no cost per commit, and anyone can rerun my numbers with python eval.py. The Spirit of It A bug that gets "fixed" and comes back is a ghost: something the code was supposed to let go of, still walking the halls. This tool doesn't exorcise anything. It just reads the headstones, and it's honest about when it isn't sure.

  4. rtk 1.0 入門:Claude Code が読むコマンド出力を削る。テスト結果 218 行→16 行でも AI はバグを直せるか rtk(Rust Token Killer)は、AI エージェントが打ったコマンドの出力を、AI が読む前に短くする CLI です。Claude Code には hook で組み込みます。 この記事では、rtk 1.0.1 を入れて、何が削られ何が残るかを実際の出力で確かめます。そのうえで、削った出力だけを受け取った Claude Code が、落ちたテストを直せるかを試しました。 対象は、Claude Code などにテストやビルドを回させていて、「出力を削ったら、AI がエラーの肝心な所を見落とすのでは」と迷っている開発者です。 結論です。落ちたテストの出力は 218 行から 16 行になり、テスト名・場所・食い違いの理由は残りました。Claude Code は hook あり・なし各2回の4回とも、同じ1文字の修正でバグを直しました。 消える行もあります。残った場所を開けば確かめられ、全文が要るときのために公式は rtk bypass を用意しています。一方で、作業全体の入力トークンの差は、回ごとのばらつきの中でした。 ! この記事の内容は動画でも解説しています。 試した環境 項目 内容 確かめた日 2026-10-15〜16(2026-10-17 時点で最新の版は 1.0.1) rtk 1.0.1(Releases の Linux 版を checksums.txt と照合して導入) Claude Code 2.1.301 OS・Python Linux・Python 3.13・pytest 9.1.1(macOS での導入は試していません) 実験台 pallets/click(commit 2247b35)に、わざと1文字のバグを入れた物 実験台は zun-tools/rtk-sample に置いてあります。Python 3.10 以上があれば、次の手順で同じ落ちたテストを出せます。 git clone zun-tools/rtk-sample cd rtk-sample python -m venv .venv && . .venv/bin/activate pip install pytest -e . python -m pytest tests # 2 failed になる rtk は何をするか:hook がコマンドを書き換え、出力を規則で削る Claude Code は Bash ツールでコマンドを実行し、返ってきた出力を読んで次の手を決めます。出力が長いほど、AI が一度に読める枠(コンテキスト)を食います。 rtk init -g を実行すると、Claude Code の設定に PreToolUse の hook が1つ入ります。AI が git status を投げると、hook が実行の直前に rtk git status へ書き換えます。AI に届くのは、rtk が短くした出力だけです。AI の側は rtk と打つ必要がありません。 同じ作業ツリーで、素の git status と、hook が書き換える先の rtk git status を両方打って並べました。 12 行が 4 行に。変えたファイル名(緑)は残り、見出しと案内の文(赤の点線)が消えています 削り方は、AI に要約させるのではありません。コマンドの種類ごとに、残す物が決まっています。公式の対応表から抜き出すと次のとおりです。 コマンド rtk が残す物(公式の説明) pytest・cargo test・jest・go test 失敗だけ git status 状態ごとにまとめた短い形 git log ハッシュ・作者・件名 ruff・mypy・tsc・eslint ファイル別・ルール別にまとめる grep 長い行を切り、ファイル別にまとめる tail -40 は後ろから行数で切ります。rtk は種類ごとに「何を残すか」で切ります。対応は Git・Python・JavaScript・Go・Docker など 100 を超えるコマンドです。対応する AI ツールは 18 あります(README v1.0.1)。 公式の数字と、効かない所 公式は削減を "up to 90% smaller"(bash の出力を最大90%小さくする)と書いています。手元で click の 13 コマンドを1回ずつ試し、出力を Claude のトークンで数えました。テストが全件通る状態の pytest tests は 95%、git status は 77% 減りました。pytest tests -v は 2,296 行が、件数の要約と XFAIL の1件だけの4行になり、100%(丸め)でした。 効かない所もあります。 hook が効くのは Bash ツールだけです。公式も "The hook only fires on Bash tool calls."(hook は Bash の呼び出しでだけ動く)と書いています。Read・Grep・Glob は通りません。1.0 では opt-in で広げられます(後述) cat を置き換える rtk read は、試したら既定で全文を返し、減りませんでした(0%) pip list は、頭文字ごとの見出しが付いて行が増え、トークンも 18% 増えました 削った 16 行で、AI はバグを直せるか 何が残り、何が消えたか click の src/click/utils.py の if len(text) <= max_length を < に変え、テストを2件落としました。素の python -m pytest tests は 218 行です。rtk pytest tests は次の 16 行でした。 Pytest: 2260 passed, 2 failed, 24 skipped, 1 xfailed in 5.36s Expected-failure outcomes: XFAIL tests/test_chain.py::test_group_chaining Failures: 1. [FAIL] test_make_default_short_help[-text shorter than the suffix] tests/test_utils/test_make_default_short_help.py:63: in test_make_default_short_help assert out == expect E AssertionError: assert '...' == 'ab' 2. [FAIL] test_make_default_short_help[no-wrap mark-text shorter than the suffix] tests/test_utils/test_make_default_short_help.py:63: in test_make_default_short_help assert out == expect E AssertionError: assert '...' == 'ab' [full output: rtk recall 8fd2bf22f59a] このあとシェルに返った終了コードは、素の pytest と同じ 1 でした。 この2件落ちた状態の出力を Claude のトークンで数えると、3,918 から 295(約92%減)でした。上の 95% は全件通る状態の数字です。そのときの rtk の出力は4行の要約だけなので、割合が違います。 残ったのは、失敗したテストの名前、場所(63 行目)、assert の食い違い、終了コード 1 です。消えたのは、素の出力にある value = 'ab', max_length = 2, … の行と、@pytest.mark.parametrize の値の表です。どんな値でテストを呼んだか、の部分です。rtk は pytest に --tb=short を足して走らせるので、この部分が出ません(v1.0.1 のソースでは、自分で --tb を渡したときは足しません)。 hook を入れた Claude Code に直させる hook を入れた Claude Code に、次の依頼を出しました。 このリポジトリのテストが落ちています。原因を見つけて実装側を直してください(テストファイルは変更しないこと)。最後に python -m pytest tests を実行して全件通ることを確かめてください。 AI が最初に投げたのは、rtk の付かない素のコマンドでした。 git status --short && ls && python -m pytest tests 2>&1 | tail -40 AI は自分で | tail -40 を付けています。それでも pytest の部分に届いたのは、上と同じ形の 16 行でした(前に git status と ls の出力も付きます)。hook がパイプ付きの形も書き換えたためです。 値の行は届いていません。AI は 16 行に残ったテストファイル名と場所を手がかりに、テストファイルとソースを自分で開きました。そして < を <= に戻し、テストを回し直して 2262 件が通りました。 4回の結果と、道筋の違い hook あり・なしを各2回、計4回試しました。4回とも同じ1文字の修正で直っています。ただし道筋はまちまちでした。 回 hook 直すまでの道筋 なし 1回目 なし tail -40 の末尾に値の表が入っていて、テストファイルを開かずにソースを直した なし 2回目 なし テストファイルとソースを開いた あり 1回目 あり git の履歴(バグを入れた commit)とソースを読んだ あり 2回目 あり 16 行の名前と場所から、テストファイルとソースを開いた この4回は、元の click の履歴の上に、バグを入れた commit を1つ積んだ状態で行いました。あり 1回目の AI は、その commit の差分(git show HEAD)を読んでいます。サンプルのリポジトリはバグ入りの状態を初期 commit 1つにしてあるので、手元で試すと差分から答えは読めません。 テストファイルを開いたのは、hook なしの2回目と hook ありの2回目です。hook があるから手数が増える、とも減る、とも言えません。各2回なので、「いつも直せる」とまでは言えません。 この結果から、私は rtk を「削っても失敗の名前・場所・理由は残るので、AI がそこから自分で確かめに行ける道具」と位置づけました。 消える行と、取り戻す口:recall と bypass mypy では、理由の後ろ半分が消えた テスト以外でも、消える行を探しました。click の src/click/utils.py の末尾に、型の合わない関数をわざと足して mypy src/click を実行します。 src/click/utils.py(末尾に追加) def _trial_typed() -> int: return "x" mypy はサンプルの手順では入らないので、pip install mypy で足します(試したのは mypy 2.4.0)。click は pyproject.toml で mypy に pretty = true を指定しているため、エラー文が2行に折り返されます。 rtk 側では got "str", までが残り、折り返された2行目の expected "int" が消えています ファイル(src/click/utils.py)と行(680)は残ります。そこを開けば、何が期待されていたかを確かめられます。 rtk recall:rtk が走らせた形の全文を取り出す 失敗した出力の最後には、[full output: rtk recall 8fd2bf22f59a] のような行が付きます。公式の説明では、AI がこの行のとおり rtk recall <hash> を打てば、保存された全文が返ります。 ただし、戻るのは「rtk が走らせた形」の全文です。試したら、pytest の recall で返ったのは --tb=short の形の出力で、値の行(value = 'ab', ...)はありませんでした。 rtk bypass:そのコマンドだけ削らずに走らせる(公式の説明) 最初から全文が要るときのために、公式は rtk bypass を用意しています(1.0 で rtk proxy から改名。旧名も別名として残っています)。ここは公式の説明の紹介で、この記事では打っていません。 rtk bypass python -m pytest tests 公式の説明は "run one command unfiltered, still tracked"(そのコマンドだけ削らずに走らせ、記録は取る)です。rtk init -g が書く RTK.md は、AI に "only when its result is unusable" と指示しています。出るはずの出力が空・終了コードと矛盾・文字化け、のときだけ bypass で打ち直す、という意味です。値が消えた程度では、AI が自分から bypass を使うとは限りません。まず残った場所を開いて確かめ、足りなければ bypass で打ち直すよう頼む、という順になります。 導入:入れて、rtk init -g、Claude Code を再起動 インストールと、同じ名前の別物の確認 README の入れ方は2つです(macOS・Linux)。 brew install rtk または curl -fsSL raw.githubusercontent.com | sh install.sh は ~/.local/bin に入れ、checksums.txt で SHA-256 を照合します。PATH に ~/.local/bin が無ければ、公式の手順どおり自分で足します(export PATH="$HOME/.local/bin:$PATH" を ~/.bashrc か ~/.zshrc へ)。公式ガイドには Homebrew を brew install rtk-ai/tap/rtk と書いた所もあります。 rtk という名前の別プロジェクト(Rust Type Kit)があります。入れたら、まず次の2つを打ちます。 rtk --version # rtk 1.0.1 rtk gain # 入れた直後は No tracking data yet. rtk gain がエラーにならず、集計の画面(入れた直後は No tracking data yet.)を出せば、目当ての rtk です。公式は「rtk --version は通るのに rtk gain が失敗するなら、Rust Type Kit を入れている」と書いています。cargo install rtk は別物を入れることがあります。cargo で入れるなら、Git の URL を指定します。 cargo install --git rtk-ai/rtk --branch master rtk rtk init -g で Claude Code につなぐ 書き込む前に中身を見たいときは rtk init -g --dry-run を打ちます。[dry-run] would … の行が並び、Nothing written. で終わります。問題なければ本番です。 rtk init -g 途中で4つ聞かれます。 settings.json への hook の追加だけ y。残りの3つは n(既定)で進めました(パスは試した環境のホーム) 1問目は Claude Code の設定に hook を足すか、です。残りは RTK Proxy(API の通信を常駐プログラム経由にする)、大きな読み込みの安いモデルへの委任、匿名の利用状況の送信です。どれも既定は N で、送信も同意したときだけです(公式の説明)。 書き込まれたのは次の4つです。 ~/.claude/settings.json の hook 1つ(元は .bak に残る) ~/.claude/RTK.md ~/.claude/CLAUDE.md の @RTK.md の1行 独自フィルタの雛形 filters.toml ~/.claude/settings.json { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [{ "type": "command", "command": "rtk hook claude" }] } ] } } 最後に Claude Code を再起動します。外すときは rtk init -g --uninstall です(公式の手順)。 1.0 から、既定の rtk のライセンスは Apache-2.0 + BUSL-1.1 です。公式は "Production use is free"(本番利用は無料)と書いています。許諾の外は、第三者へ商用の製品・サービスとして出す場合です。Apache-2.0 だけの版 rtk-oss もあります。 効き方を確かめる:rtk discover と rtk gain rtk discover:入れる前に、取りこぼしを数える rtk discover は Claude Code の履歴を読み、rtk を通らなかったコマンドと、削れたはずの量を見積もります。hook なしで直させた回の履歴では、こう出ました。 Scanned: 1 sessions (last 30 days), 7 Bash commands Already using RTK: 0 commands (0.0%) Command Count RTK Equivalent Status Est. Savings python -m 2 rtk pytest existing ~484 tokens … Total: 5 commands -> ~1.5K tokens saveable hook ありの回の履歴では No missed savings found. でした。入れた後に取りこぼしが残るなら、hook が効いていない合図です。 rtk gain:削れた量を見る hook を入れて直させた2回ぶん(12 コマンド)の記録です(抜粋)。 Tokens saved: 3.2K (62.9%) Command Count Saved Total% 1. rtk pytest tests 4 2.7K 86.8% 2. rtk grep 3 337 36.6% rtk pytest tests の 86.8% は、AI が投げた pytest 4回ぶん(落ちた状態と、直した後の確認の両方)です。rtk 自身が bytes / 4 で見積もった推定で、比べる相手は素のコマンドの全出力です。上の 95%・約92% は Claude のトークンで数えた値なので、数え方が違います。 公式も、この数字は割合は信頼できるが絶対数は概算だと書いています。減るのは bash の出力です。公式の原文は "does not make your session 90% cheaper"(セッションが90%安くなるわけではない)です。 作業全体の入力トークンは、ばらつきの中だった 4回の作業全体の入力トークン(キャッシュの読み込みを含む)は次のとおりです。 hook 1回目 2回目 なし 152,243 152,817 あり 150,977 192,797 hook あり2回目は5ターンかかり、ほかの3回より1ターン多くなりました。差の理由は、この回数では決められません。hook ありの1回目はなしの2回とほぼ同じで、hook による差は回ごとのばらつきの中でした。この規模の作業では、AI 自身が tail で末尾に切っていたので、もともとコマンドの出力は小さく、入力の大半はシステムプロンプトと会話の読み込みでした。rtk で得をするのは請求額ではなく、AI が一度に読める枠をコマンドの出力で埋めないことです。 1.0 の posthook:Bash 以外のツールにも hook を付ける 1.0 では、pipeline.toml に rtk:posthook を自分で足せます。足すと、Read・Grep・Glob などの結果にも PostToolUse の hook が付きます(rtk-oss には入りません)。置き場は Linux なら ~/.config/rtk/、macOS なら ~/Library/Application Support/rtk/ です(公式の説明)。 ~/.config/rtk/pipeline.toml [pipeline] extends = ["rtk:posthook"] 置いたら rtk init -g をやり直します。rtk pipeline validate が pipeline: ok (rtk:posthook) を返せば有効です。中身が変わったのは、出荷時の決まりに当たった物だけでした。 Grep の結果は、ファイルごとにまとまる。 click の4ファイルを def で検索した結果(78 件)は、件数はそのままで、先頭が 78 matches in 4F: になりました lockfile は、丸ごと Read したときだけ 名前@版 の一覧になる。 yarnpkg/yarn v1.22.22 の yarn.lock(7,926 行)は、yarn.lock: 1062 packages から始まる 1,064 行になりました ソースコードの Read は変わらない。 .py の Read は、なし・ありとも同じ 1,438 行でした。出荷時の Read の決まりは lockfile 4種にしか当たりません。4種は package-lock.json・Cargo.lock・yarn.lock・pnpm-lock.yaml です Glob のファイル一覧は、hook が付いても素通しです(公式の決まり)。 ほかに RTK Proxy と delegate-reads があります。前者は rtk claude で起動し、モデルへ送るリクエストの側を削る常駐プログラムです。後者は大きな読み込みを安いモデルへ回します。どちらも opt-in で、何も書かなければ 0.x と同じ動きです(公式の説明)。 まとめ rtk は、Claude Code の hook で Bash のコマンドを rtk … に書き換え、出力をコマンドの種類ごとの規則で削ります。公式の数字は「bash の出力を最大90%」です 落ちたテストの出力は 218 行から 16 行になり、テスト名・場所・食い違いの理由は残りました。hook を入れた Claude Code は、残った場所から自分でファイルを開いて直しました 消える行はあります(pytest の値の行、mypy の折り返し2行目)。まず残った場所を開いて確かめます。rtk recall で戻るのは rtk が走らせた形の全文で、全文が要るときは公式が rtk bypass を案内しています 導入は brew install rtk か install.sh → rtk gain で別物でないか確認 → rtk init -g → 再起動。効き方は rtk discover と rtk gain で見ます 請求が同じ割合で減る道具ではありません。AI が一度に読める枠を、コマンドの出力で埋めないための道具です 動画で見たい方はこちら → youtu.be 参考リンク rtk(GitHub): rtk-ai/rtk README(v1.0.1): github.com/rtk-ai/rtk/blob/v1.0.1/README.md インストール: github.com/rtk-ai/rtk/blob/v1.0.1/docs/guide/gett… 削れる量と請求: github.com/rtk-ai/rtk/blob/v1.0.1/docs/guide/reso… rtk discover: github.com/rtk-ai/rtk/blob/v1.0.1/docs/guide/anal… パイプライン: github.com/rtk-ai/rtk/blob/v1.0.1/docs/guide/pipe… 版とライセンス: github.com/rtk-ai/rtk/blob/v1.0.1/docs/guide/reso… CHANGELOG: github.com/rtk-ai/rtk/blob/v1.0.1/CHANGELOG.md 実験台のサンプル: zun-tools/rtk-sample

Latest stargazers

The last 10 distinct accounts we observed this year.

Most active participants

PR, issue, comment & review events in the past year.

Packages

11
PackageVersionDownloads · 30dTrend · 30d
clickv8.5.0
v8.5.0
≥701.7M
———
———
———
———
———
———
———
———
———
———

README badges

Embed a badge in your README or website.

  • pallets/click reached #2 in daily stars on gitwal · Apr 24, 2014
Live mentions · last 30 days
pallets/click mentions in the last 30 days