Skip to content

Make a fresh machine reach parity: statusline, permissions, cloud-init - #8

Open
sgup wants to merge 1 commit into
masterfrom
portable-settings
Open

Make a fresh machine reach parity: statusline, permissions, cloud-init#8
sgup wants to merge 1 commit into
masterfrom
portable-settings

Conversation

@sgup

@sgup sgup commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Closes three of the five gaps that stood between this repo and "clone it, run it, done" on a brand-new Mac or box.

1. The statusline was linked but never registered

install.sh symlinked statusline-command.sh and left a comment saying registration was separate — so a fresh machine got the script and no statusline. Now tracked as:

"statusLine": { "type": "command", "command": "bash ~/.claude/statusline-command.sh" }

Verified ~ actually expands in that position, so a single string works on both platforms rather than needing per-machine absolute paths.

2. The permission allowlist was untracked

32 rules on the Mac, none in the repo — a new machine re-prompts for everything already approved. 22 are portable and are now tracked. The other 10 are one-off captures like:

Bash(cd "/Users/shridhar/Code/apps/Sand Patterns/…" __NEW_LINE_6eb6b275__ echo "=== RAIN SAMPLES ===" …)

Absolute paths and captured multi-line commands. Publishing those to a public repo helps nobody and would pollute every new machine, so they are filtered out. Behaviour flags come along too: effortLevel, theme, tui, autoCompactEnabled, autoUpdatesChannel, agentPushNotifEnabled, and the three skip* flags.

⚠️ Worth a conscious decision: this carries permissions.defaultMode: "auto". That is your current Mac setting, and it means a freshly provisioned machine starts in auto-accept mode. Say the word and I will drop defaultMode from the fragment so each machine opts in deliberately.

3. The cloud-config existed only in a chat log

A new box meant re-deriving it from scratch — including the - default trap that already cost one full rebuild. Now linux/cloud-init.yaml, carrying every lesson:

  • - default preserved in users:, with the reason stated, since omitting it suppresses the provider's key injection and can leave a box with no keys at all
  • the non-root user's authorized_keys seeded from root's provider-injected keys, not from github.com/<user>.keys — those are not necessarily the key your agent offers, which is exactly what broke the first attempt
  • no package_upgrade, which had delayed Tailscale behind a full apt upgrade; unattended-upgrades clears the backlog after boot instead
  • Automatic-Reboot "false" so a 6am restart never kills a long-running agent session
  • everything past user and network setup delegated to provision.sh, so the two cannot drift

Validated with cloud-init schema --config-file on a real cloud-init install: Valid schema.

Deliberately still untracked

hooks. The Mac drives a local Dynamic Island script (~/.claude/hooks/claude-island-state.py, itself not in this repo); the box drives atuin. Genuinely per-machine, so merging either one onto the other would be wrong.

Remaining gaps, for later

  • MCP servers (6) — needs its own PR; two carry credential env vars, so it must reference secrets by name rather than inline them into a public repo.
  • Skill content (~8 MB) — skill-lock.json is tracked but nothing consumes it. Either commit the content or write a restore script that re-clones from the pinned hashes.

Three portability gaps, found by asking what a brand-new Mac or box would
actually be missing.

install.sh linked the statusline script but nothing ever registered it, so a
fresh machine got the file and no statusline. The command is now tracked as
`bash ~/.claude/statusline-command.sh`; verified that ~ expands in that
position, so one string works on both platforms.

The permission allowlist was untracked, meaning a new machine re-prompts for
everything already approved. 22 of the 32 rules are portable and are now
tracked; the other 10 are one-off captures carrying absolute /Users paths and
__NEW_LINE_ markers, which would publish local paths and help no one.
Behaviour flags (effortLevel, theme, tui, autoCompact, the skip* set) come
along too.

The Hetzner cloud-config existed only in a chat log, so a new box meant
re-deriving it - including the `- default` trap that already cost one
rebuild. It is now linux/cloud-init.yaml, delegating everything past user and
network setup to provision.sh so the two cannot drift. Validated with
`cloud-init schema`.

hooks stay untracked on purpose: the Mac drives a local Dynamic Island script
and the box drives atuin. They are genuinely per-machine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant