Files
AIPass/CHANGELOG.md
T
AIOSAIandClaude Opus 4.8 668841417f fix(portability): aipass init UTF-8 stdout on Windows + CI e2e lane (DPLAN-0194)
The real T1 Windows bug (diagnosed via the now-reverted error-surfacing
probe): aipass init scaffolds fine, then crashes printing its success
banner — Rich writes the success glyphs through a cp1252 stdout
(UnicodeEncodeError 'charmap'). Same class as the drone fix. The aipass
entry point now reconfigure()s stdout/stderr to UTF-8 in place on Windows.

Also: ci.yml's broad 'pytest --rootdir=.' swept in tests/e2e (which build
a wheel via the dedicated e2e-wheel.yml), failing the unit lane since the
harness landed; now --ignore=tests/e2e in both pytest jobs.

route_command error-surfacing probe reverted to honor 'no function change'
(the masked-error mislabel is noted as a separate @aipass recommendation).

Local: e2e 14/14 green, aipass units 24/24, ruff clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 01:17:56 -07:00

18 KiB

Changelog

All notable changes to AIPass will be documented in this file.

The format is based on Keep a Changelog, and this project uses Calendar Versioning in the format YYYY.WNN (year and ISO week number).


[2026.W23] - 2026-06-02

Added

  • Cross-OS end-to-end WIRING test (tests/e2e/, e2e-wheel.yml) — the first CI gate that proves real AIPass wiring (not units-with-mocks) by building the wheel, installing it into a clean venv, and asserting a 4-tier ladder: package install + console scripts (T0), aipass init scaffolding (T1), a hook actually firing via the bridge with an observable engine.jsonl record (T2a), and drone resolving + subprocess-executing a real branch (T3). Runs on a 3-OS matrix (ubuntu/windows/macos, fail-fast: false). Ran red-first on Windows by design and immediately earned its keep — it caught two real, previously uncovered Windows wiring bugs (aipass init preflight + drone stdout encoding, both fixed below). Notably the layers we most feared — clean-wheel install (T0) and hook firing (T2a) — passed on Windows. (DPLAN-0194 / FPLAN-0239)
  • drone rm — provider-agnostic safe delete — a contained recursive delete that lets agents clean up scratch dirs without tripping the rm -rf block. Deletes are confined to the project root and the system temp dirs (/tmp and $TMPDIR), refusing anything outside (home, /etc, /, etc.). Even inside those roots it hard-refuses protected internals — .git, .trinity/, .aipass/, .codex/, .agents/, and sibling-branch worktrees — mirroring the filesystem boundary an OS-sandboxed agent (e.g. Codex) enforces, so behavior is consistent across CLIs. Pure-Python (shutil.rmtree), with a red-team test suite for containment escapes (symlinks, traversal, sibling branches). (#630)
  • rm_gate hook — block raw recursive rm, teach the safe path — a PreToolUse gate (mirroring git_gate) that blocks raw rm -r/-rf/-fr/ --recursive and redirects the agent to drone rm. Provider-agnostic (runs in the hook engine, not tied to Claude Code permission rules), conservative (unparseable targets are blocked, not allowed), and skips drone rm itself. This makes the safe-delete path discoverable at the moment of friction. (#630)
  • Hook engine logs agent_type / agent_id per fire — the engine now records which agent triggered each hook (e.g. agent=main vs agent=Explore) in both engine.jsonl and the prax monitor stream. Previously the payload flowed into handlers but was never logged, leaving no way to tell an internal main-turn fire from a real sub-agent fire. Pure visibility; no behavior change. Groundwork for #606. (#606)
  • OpenSSF Best Practices passing badge — AIPass earned the OpenSSF Best Practices (CII) passing badge (100% of criteria), added to the README badge cluster. Self-certified across all six categories — basics, change control, reporting, quality, security, and analysis. Complements the existing OpenSSF Scorecard, lifting the CII-Best-Practices check from 0. (DPLAN-0193)

Changed

  • Retired the blanket rm deny from provider settings — setup.sh and aipass init no longer ship Bash(rm -rf*) / Bash(rm -r *) deny rules (they were mis-filed among git rules, blocked all /tmp cleanup, and gave a bare "permission denied" with no guidance). The rm_gate hook + drone rm now own this — cross-provider, path-aware, and they teach. aipass doctor detects the stale rules on existing installs and aipass doctor --fix removes them (idempotent, preserves all other rules). Claude Code still natively circuit-breaks rm -rf / and rm -rf ~. (#630)

Fixed

  • Two latent Windows portability bugs caught by the new e2e harness — both were always present in the code; they only surfaced now because this is the first CI to run aipass init scaffolding and real-branch drone routing on Windows (the old Windows CI ran an editable install, aipass-less, and only routed to in-process modules, so both paths had zero Windows coverage). Pure portability fixes — Linux/macOS behaviour is unchanged.
    • aipass init crashed on Windows (surfaced as a misleading "Unknown command: init"). Init scaffolded the project correctly, then crashed printing its ✓ Project initialized banner — Rich wrote the ✓/box glyphs through a cp1252 stdout, raising UnicodeEncodeError ('charmap'); the error handler's ✗ message hit the same wall, bubbling up to the command router which mislabeled it. The aipass entry point now reconfigures stdout/stderr to UTF-8 in place on Windows. (The init preflight ancestor-walk was also hardened to skip un-enumerable Windows drive-root entries — defensive, not the trigger.)
    • drone @branch crashed on Windows with the same UnicodeEncodeError ('charmap'). drone resolved + subprocessed the branch correctly, then crashed printing the captured output through cp1252 stdout. The existing PYTHONUTF8 guard only affected child interpreters, not the live process streams — drone's entry point now also reconfigure()s stdout/stderr to UTF-8 in place.
    • CI unit lane no longer runs the e2e wheel tests. ci.yml's pytest --rootdir=. swept in tests/e2e/ (which build a wheel per the dedicated e2e-wheel.yml), failing the unit lane; it now --ignores them. (DPLAN-0194)
  • A release merge can no longer destroy the dev branch — drone @git merge passed --delete-branch to gh pr merge unconditionally, so merging a dev→main PR deleted the persistent dev branch on the remote and stranded the working tree on main (the next commit silently landing on main). Merge now looks up the PR's head ref and only deletes non-protected branches — dev and main are never deleted, and an undeterminable head ref fails safe (no delete). After a merge it returns the working tree to dev (loud warning if it can't). drone @git branches now runs fetch --prune before listing so it reflects the live remote instead of stale cached refs, and a new drone @git prune-temp cleans up merged temp PR branches. (#625)
  • drone @git status/diff show their scope — when scoped to a branch (no --all), output now appends "(showing scope — use --all for full repo)", so an empty scoped view is no longer mistaken for a clean repo. (#623)
  • External projects can call AIPass branches via drone — drone @api ... (and any drone @X) now resolves from a non-AIPass project CWD instead of being blocked with "path escapes project root." The resolver was validating a branch's path against the primary registry root even when the branch was found via the AIPASS_HOME fallback, so any external project (Vera Studio, Daemon) hit a false security block. resolve_branch() now validates containment against the registry the branch was actually found in. Security is unchanged — each branch is still contained within its own declaring registry's root; genuine path escapes remain blocked. (#618)
  • aipass <command> runs instead of printing an introspection banner — aipass is a user-facing binary, so aipass doctor (and every other command) must execute, not describe itself. All 7 modules (doctor, doctor_fix, doctor_wire, handoff, help_chat, init_flow, profile) previously hit a no-args→introspection gate (a standard meant for drone @branch <module> discovery) and showed a banner on bare invocation. Now bare invocation runs the command or shows usage; the introspection banner moved to --info. The seedgo introspection standard is bypassed for these binary-invoked modules (documented).
  • Dashboard plan counts no longer zeroed on refresh — a branch's active_plans was reset to 0 by every drone @prax dashboard refresh, because PLANS.central.json only held Flow's own plans (location==FLOW_ROOT filter). The central file is now comprehensive: all plans grouped per-branch, so refresh reports each branch's real count (e.g. devpulse now shows its 12 open plans instead of 0).

Security

  • Pinned the requests floor to a non-vulnerable version — raised requests to >=2.34.2 in pyproject.toml and the API branch's requirements.project.txt (which previously listed it unconstrained). This clears six OSV advisories the OpenSSF Scorecard flagged against the dependency (PYSEC-2014-13, PYSEC-2014-14, PYSEC-2018-28, GHSA-9wx4-h78v-vm56, GHSA-9hjg-9r4m-mvj7, GHSA-gc5v-m9x4-r6x2) — the oldest surfaced only because the dependency was declared without a version bound. No runtime change (the AIPass venv already ran a fixed release). (DPLAN-0193)
  • Pinned the test container base image by digest — Dockerfile.test now pins ubuntu:24.04 to its registry digest (sha256:786a8b55…) so the test image is reproducible and tamper-evident, clearing the Scorecard containerImage not pinned by hash finding. (DPLAN-0193)

[2026.W22] - 2026-05-30

Added

  • drone @hooks status — read-only viewer for a project's hook config: master switch, every hook's enabled state per event group, matchers, and an enabled/total summary. Resolves the project's .aipass/hooks.json by walking up from CWD. (DPLAN-0190 Phase B)
  • Hooks activate in every project — aipass init now writes .aipass/hooks.json, so new projects fire the hook engine out of the box (previously: no config shipped, 0 hooks fired). aipass init update union-merges the template, preserving any per-hook on/off choices the user made. aipass doctor now checks for the config's presence. Dead hook-script shipping (_ship_hooks) removed. (DPLAN-0190 Phase A)
  • README logo — centered logo image replaces plain # AIPass header. New assets/logo.png added to the repo.
  • OpenSSF Scorecard — .github/workflows/scorecard.yml runs the official OSSF Scorecard action on push to main and weekly. Publishes a public security health score at scorecard.dev with a README badge. Actions pinned by SHA.
  • GitHub Releases — publish.yml now cuts a GitHub Release on each v* tag, with notes pulled from the top CHANGELOG section and the built dist attached. PyPI publish + GitHub Release now fire from the same tag.
  • Registry descriptions — all 13 branches now have one-liner descriptions in AIPASS_REGISTRY.json. drone systems shows what each agent does instead of blank lines. Closes #607.

Changed

  • Security gates fully project-aware — both the edit gate and the subagent stop gate now derive the package name dynamically from CWD instead of hardcoding src/aipass/. Cross-branch write protection and branch detection work for any src/<package>/<branch>/ project; previously the subagent gate silently no-opped outside AIPass. 9 new external-project tests. Closes #605.
  • Hooks branch promoted to service — registry profile changed from "AIPass Workshop" to "library" so it appears in drone systems alongside the other 12 services.
  • Hooks branch hardened to 100% seedgo — the @hooks citizen took full ownership of its branch: every handler verified wired + firing, README rewritten (two-tier provider/project model, dynamic-dispatch design, event table), 2 stale tests resolved (253 pass). Dead-code/unused-function flags documented as architectural bypasses — the 15 handlers are invoked dynamically via importlib from hooks.json paths, never statically imported. (DPLAN-0191)

Release

  • Version 2.5.0 published to PyPI. Trusted publishing via GitHub Actions (publish.yml triggers on v* tags — no manual twine upload needed). The same tag now also cuts a GitHub Release with these notes attached.

Removed

  • Gemini CLI full removal — deleted .gemini/ directory (5 files) and GEMINI.md. Stripped all references from setup.sh (~50 lines), README.md, bug-report.yml, aipass init (bootstrap/scaffold/test), hooks (README/prompt/passport), and prax monitoring (~300 lines). 21 files changed, -927 lines. Closes #608.

[2026.W21] - 2026-05-25

First weekly release. AIPass now follows a Sunday release cadence: changes accumulate on dev throughout the week and merge to main as a single versioned release with notes.

Added

  • Hook engine — a new centralized dispatch system for all hook execution. A thin bridge receives events from the AI provider (Claude, Codex, etc.) and routes them through a single Python engine that reads per-project configuration, executes the appropriate handlers, and logs every invocation. Replaces 14 standalone shell/Python scripts with native handler modules organized by domain: prompt injection, security enforcement, lifecycle management, and notifications.
  • Per-project hook configuration via .aipass/hooks.json. Each project can enable, disable, or customize individual hooks without touching provider-level settings. Previously hooks fired globally with no per-project control.
  • Audio feedback on hook events using Piper TTS. All 14 handlers produce distinct spoken audio cues so operators can monitor sessions without watching the terminal. A shared sound module (hooks/apps/sound.py) provides speak() and play() with built-in mute support. Toggle with drone @hooks hooksound on|off — muting silences all 14 handlers without skipping their functional logic.
  • Hooks agent — the 13th citizen in the AIPass registry, owning all hook infrastructure: the engine, bridge, handlers, and configuration schema.
  • Dashboard plugin for devpulse — aggregates git status, session history, and dispatch state into a single startup view. Wired into the session startup protocol so branch managers see current state immediately.
  • External log routing — prax now accepts structured log entries from any branch, not just its own modules. Hook executions, dispatches, and agent activity all flow into the central monitoring log.

Changed

  • Provider settings fully migrated to bridge pattern. All hook entries in the Claude provider configuration now call the bridge dispatcher instead of individual scripts. Each hook produces its own system-reminder to the model, preserving prompt injection fidelity (a single merged bridge was found to break prompt delivery due to Claude Code's output persistence threshold).
  • setup.sh rewritten to install hooks via the bridge pattern. The old version hardcoded 14 script paths; the new version writes a single bridge call per event type and validates that the bridge module exists.
  • Documentation sweep across .claude/README.md, SECURITY.md, the global prompt, and branch-level docs to reflect the new hook architecture. References to legacy .claude/hooks/ scripts replaced with the native handler locations.
  • aipass init update now correctly preserves user-customized hook settings during project updates instead of overwriting them.
  • Seedgo snapshot tests rebuilt — the provider hooks snapshot fixture and extraction logic were structurally broken (silently passing with zero results). Both the fixture format and the test assertions have been corrected.
  • Test suite updated for hook migration — test_git_gate.py imports from the new handler module; test_bootstrap.py no longer asserts that project initialization ships standalone hook scripts (it no longer does).

Fixed

  • Settings merge on project update — aipass init update was clobbering user hook configurations. The merge logic now layers AIPass defaults under existing user settings.
  • Python 3.10 test collision — a module/function name collision caused mock patch targets to fail on Python 3.10. Test targets corrected.
  • Dead code removal — removed an unused CLI __main__.py entrypoint and cleaned up .gitignore entries that were masking tracked files.
  • Codecov patch threshold lowered to 50% to reflect the project's current coverage baseline and stop false-negative CI failures.

Removed

  • 18 standalone hook scripts in .claude/hooks/ disabled (renamed with (disabled) suffix). Their logic now lives in native handler modules under src/aipass/hooks/apps/handlers/. The old files remain on disk for reference but are no longer executed.
  • drone hook-sounds plugin disabled. Sound control moved to hooks branch as drone @hooks hooksound on|off with full mute support for all 14 handlers (the old plugin only controlled 4).

Infrastructure

  • Provider manifest migrated to bridge pattern. provider_manifest.json now stores bridge commands ($AIPASS_HOME/...bridges/claude.py EventType) instead of standalone script names. doctor_wire.py auto-wires bridge entries directly — no longer copies scripts to ~/.claude/hooks/ or generates sys.executable paths. Doctor checks validate commands exist in provider settings instead of checking for script files on disk.
  • README v3 — rewritten for external users. Tighter problem/solution framing, collapsible agent details, Gemini CLI removed (untested), user-project perspective throughout.
  • Inline handoff (aipass init run Step 11) — new default stays in the current terminal via os.execvp instead of opening a new window. Users choose "stay here" or "new window." Enables single-terminal demo recordings. Closes #610.
  • Project-aware global prompt — the global prompt loader now detects whether CWD is inside AIPass or an external project. External projects receive their own lighter prompt (from .aipass/aipass_global_prompt.md) instead of the full AIPass-internal playbook. Fixes drone @prax errors in new projects.
  • Project CLAUDE.md template — aipass init now generates a project-specific CLAUDE.md from .aipass/project_CLAUDE.md instead of copying the AIPass-internal one. Removes the startup protocol reference to drone @prax dashboard refresh which doesn't exist in external projects.
  • Gemini CLI removed from aipass init CLI choices and handoff options. GEMINI.md no longer created for new projects. Gemini CLI is being retired upstream.
  • Demo GIF added to assets/demo.gif and referenced in README.

This is the first CHANGELOG entry. Prior work is documented in the repository's commit history and branch session logs.