| name | update |
| description | Update Fritz Local to the latest version. Pulls from git, symlinks new skills and managed hooks, runs pending migrations, and reports changes. Use when the session-start hook reports an update is available, or run /update manually.
|
Update
Update the local Fritz Local installation to the latest version.
Trigger
Activate when:
- The session-start hook reports a Fritz Local update is available
- The user asks to update or upgrade Fritz Local
- Run
/update
Workflow
0. Resolve the repo location
Fritz can be cloned anywhere; do not assume ~/.fritz-ai-local. Resolve the
real repo root first and use it for every command below (shown as <REPO>):
python3 -c "import pathlib,os; print(os.environ.get('FRITZ_REPO_PATH') or pathlib.Path('$HOME/.brain/hooks/brain_common.py').resolve().parents[1])"
This follows the ~/.brain/hooks/ symlinks back to the actual clone. If
~/.brain/hooks/brain_common.py is missing, fall back to wherever the managed
hooks were symlinked from, or ask the human for the clone path. On Windows,
substitute %USERPROFILE% for $HOME.
Before pulling, read <REPO>/VERSION and
<REPO>/bindings/claude/.claude-plugin/plugin.json version if present. Keep
those values for the final version transition report.
1. Pull latest
Run:
git -C <REPO> pull
If the pull fails (dirty tree, merge conflict), report the error and stop.
2. Read version change
Read <REPO>/VERSION for the new version. Compare with the version shown in the
update notification (if any). Report the version bump.
Read <REPO>/bindings/claude/.claude-plugin/plugin.json version after the
pull. Report the Plugin version transition as <old plugin version> → <new plugin version> when both values are known, or unknown → <new plugin version>
when the old value was unavailable.
3. Symlink new skills and managed hooks
First detect whether Claude Code is plugin-managed:
python3 -c 'import json,os,pathlib; env=os.environ.get("CLAUDE_SETTINGS_PATH"); p=pathlib.Path(env.strip()).expanduser().resolve() if env and env.strip() else pathlib.Path.home()/".claude/settings.json"; s=json.loads(p.read_text()) if p.exists() else {}; e=s.get("enabledPlugins"); plugin="fritz-brain@fritz-local"; print((isinstance(e,list) and plugin in e) or (isinstance(e,dict) and plugin in e and e.get(plugin) is not False))'
If this prints True, the Claude binding is plugin-managed. For Claude Code,
skip the whole legacy Claude wiring path: do not symlink repo skills into
~/.claude/skills/, do not refresh ~/.brain/hooks/ solely for Claude hook
execution, and do not run python3 <REPO>/hooks/install_claude_hooks.py.
Report exactly:
Claude: plugin-managed — skills/hooks owned by fritz-brain plugin; legacy registration skipped
Codex CLI, Gemini CLI, and non-Claude managed hook symlinks are unaffected by
this Claude-only condition.
List all directories in <REPO>/skills/. For each skill directory (any subdir containing a SKILL.md), check if a symlink exists in the agent's skill directory:
- Claude Code:
~/.claude/skills/ (skip when plugin-managed)
- Codex CLI:
~/.codex/skills/
- Gemini CLI:
~/.gemini/skills/
If a skill directory exists in the repo but has no symlink, create the symlink.
If a skill directory was removed from the repo but a symlink still exists, warn the user but do NOT delete the symlink. The human decides.
Then refresh managed hook symlinks from <REPO>/hooks/ into
~/.brain/hooks/ for all Python hook files required by the current agent.
When Claude is plugin-managed and the current update is for Claude only, skip
this hook refresh; the Claude plugin owns its hook scripts.
At minimum keep these common hooks current:
brain_capture.py
brain_session_start.py
brain_prompt_check.py
brain_common.py
brain_security.py
For Hermes Agent, also symlink:
hermes_brain_context.py
hermes_brain_capture.py
Then register the Claude Code hooks only when Claude is not plugin-managed. The
legacy directory-source marketplace path needs this because its skills load but
its hooks do NOT auto-register — without this step the four fritz hooks never
fire and Claude records 0 captures. Run the installer (idempotent; merges into
~/.claude/settings.json, preserving other plugins' hooks):
python3 <REPO>/hooks/install_claude_hooks.py
4. Run pending migrations
Check <REPO>/migrations/ for numbered Python scripts (e.g., 001-add-settings.py). Check ~/.brain/.migrations-run for which migrations have already been executed. Run any new migrations in order.
Each migration script:
- Receives no arguments
- Reads/modifies files in
~/.brain/ or vault directories
- Is idempotent (safe to run twice)
- Prints a summary of what it did
After running each pending migration, the runner must ensure that
migration's number is recorded in ~/.brain/.migrations-run only when the
migration actually completed. Do a line-exact membership check (so 002 does
not match 0020) and append the number on its own line only if it is not
already present and the migration output does not say it was skipped. Some
migrations (e.g. 002 and 004) self-record their own number when complete;
because the runner appends only when the number is absent, this is safe and
never double-records. Migrations that do not self-record (e.g. 001) rely on the
runner to record them after successful completion.
5. Check MCP token wiring status
Run the Claude MCP registration refresh step every update, even when migration
006 is already recorded:
python3 <REPO>/migrations/006-claude-user-scope-mcp-registration.py --refresh
Report Claude MCP registration status without printing the token value:
current when Claude's user-scope mcpServers.fritz-brain entry exists in
~/.claude.json, uses type: http, points at
settings.local_brain_service.base_url plus /mcp/, and its
Authorization header token matches settings.local_brain_service.api_token.
refreshed when the update command rewrote a missing, stale-token, or
stale-URL registration.
skipped when no registry token exists or the Claude CLI is unavailable.
After migrations finish, report Token wiring status without printing the
token value:
wired when ~/.zshenv contains the Fritz-managed token export block and
~/Library/LaunchAgents/ai.fritz.local-brain-token-env.plist exists.
partial when only one of the managed zshenv block or LaunchAgent plist
exists.
missing when neither exists. In that case, report that running /update
again should apply pending migrations, and list migration output if it explains
why token wiring was skipped.
Also note whether settings.local_brain_service.api_token_env is set in
~/.brain/registry.yaml (default LOCAL_BRAIN_API_TOKEN). Do not echo
settings.local_brain_service.api_token.
6. Scan vaults for brain contract drift
The brain contract declared in brain-setup carries a
brain_contract_version. When the skill ships a new version, existing vaults
keep their older brain.md until the human re-runs setup there.
This step is a passive scan — read-only. No writes, no prompts, no per-vault
updates.
- Read the current version declared in
<REPO>/skills/brain-setup/SKILL.md by locating the line
The current brain contract version is \N``. If it cannot be parsed,
skip this step silently.
- Read
~/.brain/registry.yaml and iterate over its vaults: entries.
- For each vault, open
<vault-path>/.brain/instructions/brain.md and parse
its frontmatter. If the file is absent, the vault has not been set up with
the new architecture yet — flag it for the report as "no brain.md".
- If the file's
brain_contract_version is less than the current version,
flag the vault for the report as "outdated (vN → vM)".
- Do not touch any file. This is a detection step only.
7. Resolve Local Brain service behavior if unconfigured
Read ~/.brain/registry.yaml. If settings.local_brain_service is absent,
pause and ask the human which behavior they want for the optional Dockerized
Local Brain service:
- Configure and start the optional Docker Local Brain service now.
- Keep using the existing local slash-skill workflow, but allow future setup
suggestions.
- Write
enabled: false, base_url: http://127.0.0.1:8765,
api_token_env: LOCAL_BRAIN_API_TOKEN, optionally api_token for trusted local agent use, allow_remote: false, and
suggest_setup: true.
- Keep using the existing local slash-skill workflow, and stop future setup
suggestions.
- Write
enabled: false, base_url: http://127.0.0.1:8765,
api_token_env: LOCAL_BRAIN_API_TOKEN, optionally api_token for trusted local agent use, allow_remote: false, and
suggest_setup: false.
Do not start Docker or set enabled: true without explicit human approval. If
the registry setting already exists, do not ask and do not overwrite it.
8. Report
Show the user:
- Version change (e.g.,
1.0.0 → 1.1.0)
- Plugin version transition (e.g.,
1.0.0 → 1.1.0)
- New skills added
- Hook symlinks refreshed or missing
Claude: plugin-managed — skills/hooks owned by fritz-brain plugin; legacy registration skipped
when the Claude plugin-managed branch was detected
- Removed skills (warnings only)
- Migrations run and their summaries
- Claude MCP registration status:
current, refreshed, or skipped; include
whether the user-scope registration was missing or drifted, but never print
the token value.
- Token wiring status:
wired, partial, or missing; include whether the
managed zshenv export block and LaunchAgent plist are present, but never print
the token value.
- Local Brain service setting state: report whether
settings.local_brain_service
exists, whether it is enabled, and whether a human decision was recorded during
the update.
- Brain contract drift: list of vaults with outdated or missing
brain.md,
along with "Run /brain-setup in those vaults to refresh."
- Any errors encountered
Important
- Execute immediately when invoked. No second confirmation.
- If
<REPO> is not a git repo, report the error and suggest re-cloning.
- On Windows, use
%USERPROFILE% for ~ and mklink for symlinks.
- Log the update operation to
~/.brain/log.md.