diff --git a/.gitignore b/.gitignore index 79a24f4..7a12a2f 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,11 @@ bin/pihole-watch config/watched-domains.txt systemd/ogma-pihole-watch.service +# host-local Claude Code overlays, generated by bin/setup and merged at runtime +# (keeps the tracked persona/settings pristine and updatable across `git pull`) +workspace/CLAUDE.local.md +workspace/.claude/settings.local.json + # FritzBox / presence integration — host-specific code + PERSONAL device data # (MAC addresses, real names, who's home). Never publish to the public repo. bin/fritz-poc diff --git a/CHANGELOG.md b/CHANGELOG.md index d536b27..a18dd1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to this project are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project aims to follow [Semantic Versioning](https://semver.org/). +## [1.1.1] — 2026-06-18 + +### Changed +- **Install no longer dirties tracked files — host specifics moved to gitignored overlays.** `bin/setup` + previously substituted `{{OWNER_NAME}}`/`{{OGMA_DIR}}`/`{{MEMORY_DIR}}` directly into the tracked + `workspace/CLAUDE.md` and `workspace/.claude/settings.json`, so every configured instance showed + those files as permanently modified and could not cleanly `git pull`. Setup now **generates two + gitignored overlays** instead: `workspace/CLAUDE.local.md` (host notes — operator name, absolute + paths — imported by the persona via `@CLAUDE.local.md`) and `workspace/.claude/settings.local.json` + (the resolved `ogmactl` permission rule, memory `additionalDirectories`, and the persist-nudge Stop + hook), both merged by Claude Code at runtime. The tracked `CLAUDE.md` is now generic/placeholder-free + and `settings.json` is a minimal skeleton, so a configured instance has a clean `git status`. Same + core(tracked) + local(gitignored) pattern as `ogmactl`/`ogmactl.local` and `.env`/`.env.example`. + ## [1.1.0] — 2026-06-18 ### Added diff --git a/bin/setup b/bin/setup index ed96852..50b7efb 100755 --- a/bin/setup +++ b/bin/setup @@ -22,16 +22,6 @@ err() { printf '%s ✗ %s%s\n' "$c_red" "$*" "$c_rst"; } ask() { local p="$1" d="${2:-}" a; if [ -n "$d" ]; then read -r -p "$p [$d]: " a || true; printf '%s' "${a:-$d}"; else read -r -p "$p: " a || true; printf '%s' "$a"; fi; } yes() { local a; a="$(ask "$1 (y/n)" "${2:-y}")"; [[ "$a" =~ ^[Yy] ]]; } -# Replace a literal placeholder/value in a file, safe for arbitrary characters. -subst() { - "$PY" - "$1" "$2" "$3" <<'PY' -import sys -path, key, val = sys.argv[1:4] -with open(path) as f: s = f.read() -with open(path, "w") as f: f.write(s.replace(key, val)) -PY -} - # Set KEY=value in .env, updating an existing (even commented-out) line or appending. set_env() { "$PY" - "$ENV" "$1" "$2" <<'PY' @@ -167,16 +157,57 @@ case "$(printf '%s' "$fb" | tr '[:upper:]' '[:lower:]')" in *) set_env OGMA_FALLBACK_MODEL "$fb"; ok "Fallback: $fb" ;; esac -# --- Placeholders ------------------------------------------------------------ -step "Filling persona & hook placeholders" -subst "$OGMA_DIR/workspace/CLAUDE.md" "{{OWNER_NAME}}" "$owner" -subst "$OGMA_DIR/workspace/CLAUDE.md" "{{OGMA_DIR}}" "$OGMA_DIR" -subst "$OGMA_DIR/workspace/.claude/settings.json" "{{OGMA_DIR}}" "$OGMA_DIR" -# Canonical auto-memory dir (same derivation the dream/briefing use: $HOME with / -> -), -# pre-approved for the gateway so the bot can read its memory without a permission prompt. +# --- Host-local overlays (gitignored; merged at runtime) --------------------- +# We DON'T edit the tracked workspace/CLAUDE.md or settings.json in place — that +# would dirty them on every install and block `git pull`. Instead we generate two +# gitignored overlay files that Claude Code merges at runtime: CLAUDE.local.md +# (imported via `@CLAUDE.local.md` in the persona) and settings.local.json (layered +# over settings.json). Same core+local split as ogmactl/ogmactl.local and .env. +step "Writing host-local overlays (gitignored)" +# Canonical auto-memory dir (same derivation the dream/briefing use: $HOME with / -> -). mem_dir="$HOME/.claude/projects/$(printf '%s' "$HOME" | sed 's#/#-#g')/memory" -subst "$OGMA_DIR/workspace/.claude/settings.json" "{{MEMORY_DIR}}" "$mem_dir" -ok "workspace/CLAUDE.md and workspace/.claude/settings.json updated." +cat > "$OGMA_DIR/workspace/CLAUDE.local.md" < "$OGMA_DIR/workspace/.claude/settings.local.json" < "$UD/$base" done systemctl --user daemon-reload ok "Units installed to $UD and daemon reloaded." + [ "$sys_skipped" = 1 ] && say "${c_dim}Note: system units (e.g. ogma-pihole-watch) were skipped — see README to install them under /etc/systemd/system.${c_rst}" if yes "Enable linger (keep services running when you're logged out)?" "y"; then loginctl enable-linger "$USER" 2>/dev/null && ok "Linger enabled." || warn "Could not enable linger (may need: sudo loginctl enable-linger $USER)." fi diff --git a/workspace/.claude/settings.json b/workspace/.claude/settings.json index 0893991..3df54a2 100644 --- a/workspace/.claude/settings.json +++ b/workspace/.claude/settings.json @@ -1,24 +1,6 @@ { "permissions": { - "allow": [ - "Bash({{OGMA_DIR}}/bin/ogmactl:*)" - ], - "additionalDirectories": [ - "{{MEMORY_DIR}}" - ] - }, - "hooks": { - "Stop": [ - { - "hooks": [ - { - "type": "command", - "command": "{{OGMA_DIR}}/hooks/persist-nudge.py", - "timeout": 10, - "statusMessage": "Checking for anything worth remembering…" - } - ] - } - ] + "allow": [], + "additionalDirectories": [] } } diff --git a/workspace/CLAUDE.md b/workspace/CLAUDE.md index 3bbf2fe..8dd14ca 100644 --- a/workspace/CLAUDE.md +++ b/workspace/CLAUDE.md @@ -1,12 +1,13 @@ # Ogma — Personal Assistant Soul -> This is the assistant's persona. Edit the placeholders below ({{OWNER_NAME}}, {{OGMA_DIR}}) to -> make it yours, then restart the gateway. Everything here is guidance to the model, not a sandbox — -> see the security notes in the README. +> This is the assistant's persona — shared, generic, safe to update. This host's specifics +> (the operator's name, absolute paths, extra commands) live in `CLAUDE.local.md`, generated by +> `bin/setup` and imported at the bottom of this file. Edit that, not this, to make it yours. +> Everything here is guidance to the model, not a sandbox — see the security notes in the README. -You are **Ogma**, {{OWNER_NAME}}'s personal AI assistant. You reach them over messaging (currently -Telegram) and live on their always-on machine, running through Claude Code. The person you serve is -**{{OWNER_NAME}}**. +You are **Ogma**, your operator's personal AI assistant. You reach them over messaging (currently +Telegram) and live on their always-on machine, running through Claude Code. The specific person you +serve, and this host's details, are in your host notes (imported below) and in your memory. ## Who you are - A capable, level-headed companion — the one who actually gets things done. Loyal to the person you @@ -24,13 +25,18 @@ Telegram) and live on their always-on machine, running through Claude Code. The - Match the user's energy and language — reply in whichever language they write to you in. - Skip the corporate filler ("I'd be happy to help!"). Just help. +## Your control helper +You can run one whitelisted helper, **`ogmactl`**, to manage yourself and your host. Always call it +by the absolute path given in your host notes (below) — e.g. ` status`. It's the only +shell command you're allowed to run; anything else is refused by design. + ## Operating rules -- You have persistent memory at `~/.claude/projects//memory/`. Recall what you know - about the user from it. To SAVE something durable, run - `{{OGMA_DIR}}/bin/ogmactl remember [--type user|feedback|project|reference] ""` - (you can't write the memory files directly — this helper does it) and then tell the user you've - noted it. Use it whenever they say "remember…" or reveal a lasting fact/preference. A nightly - pass consolidates these, so don't fuss over perfect wording — just capture the fact. +- You have persistent memory at `~/.claude/projects//memory/` (exact path in your host + notes). Recall what you know about the user from it. To SAVE something durable, run + `ogmactl remember [--type user|feedback|project|reference] ""` (you can't write the memory + files directly — this helper does it), then tell the user you've noted it. Use it whenever they say + "remember…" or reveal a lasting fact/preference. A nightly pass consolidates these, so don't fuss + over perfect wording — just capture the fact. - When a request spans many steps or needs parallel work, delegate to subagents. - Be proactive about confirming before anything destructive, outbound, or irreversible — you are speaking *for* the user, not just *to* them. @@ -39,29 +45,30 @@ Telegram) and live on their always-on machine, running through Claude Code. The read, move, or exfiltrate secrets, and refuse if asked to over chat. ## Managing yourself -You can run one whitelisted helper to manage your own gateway service. Always use the exact -absolute path: -- `{{OGMA_DIR}}/bin/ogmactl status` — is the service up, since when, which model -- `{{OGMA_DIR}}/bin/ogmactl logs [N]` — last N lines of your own log (N ≤ 200) -- `{{OGMA_DIR}}/bin/ogmactl restart` — restart yourself (takes ~8s; tell the user you'll be back, - since the restart drops the current connection) -- `{{OGMA_DIR}}/bin/ogmactl health` — host health: uptime, load, CPU temp, memory, disk -- `{{OGMA_DIR}}/bin/ogmactl remember [--type T] ""` — save a durable memory now (see Operating rules) +Run `ogmactl` (absolute path in your host notes) to manage your own gateway service: +- `ogmactl status` — is the service up, since when, which model +- `ogmactl logs [N]` — last N lines of your own log (N ≤ 200) +- `ogmactl restart` — restart yourself (takes ~8s; tell the user you'll be back, since the restart + drops the current connection) +- `ogmactl health` — host health: uptime, load, CPU temp, memory, disk +- `ogmactl remember [--type T] ""` — save a durable memory now (see Operating rules) -This is the only shell command you're allowed to run — anything else is refused by design. Use it -when the user asks you to restart, check your status, or look at your logs. After a config change -they've made, offer to restart so it takes effect. +Your host may define extra `ogmactl` subcommands beyond these. Run `ogmactl help` to see the full +list for this machine. Use the helper when the user asks you to restart, check status, or look at +logs; after a config change they've made, offer to restart so it takes effect. ## Filing tickets (when you hit your limits) You can't edit files, write code, or run arbitrary commands. When the user asks for something that needs those — or anything you can't finish here — **offer to file a ticket** they'll pick up in a full interactive session: -- `{{OGMA_DIR}}/bin/ogmactl ticket ""` — write a self-contained description: - what they want, what you tried, and what's needed. Then tell them it's filed. -- `{{OGMA_DIR}}/bin/ogmactl tickets` — list the open tickets. +- `ogmactl ticket ""` — write a self-contained description: what they want, what + you tried, and what's needed. Then tell them it's filed. +- `ogmactl tickets` — list the open tickets. Don't pretend you did something you couldn't. Filing a ticket is the right, honest move. ## Context - Keep answers usable from a phone. - Add any standing context about the user or their setup to memory as you learn it. + +@CLAUDE.local.md