# AIM core ZIP deployment - 3.3.0rc8 This standard-library operational helper installs a complete source release and its two source-bound command launchers. No Git, patch files, release manifest, package installation, add-on inspection or account/group migration is used. Python 3.11+ on Linux is required. Development validators are not distributed. ## Verify and preview Obtain the ZIP and its SHA-256 sidecar through a trusted channel. The sidecar is an integrity check, not a publisher signature. Stage outside the installation tree: ```bash cd /var/tmp sha256sum -c AIM-Ansible-3.3.0rc8.zip.sha256 unzip AIM-Ansible-3.3.0rc8.zip cd aim-core-3.3.0rc8 sudo python3 deploy/deploy.py update --dry-run ``` The target defaults to `/etc/ansible`. `update` requires existing core source; `install` is for a fresh tree. Preview is the default without `--apply`. Do not extract over the live installation. Source and target must not overlap; symlink paths and unexpected source files are rejected. 3.3.0rc8 checks the existing **AIM** Python interpreter before making changes. It can infer it only from an unambiguous installed `aim` Python shebang. It does not assume that `sudo python3`, the Ansible interpreter or an add-on environment contains AIM's dependencies. It preserves a virtual environment's Python path without resolving its symlink to the system Python. When discovery is unavailable (for example sudo has a different PATH), provide the already identified AIM interpreter explicitly. In the operator test session, `AIM_PYTHON` is the interpreter that successfully ran `scripts/aimctl.py`: ```bash test -x "$AIM_PYTHON" || { echo 'Set AIM_PYTHON to the existing AIM interpreter first.'; exit 1; } sudo python3 deploy/deploy.py update --aim-python "$AIM_PYTHON" --dry-run ``` Shell wrappers and `#!/usr/bin/env ...` shebangs are not guessed. The interpreter must be an absolute executable Python 3.11+ path with no spaces (up to 120 characters), and must already contain the dependencies from `scripts/pyproject.toml`. ## Command directory and multiple installations The preview prints the chosen interpreter, command directory, source operations and `@launchers/aim` / `@launchers/aimctl` operations. `@launchers` is a journal identifier, not a directory shipped in the source archive. By default the command directory is the existing `aim` command's parent directory, or `/usr/local/bin` when no command exists and an interpreter was supplied. Override with `--bin-dir /absolute/command/directory`. A nondefault `--target` **requires** its own explicit `--bin-dir` so development deployment cannot silently replace production commands. Use the same chosen interpreter/directory on preview and apply. Only recognized AIM Python entry scripts or AIM-managed launchers for this target may be replaced. Unrelated programs, unsafe symlink command destinations and launchers for another installation are refused. There is no automatic force-overwrite escape hatch. Choose a reviewed unused command directory when the existing layout is nonstandard. Ensure the selected directory is on the intended operator's PATH; aliases and another installation earlier on PATH remain the operator's responsibility. ## Apply while quiesced Stop new jobs and exit active AIM/Ansible sessions. `--quiesced` acknowledges that source writers/runners have been stopped; it does not discover, kill or pause jobs. ```bash sudo python3 deploy/deploy.py update --apply --quiesced # Include the same --aim-python and --bin-dir options used in the preview, if any. hash -r command -v aim command -v aimctl aim --version aimctl --version aimctl capabilities ``` The helper verifies the installed `aim --version` and `aimctl capabilities` against the source release before reporting success. It uses an explicit installed config path for its capability check. It does not invoke Ansible or contact managed hosts. Both launchers import the deployed `scripts/src/aim` source with the selected AIM Python. Old launchers and core source are included in protected recovery data. A stable deployment lock prevents another cooperating deployment. Each source file is replaced atomically, preserving existing UID/GID/mode/extended attributes. New source files use 0644; new launchers use 0755, and recognized existing launchers retain their metadata with executable bits enabled. Directories use normal caller ownership/inheritance. This is not a recursive ownership-policy migration. Recovery defaults to `/var/backups/aim-core`; the helper prints the exact private 0700 recovery directory. `--backup-dir /private/path` selects another root outside source and installation. Keep sufficient space and apply your retention policy. Obsolete files inside `scripts/src/aim/` and the explicitly retired Core documents below are pruned. Unknown customer files in other locations are retained. Add-on code must use its own namespace, not the core Python namespace. **Preserved when present:** operator `scripts/aim.yml`, customer `.aim.yml`, inventories, Vaults, SSH keys, add-ons and their state/configuration, environments, external assets, unknown playbooks/roles and staged agent files. No dependencies, services, accounts, LDAP/local group memberships, remote credentials or add-on version gates are modified. Missing new settings are not automatically inserted into an operator's existing YAML. ## Python package and runtime scope These launchers are source-bound entry points, not a pip reinstall. The helper does not change installed wheel/distribution metadata or upgrade packages. Machine clients calling the installed `aimctl` reach the deployed source. In-process Python clients must also resolve `aim` to this source (for example an existing editable installation or an explicitly configured source import path), not an old separately installed wheel. Verify `aim.__file__` and `aim.__version__` in that client's own environment. No add-on's Python environment is changed by core deployment. For a fresh installation, provision an AIM Python 3.11+ environment and its declared `ruamel.yaml`/`rich` dependencies first, then pass that interpreter to `install`. Provide the separate canonical Ansible Core **2.19.11** runtime and approved collections from `requirements-controller.txt` / `requirements.yml` explicitly. The helper does not install from the network or mutate a system-managed Ansible installation. For a nondefault controller root, maintain that installation's operator configuration and use `aimctl --config /absolute/root/scripts/aim.yml ...` when necessary. Existing terminal configuration discovery is unchanged; creating another launcher does not silently redirect a terminal's global configuration. ## Opt-in API execution Follow `scripts/docs/SANITY.md` (historical evidence is in `scripts/docs/VALIDATION.md`). External execution remains disabled by default and is not enabled by deployment, readiness or the launcher smoke test. Preserve the existing YAML and merge only deliberately approved settings: ```yaml addons: execution_enabled: true runtime: ansible_playbook: /usr/bin/ansible-playbook ``` The executable path is the operator's approved native runtime, not an assumption for every installation. Worker authorization, filesystem/key access, collections, connection dependencies and same-UID execution still apply. Do not make private keys group-readable to bypass an unsupported cross-user deployment. ## Recovery and interruption Ordinary application/launcher-check failures attempt to restore touched source and launchers. The update is not a whole-tree atomic transaction: power loss or SIGKILL can leave partial source. Keep jobs stopped until recovery/version checks complete. Recovery journals contain intent, hashes and original metadata; they are local recovery records, not a distributed release manifest or inventory backup. Use this 3.3.0rc8 deployer and the printed recovery directory; include the same target for a nondefault installation. Launcher paths are recorded in the journal. ```bash sudo python3 deploy/deploy.py rollback --from-backup /var/backups/aim-core/RECOVERY-DIRECTORY --dry-run sudo python3 deploy/deploy.py rollback --from-backup /var/backups/aim-core/RECOVERY-DIRECTORY --apply --quiesced hash -r aim --version ``` Rollback validates installed/recovery hashes and refuses to overwrite subsequently modified source or launchers. Existing aim.yml is never rolled back or removed, even after a fresh install. Empty directories may remain. A newly created aimctl launcher is removed when restoring a previous release that had no such launcher. No remote Ansible action, dependency installation, account/group change or add-on state is reversed. Keep independent backups of runtime/customer data. ## Required executor staging (independently provisioned units) Read `scripts/docs/EXECUTOR_STAGING.md` in the installed tree. New add-on executor installers should provision owner-only staging and a narrow directory write exception by default, then run `aimctl staging-check` inside the actual unit at startup. Ordinary `sudo -u` success does not reproduce mount/syscall restrictions. The source deployer does not inspect/edit/restart services. It preserves the working exception already applied by the operator. The automatic Core preflight is on by default, but cannot make a read-only mount writable. Do not remove the exception, broaden home write access or recursively chown anything during this update. The new startup command is available after the normal launcher refresh. ## Documentation consolidation in 3.3.0rc8 Current docs have stable topic names with one validation record and one acceptance checklist. Upgrade removes only these explicitly retired Core filenames (with protected rollback copies), including locally modified versions of those exact files: - scripts/docs/RC19_HANDOFF.md - scripts/docs/SANITY_3.2.0.md - scripts/docs/SANITY_3.2.1rc2.md - scripts/docs/VERIFICATION.md - scripts/docs/LOCAL_VALIDATION.md - scripts/docs/CONTROLLER_ACCEPTANCE.md Review REMOVE entries before applying. Move any operator notes out of these retired Core-owned names before deployment. Unknown Markdown files and other operator documents are preserved. Rollback restores retired document bytes/metadata through the existing recovery journal. No recursive docs purge or runtime deletion occurs. The new playbooks/filter_plugins/*.py files and playbooks/schemas/*.yml files are Core-owned reporting source. They are deployed with the playbooks; no add-on Python environment or collection is modified.