diff --git a/README.md b/README.md index c26b6bd..3552b42 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,9 @@ nothing on Linux. | [`AGENTS.md`](AGENTS.md) | Shared context for every coding agent (branch discipline, secrets). Symlinked to `~/.codex/AGENTS.md`; Claude imports it via `@~/.dotfiles/AGENTS.md`. | | [`CLAUDE.md`](CLAUDE.md) | Claude Code global instructions (imports `AGENTS.md`). Symlinked to `~/.claude/CLAUDE.md`. | | [`claude/rules/`](claude/rules) | Claude Code rule files — model routing, Context7 doc lookups. Each is symlinked into `~/.claude/rules/`. | -| [`claude/settings.plugins.json`](claude/settings.plugins.json) | Marketplaces, enabled plugins, skill overrides. **Merged** into `~/.claude/settings.json` so machine-specific keys survive. | +| [`claude/settings.plugins.json`](claude/settings.plugins.json) | Portable Claude settings: marketplaces, enabled plugins, skill overrides, permission allowlist, statusline registration, behaviour flags. **Merged** into `~/.claude/settings.json` so machine-specific keys survive. | | [`claude/sync-plugins.sh`](claude/sync-plugins.sh) | Applies that fragment and installs the enabled plugins. Run by `install.sh`. | +| [`linux/cloud-init.yaml`](linux/cloud-init.yaml) | Cloud-config for a fresh VPS. Creates the user, joins Tailscale, then hands off to `linux/provision.sh`. | | [`claude/marketplaces.json`](claude/marketplaces.json) | Every plugin marketplace, source only. `settings.json` records only hand-added ones, so this is the complete list. | | [`claude/skill-lock.json`](claude/skill-lock.json) | Manifest of the `~/.agents/skills` set (source repo + pinned hash per skill). Reference only — not consumed by `install.sh`. | | [`install.sh`](install.sh) | Symlinks every dotfile from this repo into the right home location. | diff --git a/claude/settings.plugins.json b/claude/settings.plugins.json index 54a3b87..5546f5f 100644 --- a/claude/settings.plugins.json +++ b/claude/settings.plugins.json @@ -1,37 +1,10 @@ { - "extraKnownMarketplaces": { - "antigravity-cc": { - "source": { - "source": "github", - "repo": "simplybychris/antigravity-plugin-cc" - } - }, - "cloudflare": { - "source": { - "source": "github", - "repo": "cloudflare/skills" - } - }, - "expo-plugins": { - "source": { - "source": "github", - "repo": "expo/skills" - } - }, - "openai-codex": { - "source": { - "source": "github", - "repo": "openai/codex-plugin-cc" - } - }, - "RevenueCat": { - "source": { - "source": "github", - "repo": "RevenueCat/ai-toolkit" - } - } - }, + "agentPushNotifEnabled": true, + "autoCompactEnabled": true, + "autoUpdatesChannel": "latest", + "effortLevel": "xhigh", "enabledPlugins": { + "RevenueCat@RevenueCat": false, "agy@antigravity-cc": false, "clangd-lsp@claude-plugins-official": false, "cloudflare@claude-plugins-official": true, @@ -48,7 +21,6 @@ "plugin-dev@claude-plugins-official": false, "posthog@claude-plugins-official": false, "revenuecat-play-billing@RevenueCat": false, - "RevenueCat@RevenueCat": false, "stripe@claude-plugins-official": false, "supabase@claude-plugins-official": false, "superpowers@claude-plugins-official": true, @@ -57,6 +29,69 @@ "upgrading-expo@expo-plugins": false, "vercel@claude-plugins-official": false }, + "env": { + "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" + }, + "extraKnownMarketplaces": { + "RevenueCat": { + "source": { + "repo": "RevenueCat/ai-toolkit", + "source": "github" + } + }, + "antigravity-cc": { + "source": { + "repo": "simplybychris/antigravity-plugin-cc", + "source": "github" + } + }, + "cloudflare": { + "source": { + "repo": "cloudflare/skills", + "source": "github" + } + }, + "expo-plugins": { + "source": { + "repo": "expo/skills", + "source": "github" + } + }, + "openai-codex": { + "source": { + "repo": "openai/codex-plugin-cc", + "source": "github" + } + } + }, + "permissions": { + "allow": [ + "Bash(cat:*)", + "Bash(cd:*)", + "Bash(curl:*)", + "Bash(do echo -n \" $f: \" ffmpeg -i \"$f\" -af ebur128 -f null -)", + "Bash(do echo -n \"$f: \" ffmpeg -i \"$f\" -af ebur128 -f null -)", + "Bash(ffmpeg:*)", + "Bash(find:*)", + "Bash(npm run build:*)", + "Bash(npm run lint)", + "Bash(swift:*)", + "Bash(swiftlint:*)", + "Bash(wc:*)", + "Bash(xcodebuild:*)", + "WebFetch(domain:github.com)", + "WebSearch", + "mcp__context7__query-docs", + "mcp__context7__resolve-library-id", + "mcp__firecrawl__firecrawl_scrape", + "mcp__firecrawl__firecrawl_search", + "mcp__gemini__consult_gemini", + "mcp__plugin_context7_context7__query-docs", + "mcp__plugin_context7_context7__resolve-library-id" + ], + "defaultMode": "auto", + "deny": [] + }, "skillOverrides": { "accessorysetupkit": "off", "adattributionkit": "off", @@ -108,7 +143,13 @@ "workers-best-practices": "off", "wrangler": "off" }, - "env": { - "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" - } -} + "skipAutoPermissionPrompt": true, + "skipDangerousModePermissionPrompt": true, + "skipWorkflowUsageWarning": true, + "statusLine": { + "command": "bash ~/.claude/statusline-command.sh", + "type": "command" + }, + "theme": "dark-daltonized", + "tui": "fullscreen" +} \ No newline at end of file diff --git a/linux/cloud-init.yaml b/linux/cloud-init.yaml new file mode 100644 index 0000000..a9d1d82 --- /dev/null +++ b/linux/cloud-init.yaml @@ -0,0 +1,75 @@ +#cloud-config +# Hetzner (or any cloud-init host) bootstrap for a Linux dev box. +# Paste into the provider's "Cloud config" field. Substitute HOSTNAME and the +# Tailscale auth key; everything else is generic. +# +# Tick your SSH keys in the provider's creation form as well. `- default` +# below preserves the provider's key injection into root, and runcmd copies +# those same keys to the non-root user — which is the only reliable way to +# get in. Seeding from github.com/.keys instead looks equivalent and is +# not: the keys published there need not be the key your SSH agent offers. + +hostname: CHANGE-ME +package_update: true +# NOT package_upgrade: it delays runcmd by several minutes behind a full +# apt upgrade, so Tailscale takes that long to appear. unattended-upgrades +# below applies the backlog shortly after boot instead. + +users: + # `- default` is load-bearing. A users: block without it SUPPRESSES the + # provider's SSH key injection entirely, which can leave a box with no keys + # at all and only the web console as a way in. + - default + - name: shridhar + groups: [sudo] + shell: /bin/bash + sudo: ['ALL=(ALL) NOPASSWD:ALL'] + +ssh_pwauth: false + +packages: [git, curl, unzip, ca-certificates, unattended-upgrades] + +swap: + filename: /swapfile + size: 4294967296 + maxsize: 4294967296 + +write_files: + # Patch automatically, but never reboot unattended: a surprise restart would + # kill long-running agent sessions and detach tmux work. Reboot by hand when + # /var/run/reboot-required appears. + - path: /etc/apt/apt.conf.d/20auto-upgrades + content: | + APT::Periodic::Update-Package-Lists "1"; + APT::Periodic::Unattended-Upgrade "1"; + APT::Periodic::AutocleanInterval "7"; + - path: /etc/apt/apt.conf.d/52unattended-upgrades-local + content: | + Unattended-Upgrade::Automatic-Reboot "false"; + Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; + Unattended-Upgrade::Remove-Unused-Dependencies "true"; + +runcmd: + # Give the non-root user exactly the keys the provider injected into root. + - install -d -m 700 -o shridhar -g shridhar /home/shridhar/.ssh + - cat /root/.ssh/authorized_keys > /home/shridhar/.ssh/authorized_keys + - chown shridhar:shridhar /home/shridhar/.ssh/authorized_keys + - chmod 600 /home/shridhar/.ssh/authorized_keys + + # Tailscale. Use a single-use, ephemeral, short-expiry auth key. + - curl -fsSL https://tailscale.com/install.sh | sh + - tailscale up --hostname=CHANGE-ME --authkey=TAILSCALE_AUTH_KEY_HERE + + # Apply the security backlog the base image ships with (typically ~50 + # packages including openssh-server and a kernel). + - DEBIAN_FRONTEND=noninteractive unattended-upgrades + + # Everything else — toolchain, shell, dotfiles, Claude plugins — is + # provision.sh's job. Kept there so this file and that script cannot drift. + - su - shridhar -c 'curl -fsSL https://raw.githubusercontent.com/sgup/new-mac-setup/master/linux/provision.sh | bash' + +final_message: | + Ready. Then, as the non-root user: + claude auth login + gh auth login # choose HTTPS + A kernel update usually lands in the backlog above; reboot when convenient.