I almost passed on the cute hand-drawn flowchart style, assuming it sat behind a subscription. It doesn't. The hand-drawn aesthetic is Excalidraw's default and only style, and it's completely free. The paid tier, Excalidraw+, is team cloud collaboration and version history — nothing to do with how the diagrams look.
mermaid.live is the same story: the official open-source editor for Mermaid.js, free, no credits, no pay-per-render. The "credit-based" impression usually comes from third-party SaaS tools that generate Mermaid from a prompt.
So going from a flowchart to a hand-drawn version costs nothing. Get your flowchart as Mermaid (write it, or hand a vision-capable AI a photo of your sketch), then paste it straight onto the Excalidraw canvas — it detects the syntax and pops a "Parse as Mermaid" import dialog. There is no Insert → Mermaid item in the hamburger menu or toolbar (those only have Open / Save / Export / Live Collaboration); the other entry point is the command palette (Ctrl/Cmd + /) → search Mermaid.
On Windows, when you open Terminal in a Vagrant VM, it sometimes runs in Administrator mode regardless of which shell you choose — even when you explicitly selected normal user mode.
The fix is to restore User Account Control (UAC) prompts:
- Open Control Panel → System and Security
- Under "Security and Maintenance", click "Change User Account Control settings"
- Move the slider back to the default: "Notify me only when apps try to make changes to my computer"
- Click OK, then confirm with Yes
When UAC is fully disabled (slider at "Never notify"), Windows bypasses the elevation prompt and grants administrative privileges silently — which causes every Terminal session to launch as Administrator. Restoring UAC to its default level re-enables the elevation check and lets normal user sessions work normally again.
tg-relay 的 inbound 路由依赖 tmux pane ID(%NN)——收到 Telegram 消息后,它调 tmux send-keys 把 /tmp/tg-*.md 注入对应 pane。mux.driver local 跑的是前台进程,没有 tmux pane,所以 relay 找不到投递目标,直接失败。
Outbound 没问题:notify_shuke 不依赖 tmux,local driver 下照常发 TG,reply index 里用 MUX_DRIVER_SLUG 代替 %NN 记录身份。问题只在 inbound。
可行路径:named FIFO + Stop hook exit 2
每个 local session 启动时用 slug 创建一个 named FIFO:
mkfifo /tmp/mux-tg-${MUX_DRIVER_SLUG}.fifo
tg-relay 看到 reply index 里的 pane ID 是 slug 而非 %NN,就写这个 FIFO 而非调 tmux:
echo "$message" > /tmp/mux-tg-${slug}.fifo
Claude Code 的 Stop hook 在每个 turn 结束时检查这条 FIFO:
# Stop hook
fifo="/tmp/mux-tg-${MUX_DRIVER_SLUG}.fifo"
if read -t 0.1 msg < "$fifo" 2>/dev/null; then
echo "$msg"
exit 2 # 拦住 stop,把消息作为 additionalContext 注入
fi
exit 0
exit 2 的语义:Claude 不停止,stdout 作为 additionalContext(system feedback)注入同一个 turn,Claude 继续处理。技术上不是新的 user message,是 same-turn 的 system context,但效果上 Claude 会读到并响应 TG 消息。
局限
- hook 只在 turn 边界触发。FIFO 里的消息要等当前 turn 结束才被拉取。如果turn结束时FIFO里是空的,那这个turn就正常结束了。没有机会再接到后续FIFO的内容。这是一个致命缺陷。让整个方案变得不再可行。
- additionalContext ≠ user message:conversation history 里这不是一条用户消息,边角行为可能和正常 TG 路由有差异。
- FIFO 阻塞:写端无读端时
echo > fifo 会阻塞,relay 需要用 O_NONBLOCK 或超时保护。
不完美,但架构上可行,不需要改动 Claude Code 本身。
On a corporate Windows box, git pull/git fetch keeps stopping to ask:
Unlink of file '.git/objects/pack/pack-305a05....idx' failed. Should I try again? (y/n)
The cause is a security agent — SentinelOne, ZScaler, Defender — holding an open handle on the old .idx files while Git tries to repack. Git for Windows wraps unlink/rename failures in a retry prompt, and you end up babysitting every pull, mashing n.
yes n | git pull works but you have to remember to prefix it every time. The permanent fix is one line in ~/.bashrc (the Git Bash one):
export GIT_ASK_YESNO=false
Git runs the value of GIT_ASK_YESNO as a command to decide whether to retry — a non-zero exit is treated as "n". false always exits non-zero, so every prompt is silently answered "no". It's cleaner than </dev/null redirection (works regardless of whether stdin is a tty) and doesn't touch the other interactive bits — commit-message editor, credential prompts — which go through different machinery.
Answering "n" just means Git leaves the locked old pack file on disk; the new pack is already live, so the repo is fine. Once the security agent lets go, a git gc sweeps up the leftovers.
If the prompts are frequent, this cuts down how often they fire — sometimes the lock is Git's own multi-threaded pack-objects, not the AV:
git config --global pack.threads 1
This is the silence-it companion to the heavier "it's an open handle, not a permission" diagnosis — same root cause (a process holding a handle), but here you just want the nagging to stop, not to hunt the locker down.
You run claude install, it prints "successfully installed! Version: 2.1.185", but claude --version keeps reporting the old 2.1.183. Reinstalling doesn't help.
The cause: on Windows you cannot overwrite a running .exe. The native installer downloads the new build into ~/.local/share/claude/versions/<ver> fine, but the final step — copying it onto the launcher at ~/.local/bin/claude.exe — fails silently because a live claude.exe process holds that file locked. The installer reports success on the download, not on the swap.
Confirm it's this by comparing checksums of the launcher against the version store:
sha256sum ~/.local/bin/claude.exe ~/.local/share/claude/versions/2.1.185
ls -la ~/.local/share/claude/versions/ # newest version is there, but bin/claude.exe is stale
tasklist //FI "IMAGENAME eq claude.exe" # the processes holding the lock
If the launcher hash matches an older version in the store, the swap never happened.
The clean fix is to exit every claude session and re-run claude install. But if you can't (e.g. you're driving from inside a claude session), use the fact that Windows lets you rename a locked file even though it won't let you overwrite it — the running process keeps its open handle, and a fresh file lands in the path:
cd ~/.local/bin
mv claude.exe claude.exe.old
cp ~/.local/share/claude/versions/2.1.185 claude.exe
chmod +x claude.exe
claude --version # 2.1.185
New shells immediately pick up the new binary; running sessions keep using the old one until restarted. Delete claude.exe.old once everything has been restarted.
Note that Git Bash's bare claude (no extension) is just shell resolution of claude.exe — there's only one physical file to replace, not two. This whole trap is more likely if you have autoUpdates: false in ~/.claude.json and update manually, since background auto-update would normally retry on the next launch when nothing is locked.