agentic-z-update
Pulls the latest Agentic-Z template files (agents, skills, docs) from upstream into this clone and commits them, leaving workspace/ mod work untouched. Use when the user asks to update Agentic-Z or pu
SKILL.md.claude/skills/agentic-z-update/SKILL.md
GitHub<!-- skill-dir-note -->
Path note:
<skill-dir>in commands below is the absolute path of this skill's folder. When the agent loads this skill the harness exposes the skill's base directory; substitute it before running. Sibling skills are reached via<skill-dir>\..\<other>\.
/agentic-z-update
Pull template improvements (agents, skills, conventions, docs) from upstream DayZ-n-Chill/Agentic-Z's main branch into the current clone. Three guarantees:
workspace/mod work is never touched. All changes are limited to template-managed paths.- Local customizations to template files are not overwritten silently. A three-way per-file classification (local file, file at the baseline, upstream file) detects when both the clone and upstream edited the same file and leaves it alone unless the user picks "take" in
--per-filemode. File contents are never merged: each file is either kept or replaced whole. - No two updates can apply at once. A PID-based lock covers the first-run baseline write and the apply phase (checkout, delete, commit, baseline write); previews and
--checkdo not take it. The lock file is created atomically with its content already in it, so two runs that start together cannot both get it. A lock left by a dead process is taken over under a short-lived second lock (.claude/.upstream-update.lock.takeover), and the stale lock is removed only if it is still the one that was judged stale, so two runs that find the same dead lock cannot both end up holding it.
The first run records the commit your clone was made from (the merge base with upstream main) as the baseline, so changes upstream made since you cloned are offered; with no shared history it records upstream HEAD and adds nothing. A template file that is in the baseline but missing locally is treated as one you deleted on purpose (locally-deleted): it is left alone and offered for restore in --per-file. Every later run compares the local file, the file at the baseline and upstream's current file to decide what to do per file. The comparison uses git blob ids, with the local file hashed through the clone's line-ending settings (git hash-object --stdin-paths, which applies the same filters as git add), so a CRLF checkout under core.autocrlf=true is not mistaken for a local edit. The ids come from one git ls-tree per revision and one git hash-object for the working tree, so the check costs the same handful of git calls whether 3 or 500 files drifted. The script works from the repo root (git rev-parse --show-toplevel), so it can be started from any subfolder.
How to run
python "<skill-dir>\update.py" [--check] [--quiet] [--yes] [--per-file] [--force] [--dry-run] [--no-sync]
Flags
| Flag | Behavior |
|---|---|
| (default) | Preview drift, prompt y/N, apply safe changes (conflicts left alone). When the only drift is local-only-edit or locally-deleted files, it lists them, says Up to date. and exits 0 without prompting (with --per-file, a locally-deleted file still gets the prompt so it can be restored) |
--check |
Preview only: fetches upstream (adding the upstream remote if it is missing) and writes no files; exits 1 if upstream changes are pending or no baseline exists yet, 0 if up to date (local-only-edit and locally-deleted files do not count) |
--quiet |
With --check: single-line output for hooks, and always exits 0 so the hook shows the line. Rejected without --check |
--yes |
Skip the confirmation prompt (CI / scripted use) |
--per-file |
Walk each conflict and locally-deleted file interactively: keep / take / diff / skip. Keep is a decision: the file stays yours and no longer holds the baseline back. Skip (also Enter, or no terminal) decides later: the file is offered again on the next run |
--force |
Override the dirty-tree check |
--dry-run |
Show preview, do not apply. With no baseline yet, previews against the baseline the first real run would record, without writing it |
--no-sync |
Skip the post-update sync-skills run (useful when Claude Code is the only agent CLI in use) |
Automatic commit
When at least one file is applied, the skill stages exactly the applied paths and commits only those paths (git commit --only), so anything else you had staged stays staged and out of the commit. The path list goes to git on stdin (--pathspec-from-file) and is matched literally, so a large first update is not stopped by the Windows command-line length limit and a name with * or [ in it matches only that file:
chore: pull Agentic-Z upstream (<first 8 chars of upstream SHA>)
It then records the upstream SHA in .claude/.upstream-baseline, but only when the commit succeeded and nothing upstream changed is still unapplied (a conflict or deleted-conflict that was skipped or never walked, or a file whose checkout or delete failed; local-only-edit and locally-deleted files, and conflicts you chose to keep in --per-file, do not hold it back). Otherwise the baseline stays put and the next run offers those files again. If git commit fails (for example, a pre-commit hook rejects it), the changes stay staged, the skill prints a warning and exits 1; nothing is rolled back. Unresolved conflicts are never part of the commit. Tell the user about this commit when reporting results.
Per-file status meanings
| Status | What it means | Default action |
|---|---|---|
unchanged |
Local file matches upstream | nothing |
safe-overwrite |
Not edited locally, upstream changed it | apply upstream |
new |
Upstream has it, the baseline and the clone do not | apply upstream |
locally-deleted |
In the baseline, missing in the clone, and once committed in the clone (you deleted it) | leave alone (--per-file take restores it) |
local-only-edit |
Only the clone edited it (upstream unchanged) | leave alone |
conflict |
Both the clone and upstream edited it | leave alone (use --per-file to resolve) |
deleted-clean |
Upstream removed it, not customized locally | delete |
deleted-conflict |
Upstream removed it, customized locally | leave alone |
What gets updated
Template-managed paths only:
agents/
skills/
.claude/agents/
.claude/skills/
.claude/mcp/
.claude/settings.json
.claude-plugin/
.mcp.json
hooks/
mods/
evals/
docs/
scripts/
.claude/CLAUDE.md
AGENTS.md
GEMINI.md
README.md
.gitignore
pytest.ini
.env.example
package.json
package-lock.json
.github/
CONTRIBUTING.md
LICENSE
.markdownlint.json
.markdownlint-cli2.jsonc
.markdownlintignore
What stays untouched:
workspace/ # in-progress mods
output/ # one-shot deliverables
.claude/local-memory/ # gitignored, per-clone notes
.claude/settings.local.json # local Claude Code settings
.env # gitignored API keys
When to run
- After a new Agentic-Z release.
- When a new agent or skill has shipped upstream.
- Periodically (monthly is fine).
When not to run
- Mid-merge, mid-rebase, mid-cherry-pick or mid-revert (it refuses; finish or abort first).
- With uncommitted changes to tracked template files (it refuses; commit first, or pass
--force). Untracked files, such as a skill you just added, do not block it. - On a fork that has diverged heavily from upstream main (manual cherry-pick is safer).
Files this skill creates
.claude/.upstream-baseline— upstream SHA of the last completed update. Gitignored..claude/.upstream-update.lock— concurrency lock during apply phase. Gitignored..claude/.upstream-update.lock.takeover— held for a moment while a stale lock is replaced, then removed. Gitignored.
SessionStart hook
A SessionStart hook runs update.py --check --quiet at the start of every Claude Code session in this repo. It prints a one-line nudge if upstream is ahead, if a newer prebuilt search index is available, or if no baseline has been recorded yet (run /agentic-z-update once to record it). Silent on no-change. The hook has a 20 second timeout, which leaves room for the git fetch plus the 5 second GitHub release check on a slow network; the drift check itself takes well under a second even with hundreds of files behind. It always exits 0: Claude Code drops plain output from a hook that exits non-zero, so a failing exit code would hide the nudge. Configured in .claude/settings.json.
To disable temporarily: comment out the SessionStart block in .claude/settings.json.
Search index notification
If /dayz-search-download was run before, this skill also checks whether the installed GitHub release of the search index has been superseded. The check is read-only and never downloads; it only suggests running /dayz-search-download.
To skip the check: ensure ~/.claude/dayz-search-index/release-tag.txt doesn't exist (the check is silent when no installed tag is recorded).
After updating
- Restart the agent CLIs (Claude Code, Codex, Gemini) so they pick up new agents and skills.
- Run
/dayz-preflightto confirm the environment still works.
Refuse rules (exit 1)
- Not a git repo: "Run from inside an Agentic-Z clone." With
--check --quietthis prints that one line and exits 0, so the hook shows it. - Uncommitted changes to tracked files in template paths (skipped with
--force, and not checked by--check). Untracked files are ignored: the update leaves a file only you have alone, and treats one at a path upstream adds as a conflict. Nothing is fetched or changed. - A merge, rebase, cherry-pick or revert is in progress (checked even with
--force; not checked by--checkor--dry-run, which write nothing). Its commit would fail and leave the applied files staged inside your operation, so nothing is fetched or changed. - The
upstreamremote points somewhere else: prints thegit remote set-urlfix. With--check --quietthe fix is one line and the exit is 0. git fetchfails (with--check --quietthis exits 0 silently so the hook stays quiet).- Non-interactive shell at the confirmation prompt without
--yes. git commitof the applied files fails (changes left staged, baseline not moved).