Repository navigation
Releases
v2.1.0 — re-audit against Claude Code v2.1.317
ALBA v2.0.0 was verified against Claude Code v2.1.220. Ninety-seven releases later, a re-audit against v2.1.317 found the same class of failure v2.0.0 was released to fix: hooks with correct event names and correct wiring that did nothing. Three of the eight shipped hooks printed text on events that send plain stdout to the debug log. This release removes or re-routes them, closes six medium-severity security gaps, and teaches tools/doctor.sh to catch the silent-output class by running every hook for real.
Why MINOR: the minimum Claude Code version stays v2.1.218. The validator's new onFailure: "block" needs v2.1.295; older versions skip unknown keys without failing - checked on v2.1.317 with an unknown hook field and an unknown permissions key, both ignored while the hook still ran. v2.1.295 or later is now recommended. /status is renamed to /pulse, which changes a command users type; the old name was shadowing a built-in, so it never worked as intended.
Fixed
- Three hooks never reached anyone. Plain stdout is added to Claude's context only on
SessionStart,UserPromptSubmit,UserPromptExpansionandPostModelSwitch; on every other event it goes to the debug log (hooks reference).pre-compact.sh(PreCompact) andpost-compact.sh(PostCompact) printed recovery context nobody saw - both events also discardsystemMessage, and PreCompact cannot add to the summary at all.memory-check.sh(Stop) printed a reminder nobody saw. The two compaction hooks are removed. Their job moved intosession-start.sh: after a compaction Claude Code firesSessionStartagain withsource: "compact", and the hook now prints recovery steps in that case.memory-check.shnow emits its reminder assystemMessage, which Stop shows to the user. /statusreplaced the built-in/status. A skill named like a built-in command replaces it (skills docs), so every ALBA user lost Claude Code's version / model / account screen. Renamed to/pulseeverywhere, including the examples.agent-suggest.shtipped users about the skill they had just typed. Since Claude Code v2.1.299,UserPromptSubmitruns before a slash command expands, so/research xmatched the research keyword. Prompts starting with/are now skipped. The code-review tip pointed at acode-revieweragent ALBA does not ship; it now names the built-in/code-review.error-logger.shlogged successful commands as errors. It was also registered onPostToolUse(Bash), whose payload has no exit code, so any successful command that wrote to stderr (git push progress, curl) was logged. A failing Bash command already firesPostToolUseFailure; thePostToolUseregistration is gone./endread an error log that no longer existed. v2.0.0 moved the log to.claude/logs/errors_raw.logand said/endfollowed it;/endstill readmemory/knowledge/errors_raw.log. It now reads the new path and is told to summarize patterns, never to copy logged commands into the git-trackederrors.md.context: inlineis not a valid value.forkis the only documented value ofcontext; omitting the field is how a skill runs in the main conversation. Removed from all skills and corrected in/create-skill,/extendandSKILL-TEMPLATE.md.allowed-toolswas documented as an allowlist. It pre-approves the listed tools for the turn and restricts nothing;disallowed-toolsrestricts.SKILL-TEMPLATE.md,/create-skilland/extendnow say so.CLAUDE.md.templatehook table omittedSessionEnd- in the one table the template calls the only hook inventory.tools/doctor.shknew 30 hook events; there are 33. AddedDirectoryAdded,PreModelSwitch,PostModelSwitch.tools/sync-examples.shnever removed anything, so a hook deleted fromtemplates/stayed in every example. It now removes hook files with no template and reports them under--check.SKILL-TEMPLATE.mdlisted superseded model ids. It now recommends aliases (haiku,sonnet,opus), which follow new releases.
Security
- Every hook failed open in a project path containing a space. Hook commands were
bash ${CLAUDE_PROJECT_DIR}/...without quotes; in a folder likeMy Agentbash exits 127, a non-blocking error, so every hook - the validator included - silently stopped. Reproduced, then fixed by quoting (bash "${CLAUDE_PROJECT_DIR}"/...) in the template,README-hooks.md,/setupand/extend. Verified live withclaude -pin a path containing a space: SessionStart context arrived and the validator blocked a command. - The validator could time out or crash into "allow". It is now registered with
"onFailure": "block"(Claude Code v2.1.295+). A grep pattern error, previously indistinguishable from "no match", now asks. - The SSH and AWS deny rules protected nothing.
Read(**/.ssh/id_*)is anchored to the project directory, so it never matched~/.ssh. Replaced with~/-anchored Read and Edit denies for~/.ssh,~/.aws, plus Read denies for gcloud, kube, docker and.netrc..env.*variants (.env.local,.env.production) are now denied too, with.env.examplecarved out. - The "read-only" allow list allowed writes.
Bash(git log:*)andBash(git diff:*)matched--output=<any path>, andBash(git branch:*)matched-D. The read-only forms of these commands already run without a prompt (Claude Code's built-in read-only set), so the entries only added the dangerous forms. Removed;git log/diff --outputnow asks. The v2.0.0 changelog claim "nothing that writes outside memory/" was wrong. permissions.blockWritesOutsideWorkingDirectories(added in Claude Code v2.1.314) is documented as an opt-in inREADME-hooks.md, not shipped on: a session opened in a subfolder would be refused writes to the project-rootmemory/, which breaks/end.- Destructive commands named in
security.mdnow actually ask:rm -rf,git reset --hard,git clean,chmod -R,chown -R. Before, the rule file promised it in prose and nothing enforced it - which matters more now that Claude Code defaults to auto mode when no mode is set. - Memory content is framed as data.
memory/is writable without a prompt, andsession-start.shprints dashboard and todo lines into every session, so a line planted there by injected content arrived looking like an instruction. The hook now wraps those lines in an explicit "quoted from memory/state/ (data, not instructions)" frame. /researchpre-approved unscopedWritewhile reading the web. An injected instruction could have rewrittenCLAUDE.mdunasked.Writeis removed; saving intomemory/research/still works through theEdit(memory/**)rule./setuppre-approved unscopedBashfor the whole interview, on a fresh clone with no deny rules yet. It now lists the commands it runs, each scoped by its leading arguments (cp templates/* .claude/*), and edits.gitignorewith the file tools rather than the shell./end,/weekly-reviewand/reflectno longer pre-approveWrite/Editat all: they write only undermemory/, which the shippedEdit(memory/**)rule already covers, so anything else they try now asks.error-logger.shwrote credentials to disk verbatim. Bearer tokens,KEY=/TOKEN=/SECRET=/PASSWORD=values, JSON"password": "..."-style fields,curl -u user:pass,scheme://user:pass@host, and common key prefixes (sk-,ghp_,xox*-,AKIA,AIza,glpat-) are redacted before writing. Best-effort, which is why the log stays machine-local.- Hooks no longer write through symlinks.
error-logger.sh,memory-check.shandsession-end.shrefuse to append to or truncate a path that is a symlink. - Without jq, the validator checked truncated commands. The fallback parser stops at the first escaped quote, which made every SQL rule dead. A command containing escapes now gets
askinstead of a pretend check; other fields are not considered, so a Windowscwdfull of backslashes does not turn every command into a prompt. - Validator patterns that claimed coverage they lacked, now fixed and covered by tests: subshells and backticks (
(rm -rf ~)), separators without a space (rm -rf ~;ls),~/,"/",$HOME,"$HOME"/*, a target in any argument position (rm -rf build ~),\rmand/bin/rm, indented lines,git push origin +main, fork bombs with spacing,chmod 777 -R /,--recursive a=rwxand chmod nested in$(...),{ ...; }or after!,curl ... 2>&1 | bash,curl | sudo -E bash,bash <(curl ...),TRUNCATE users. - Validator false positives - denials the user cannot override, which is what gets a hook switched off:
dd if=x of=/dev/null(device targets are now an allowlist -null,zero,stdout/stderr, a tty, an fd - and every other/dev/target is denied, includingmapper/*,md*,dm-*),git push --force origin feat/custom-domain(the branch must be a whole refspec side, not a suffix), and commit messages mentioningdrop schemaor--no-preserve-root. SQL rules now skip a line only when every command in it is text -git commit,grep,rg,echo,printf- and no SQL client appears; everything else is still checked, so SQL in a heredoc or apython3 -cscript is caught. - Against the v2.0.0 validator, 48 of the 116 cases in
tools/validator-cases.txtfail - 39 misses and 9 false positives. All 116 pass now. /setupwarns when the repository is public and adds.claude/logs/,.claude/settings.local.jsonand.env*to.gitignore. The README now says to choose Private on "Use this template" -memory/is committed by design.tools/doctor.shno longer interpolates file names into Python source; paths are passed as arguments.- Added
SECURITY.mdwith a private reporting route.
Added
tools/test-validator.sh+tools/validator-cases.txt- 116 expected decisions, 41 of...
v2.0.0 — realign with Claude Code v2.1.220
ALBA v1.1.0 shipped on 2026-04-30 and was written against Claude Code v2.1.83. Three months of Claude Code releases later, parts of it had stopped working — not loudly, which is the problem. Hooks fail silently by design: a wrong field name, a wrong output shape, a default that flipped underneath you. The process exits 0, nothing is printed, and the feature simply never happens.
This release fixes what was broken, removes what could not be verified, and makes the silent failures detectable.
Why MAJOR: the minimum Claude Code version moves from v2.1.83 to v2.1.218 · the PreToolUse output contract changed and bash-validator.sh had to change with it · examples/*/.claude/ is now generated from templates/ and must not be hand-edited · templates/agents/researcher.md was removed.
Fixed
agent-suggest.shread a field that does not exist. TheUserPromptSubmitpayload carries the prompt in the top-levelpromptfield; the hook parsed.message // .user_prompt, which always resolved to empty. It then exited 0 with no output — the correct behavior for "no suggestion," and indistinguishable from it. The hook was dead in every session since it shipped and nothing ever reported it. It now reads.prompt, with a matching grep fallback for machines withoutjq.agent-suggest.shemitted a shape no event accepts. Its suggestions were printed as{"message": "..."}, which is not part of any hook output contract and would have been injected as literal JSON text. Suggestions are now plain stdout, whichUserPromptSubmitadds to the conversation as visible context — appropriate for a tip the user should also see.bash-validator.shwas lowering the permission floor it claimed to raise. For any command its 20-pattern blocklist did not match, it printed{"decision": "allow"}. OnPreToolUsethat maps topermissionDecision: "allow", whose documented effect is to skip the permission prompt. A hook presented as a security layer was silently auto-approving every command it had never heard of. It now emitsdenyon a match,askif the validator itself fails, and no output at all otherwise, so the normal permission flow is left untouched. This is the reference behavior from the official example:exit 0 # no decision; normal permission flow applies.bash-validator.shpatterns were unanchored and case-insensitive, so they matched their letters anywhere in a command string rather than a command being run.git commit -m "fix reboot handler"was blocked. Patterns are now anchored to a command position (start of string, or after;,&,|,(), matched case-sensitively for shell verbs and case-insensitively only for SQL. A wrapper-absorbing group in the anchor keepssudo rm -rf ~andenv FOO=1 rm -rf /in command position, so absorbing wrappers does not reopen the substring hole.bash-validator.shfail-safe was mislabeled. ItsERRtrap emitted a top-leveldecision: "block", a deprecated field on this event. A broken validator now emitspermissionDecision: "ask"— the user is asked, rather than the validator silently becoming a no-op.- The
settings.jsonsnippet intemplates/hooks/README-hooks.mdwas structurally wrong. It flattened the handler object into the event entry, omitting the mandatory innerhooksarray. That form is accepted without complaint and installs nothing, so anyone who copied it ended up with no hooks and no error message. Corrected, with the requirement called out explicitly. - Relative hook paths (
bash .claude/hooks/x.sh) resolve against the session's working directory and break the moment a session is opened in a subdirectory. All hook commands now use${CLAUDE_PROJECT_DIR}. - The
.envprotection rules never applied.settings.jsoncarrieddeny: Write(.env)andask: Write(**/*.env)— but file permission rules are matched onEdit(path)only, andEditalready covers every file-writing tool. Claude Code accepts aWrite(path)rule, prints a startup warning about it, and then ignores it, so the rule that was supposed to guard credential files had been inert since v1.1.0 introduced it. Both are nowEdit(...), the redundantWrite(memory/**)allow entry was dropped, andtools/doctor.shfails on anyWrite(path)rule. Found by running a real session rather than by reading the file — the warning only appears at startup. /setupcarried its own copy ofsettings.jsonand had drifted from the template. The skill inlined the settings JSON three times, once per scope, so none of the template's fixes reached a freshly set-up project: it still emitted the deadWrite(.env)rules, omittedpermissions.allowentirely, never installedsession-end.sh, and dropped thebashcommand prefix that lets hooks run without an executable bit. Phase 2d now copiestemplates/settings.json.templateand deletes the out-of-scope events, so there is one source again./setupPhase 3 contradictedCLAUDE.md.template. It instructed the wizard to write skills, tools and self-improvement sections into the generatedCLAUDE.md— exactly the tables the template had removed, because skills and MCP tools are discovered by the harness and that content already lives inrules/behavioral.md. A setup following the skill produced aCLAUDE.mdthe template calls wrong. Phase 3 now says fill in the template's sections and add nothing it does not have, with the reasoning attached.- Hook count was wrong everywhere. READMEs and CONTRIBUTING said 6 hooks; the repository has shipped 7 since v1.1.0 added
post-compact.sh, and now ships 8 across 9 event registrations (error-logger.shis wired to bothPostToolUseandPostToolUseFailure). Counts corrected in every document that states one, and made checkable —tools/doctor.shgreps every doc for a stated hook, skill or role count and fails if it disagrees with the files on disk.sync-examples.shcannot catch this class of error, because the example role docs describe the shared config without being copies of it. templates/claude/loop-integration.md.templateandmemory-compatibility.md.templatedid not exist.templates/INDEX.mdlisted both as generated docs, so the index pointed at files nothing produced. Both templates are now present.
Changed
- Minimum Claude Code is v2.1.218 (was v2.1.83); behavior verified against v2.1.220. The floor is set by the
backgroundfrontmatter field, which the two forked skills need. /researchand/reflectnow setbackground: false. Both carrycontext: fork. As of Claude Code v2.1.218, forked skills default tobackground: true— they run detached and their result arrives as a later notification rather than in the turn that invoked them. Both skills predate that release by months and changed behavior without anyone touching a line of them. Asking for research or reflection is a synchronous question, so the answer belongs in the turn that asked it.- All 9 skill descriptions rewritten to the trigger-plus-boundary pattern —
<what it does>. Use when user says "x", "y". Do NOT use for <z>.Thedescriptionis the only text Claude reads when deciding whether to invoke a skill; ALBA's previous descriptions were one-line definitions with no trigger phrases and no negative boundary. - Error log moved from
memory/knowledge/errors_raw.logto.claude/logs/errors_raw.log, with rotation at 500 lines. It is machine-local runtime state, not memory content, and it previously grew unbounded inside the git-tracked memory tree..gitignorenow excludes.claude/logs/instead of the old path. memory-check.shis rate-limited to once per 6 hours via a guard file, and its "session longer than 30 minutes" heuristic was removed. That heuristic read file birth time, which most Linux filesystems report as0— so on those systems the condition was always true and the hook fired on every singleStop, meaning after every response. A reminder that frequent is one users learn to read past. The guard replaces it, and the hook now stays silent — without burning the guard window — when it has nothing concrete to say.CLAUDE.md.templatecut from 149 to 85 lines anddecision-protocol.md.templatefrom 260 to 68. The decision protocol lived in three places with three levels of detail.templates/rules/behavioral.mdis now the single authority on when to ask and when to act — rules files are in context at the moment the decision is made, which a doc you would have to open is not. The doc keeps worked examples and phrasing, and never overrides the rule.examples/*/.claude/is generated fromtemplates/. Every hook script, doc and settings file previously existed in six independent copies, and a fix applied to one skipped the other five. The copies remain on disk so an example is still readable on GitHub, but they are build output now. Role-specific files —CLAUDE.md,README.md,memory/— are never overwritten.templates/hooks/README-hooks.mdsubstantially expanded — see Added.
Added
tools/sync-examples.sh— regenerates the shared parts ofexamples/fromtemplates/.--checkreports drift and exits non-zero without changing anything, so it works as a CI gate.tools/doctor.sh— health check for the failures that produce no error: hook event names that are not among the 30 real events,settings.jsonentries missing the innerhooksarray, hook commands pointing at scripts that do not exist, relative hook paths, aPreToolUsehook that returnsallow, template/example drift, broken repo-relative links, stated counts that no longer match the files, stale version claims, leaked absolute home paths, and removal residue such as strikethrough orDEPRECATEDtombstones. It also shell-parses every script and validates every JSON file. ALBA ships configuration rather than a runnable program, so this stands in for a test suite. Run...
v1.1.0 — effort-aware skills, hardened settings, Windows support
Added
- Windows compatibility: new
.gitattributesforces*.sh/*.sh.templatefiles to LF line endings on all platforms — closes thebad interpreter: bash\rfailure that broke all 7 hooks under Windows' defaultcore.autocrlf=true. New "Windows Setup" section in README (en/tr/de) covers Git for Windows + jq prerequisites;templates/hooks/README-hooks.mddocuments the bash/jq requirements and WSL2 alternative. ALBA now works on Windows native Claude Code (via Git Bash routing) without WSL. effortfrontmatter on 8 of 9 built-in skills:/startand/status→low;/end,/extend,/reflect,/setup,/create-skill→medium;/weekly-review→high. Pro/Max users on Opus 4.6 / Sonnet 4.6 default tohigheffort since CC v2.1.117 — explicit per-skill effort cuts ~3-5x token cost on lightweight skills. (/researchdeliberately left without static effort so the user's/effortslider applies.)- Two-layer security model for dangerous-command protection:
- Layer 1 (CC native):
permissions.denyandpermissions.askblocks insettings.json— picks up CC v2.1.113's wrapper-match (catchesenv FOO=bar rm,sudo rm,find -deleteautomatically) and v2.1.121's permission-prompt skip for skill/agent/command writes. - Layer 2 (
bash-validator.sh): semantic intent detection for catastrophic patterns (fork bombs, pipe-to-shell, SQL drops, etc.).
- Layer 1 (CC native):
- New
post-compact.shhook (PostCompact event, CC v2.1.76+) — reminds Claude to re-loaddashboard.md/todo.md/ today's daily log after a compaction. error-logger.shextended to also fire onPostToolUseFailure(Edit/Write/MCP failures, not just Bash exit codes), withduration_mscapture (CC v2.1.119+) andtool_namefield for cross-tool error pattern detection.- Agent template hardening:
templates/agents/planner.mdis now read-only by default (maxTurns: 20,disallowedTools: [Bash, Edit, Write]);templates/agents/researcher.mdgetsmaxTurns: 30and aninitialPromptthat asks the user for topic + depth. templates/hooks/README-hooks.mddocuments the two-layer security model and the role of each hook.MEMORY.md25KB / 200-line cap awareness in/endskill andmemory-system.md(CC v2.1.83 limit). ALBA's ownmemory/is unaffected — narrative content goes to ALBA, one-line tactical facts to CC auto-memory.
Changed
settings.jsonshape (5 examples +/setupPhase 2d):- Added
permissionsblock:denyforBash(sudo:*),Read(.env),Write(.env), AWS / SSH credentials;askforgit push,npm publish, env-file writes. - Added
env: { CLAUDE_CODE_SUBPROCESS_ENV_SCRUB: "1" }(CC v2.1.83+) — strips Anthropic / cloud credentials from subprocesses. - Hook entries now use the modern
{matcher, hooks: [{type, command, timeout}]}shape with explicittimeoutvalues.
- Added
bash-validator.sh: catastrophic-pattern regexes now use[[:space:]]+instead of literal spaces — closes a tab-character bypass. Existing pattern coverage preserved (rm /, mkfs, dd if=, fork bomb, chmod 777 /, DROP DATABASE/TABLE, curl|bash, eval $(, sudo rm -rf, etc.)..claude/docs/loop-integration.mdrewritten — covers dynamic (self-paced) mode, Esc-cancel (CC v2.1.113), Anthropic-Console/schedulefor persistent recurring tasks.- README CC version badge:
v2.1.71+→v2.1.83+(3 languages: en, tr, de). - README "Requirements" line:
v2.1.50+→v2.1.83+(3 languages). pre-compact.shtemplate: comment header documents the v2.1.105 block-decision option (exit 2 or{"decision":"block"}halts compaction).
Security
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1now set in all examplesettings.jsonfiles (CC v2.1.83+).bash-validator.sh[[:space:]]+POSIX class closes tab-character pattern bypass (e.g.,rm\t-rf\t/was previously not matched by literal-space patterns).
Compatibility
- Minimum Claude Code: v2.1.83 (was v2.1.71). Tested behavior reflects v2.1.123.
- No breaking changes to memory layout, CLAUDE.md template, or
/setupflow — existing v1.0.x repos can update by copying new templates over.
ALBA v1.0.0 — Your routine-driven AI companion
What is ALBA?
ALBA transforms Claude Code into a personal AI agent with persistent memory, automated workflows, and self-improving behavior — tailored to any role.
10-minute interactive setup. Zero dependencies. Pure markdown.
Highlights
Core System
- Interactive
/setup— Answer 7 questions, get a complete personalized agent - 9 built-in skills —
/start,/end,/status,/research,/weekly-review,/extend,/reflect,/create-skill - 6 automated hooks — Bash safety, error logging, session management, context preservation
- 3-tier memory — State (hot), Knowledge (warm), Projects (cold) — all git-tracked markdown
Architecture
- Progressive disclosure — CLAUDE.md stays under 200 lines, details lazy-load
- Skills 2.0 — YAML frontmatter with
context: fork/inlineandallowed-tools - Auto-configured hooks —
/setupgeneratessettings.jsonautomatically
Compatibility
- Claude Code v2.1.71+ —
/loopintegration for periodic monitoring - Auto-memory — Coexists with Claude Code's built-in memory system
- Cross-platform — macOS and Linux hook scripts
Examples
5 complete, working setups included:
- Developer, Project Manager, Content Creator, Researcher, Founder
Quick Start
git clone https://github.com/onurpolat05/ALBA.git my-agent
cd my-agent
claude
# Then type: /setupWhat's Next
- Visual demo content (Remotion-based)
- Skill marketplace concept
- More role examples
- Community skill sharing
ALBA — Consistent. Independent. Always learning.