diff --git a/docs/sync-log.md b/docs/sync-log.md index 5cacd2b..37ebd00 100644 --- a/docs/sync-log.md +++ b/docs/sync-log.md @@ -6,6 +6,20 @@ context. --- +## [2026-05-06] sync @ Hans Air M4 + +Config: + - statusline: switch hostname source from `hostname -s` (returns generic "Mac") + to `scutil --get LocalHostName` (returns "Hans-Air-M4"), matching the + SessionStart machine-banner hook. User noticed the statusline read `@Mac` + instead of the actual machine name; root cause was the macOS default + smb-style hostname clobbering the more useful LocalHostName. + +Other drift deferred (Brewfile, .chezmoiscripts/*, dotfiles-sync.md command +edits) — needs its own dedicated sync pass. + +--- + ## [2026-05-05] security: rewrite history to scrub leaked SSH file @ Hans Air M4 Following the privacy-gate work in PR #72, decided to also retroactively scrub diff --git a/home/dot_claude/executable_statusline-command.sh b/home/dot_claude/executable_statusline-command.sh index a0104b3..05dd979 100755 --- a/home/dot_claude/executable_statusline-command.sh +++ b/home/dot_claude/executable_statusline-command.sh @@ -164,7 +164,7 @@ if [ -n "$duration_ms" ] && [ "$duration_ms" != "0" ]; then fi # --- Hostname --- -host=$(hostname -s 2>/dev/null) +host=$(scutil --get LocalHostName 2>/dev/null || hostname -s) [ -n "$host" ] && host_part=" ${DIM}@${host}${RESET}" || host_part="" printf '%b' "${BLUE}${dir}${RESET}${git_part}${model_part}${effort_part}${ctx_part}${rate_part}${duration_part}${host_part}" diff --git a/home/dot_claude/hooks/machine-banner/executable_machine-banner.sh b/home/dot_claude/hooks/machine-banner/executable_machine-banner.sh new file mode 100644 index 0000000..91d90f3 --- /dev/null +++ b/home/dot_claude/hooks/machine-banner/executable_machine-banner.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# SessionStart hook: emit "Machine: @ ()" +# so Claude Code always knows which physical box this session is on. +# Read by ~/.claude/settings.json -> hooks.SessionStart. +set -eu + +USER_NAME=$(whoami) +HOSTNAME=$(scutil --get LocalHostName 2>/dev/null || hostname -s) +MODEL=$(sysctl -n hw.model 2>/dev/null || echo unknown) + +printf 'Machine: %s@%s (%s)\n' "$USER_NAME" "$HOSTNAME" "$MODEL" diff --git a/home/dot_claude/modify_CLAUDE.md.tmpl b/home/dot_claude/modify_CLAUDE.md.tmpl index 43890ac..e1ea187 100644 --- a/home/dot_claude/modify_CLAUDE.md.tmpl +++ b/home/dot_claude/modify_CLAUDE.md.tmpl @@ -46,6 +46,25 @@ printf '%s\n' "$PREFIX" cat <<'MARKDOWN' +# Machines I work from + +The SessionStart hook prints `Machine: @ ()` so you always know which box you landed on. This table maps shorthand the user uses verbally to actual SSH targets. + +| Shorthand | Hostname / SSH alias | User | Role | +|---|---|---|---| +| air | mac-air (Hans-Air-M4) | tieubao | daily driver, Da Nang. MacBook Air M4. | +| mini | `ssh mini` (Tailscale) / `ssh mini-lan` (mDNS fallback) | server | Mac Mini M4 Pro 64GB, daemon-runtime account. Use for status checks, log inspection, and the one ADR-0012 grant: `kickstart -k system/foundation.d.hermes-agent` (passwordless). Anything else needs the `tieubao` user via `mini-tieubao`. | +| mini-tieubao | `ssh mini-tieubao` | tieubao | Same physical Mini, ops-script account. Passwordless `print` / `kickstart -k` / `bootout` / `bootstrap` against `system/foundation.d.*` per SPEC-032. **Use this in any script that needs broader launchctl verbs than `kickstart -k hermes-agent`.** Convention defined in SPEC-052. | +| egress-tokyo, trading-egress-tokyo | `ssh trading-egress-tokyo` | server | Vultr Tokyo VPS, trading egress. | +| egress | `ssh egress` (see `~/.ssh/config.d/egress.local`) | server | egress relay. | + +Resolution rules: + +- "the mini" / "mac mini" → `mini` if the work is daemon control / log tail / `kickstart -k hermes-agent`. `mini-tieubao` if the work is broader foundation.d.* manipulation (bootout, bootstrap, print on a non-hermes label) or needs `(server) ALL` run-as-server escalation. +- "this machine" / "here" → use whatever the SessionStart banner shows. If the banner contradicts the user's framing, surface the conflict before acting. + +The Mini hosts the ops-agent (`foundation.d.hermes-agent` LaunchDaemon, project at `/Users/server/dev/hermes-agent`) plus Ollama and `vps-mon-agent`. SPEC-032 specifies the substrate; ADR 0012 explains why `server`'s grant is narrow. + # Tool selection Durable rule for Claude Code. Applies to every session. Default to acting. Only ask when escalation triggers fire (see bottom). diff --git a/home/dot_claude/modify_settings.json b/home/dot_claude/modify_settings.json index 11df6dc..9e0f585 100755 --- a/home/dot_claude/modify_settings.json +++ b/home/dot_claude/modify_settings.json @@ -23,6 +23,9 @@ # "BLOCKED: Pipe-to-shell detected" -- block curl|wget | bash/sh/zsh # "BLOCKED: Destructive delete" -- block rm -rf /|~|$HOME # +# Managed SessionStart hooks (keyed by unique marker): +# "machine-banner.sh" -- prints "Machine: user@host (model)" +# # Note: `git push` to main/master/production is intentionally only a warning, # not a block. Solo workflow -- PR gating is not needed here. # The dedup list still strips any previously installed block hook on apply. @@ -95,6 +98,11 @@ echo "$INPUT" | jq \ {matcher: "Bash", hooks: [{type: "command", command: $git_push_warn_cmd}]}, {matcher: "Bash", hooks: [{type: "command", command: $rm_rf_block_cmd}]} ] + ), + SessionStart: ( + ((.hooks.SessionStart // []) | map(select( + (.hooks // []) | map(.command // "" | contains("machine-banner.sh")) | any | not + ))) + [{hooks: [{type: "command", command: "~/.claude/hooks/machine-banner/machine-banner.sh", timeout: 3}]}] ) }) '