6.6 KiB
AIM add-on development contract
Core 3.3.0rc8; service/wire/event 1.0 (stable additive 1.x); Ansible Core 2.19.11. AIM is the independently usable Source of Truth. Add-ons own presentation, sessions, authorization at their application boundary, approvals, queues and persistence. They never patch Core, scrape terminal output or duplicate inventory/execution rules.
Integration sequence
Use aim.services.v1 or one aimctl request process per JSON-lines request. Discover
capabilities, current customers/hosts/hierarchy and catalog. Prepare explicit hosts and
declared options, show the normalized request and result contract for review, check
readiness under the actual worker identity, acquire a worker slot, collect fresh
credentials, and execute using the prepared revision. A stale revision requires review.
Omit unchanged options to preserve inventory/role-default precedence.
The published API is in scripts/docs/ADDON_API.md; the complete new result contract
is in scripts/docs/OPERATION_RESULTS.md. Current support and qualification are in
ADDON_SUPPORT.md and VALIDATION.md. Never infer feature support from product version
alone. capabilities.collection_baselines declares collection floors that add-on installers/operators must satisfy; Core does not upgrade them. Unknown optional response fields may be ignored; unknown errors fail safely.
Purposeful output: new in this candidate
Check capabilities.operation_results. Catalog result is null or a declaration with
schema, scope, required flag, limits and resolved data_schema. No new execute request
field is needed. Reports are available in summary and detail mode through the final
RunResult.operation_result and the existing final result event. There is no new raw
stdout event. Parse final JSON without scraping PLAY/TASK text or debug bodies.
A result contains hosts[host] with status, schema, data, error, plus optional
global. Render data only when status is available. Missing/withheld/invalid/null is
not an empty valid report. complete means all declared report slots arrived and passed
validation; it does not mean the operation succeeded. Partial native runs can contain
useful data from successful or failed targets. Preserve overall status/stage/exit,
remote_work_may_have_started, target summary and report availability as separate facts.
Never automatically retry a result_validation failure: remote changes may be complete.
Use a generic bounded JSON/table renderer for unknown schemas, with optional richer views for known schemas. Escape text/HTML/Rich markup. Do not treat null versions as zero, pending updates as installed, excluded services as failed starts, or redacted configuration values as absent settings. Config reports expose sections but redact recognized secret/command fields; restrict report visibility and retention accordingly.
Safety and identity
Core checks active OS group membership and filesystem access. This is same-UID local
execution, not per-browser-user RBAC or an untrusted-tenant sandbox. The execution
account owns its 0600 keys and private staging. service_user is not a local UID switch.
runtime.private_key_owner affects new keys only. Do not relax permissions, export keys,
add generic sudo wrappers or run the web frontend as root to bypass the boundary.
Hardened service installers must provision both applicable staging locations (process
HOME and passwd home) and narrow ReadWritePaths exceptions. Retain ProtectHome/read-only,
ProtectSystem/strict and private tmp protections. Run aimctl staging-check inside the
actual sandbox. Core does not create accounts, modify units or restart add-on services.
Use OneRunCredentials or a private inherited FD, never passwords in request JSON, argv, environment, URLs, logs, queue records or databases. Queue plans, not secrets. Fresh credentials are required for each attempt. Password inputs are native defaults, not Custom overrides or proof of password-only authentication. Cross-UID execution is not provided by Core; independently managed executors must already have authorized access.
Progress and final outcomes
progress_mode: detail is negotiated before preparation. Correlate play/task IDs,
handle withheld names and fixed error hints, and ignore anonymous progress to avoid
duplicate rows. Keep bounded queues and responsive sinks. Raw module/exception/debug
output remains unsupported. Purposeful data is a separate final schema, not an expansion
of host_result. Target outcomes come from Core's final native per-host stats, not task
counts. An interrupted/incomplete stream must not become partial success by inference.
Ownership and handoff
Core and add-ons release independently. Core deployment preserves add-on code/state, operator aim.yml, inventories, Vaults and keys; add-ons preserve Core in return. Use ZIP + checksum + the deployer, not Git or patches. Coordinate active jobs before source replacement. Only documented retired Core files are removed on upgrade.
The nine current report schemas are documented in OPERATION_RESULTS.md and advertised by the catalog. This candidate has local regression coverage, not new managed-host certification. Record independent acceptance under your actual identity/sandbox/runtime. Request new schemas/capabilities from Core instead of adding private output workarounds.
OS patch-wave presentation (3.3.0rc8)
Patch options remain catalog-driven. Interfaces should render the advertised reboot
message/delay and the Windows-only os_patching_rescan_after_reboot option. Its catalog
default is false; do not silently enable "fully patch" behavior in an add-on.
Windows submits the current selected categories as one native win_updates wave with
module-managed Windows Update sequencing and reboot: false. AIM evaluates reboot policy
after the wave returns; it does not expose or own a per-update scheduler. With post-reboot
continuation disabled, an AIM-performed reboot can still be a successful Core run while
continuation_required: true tells the operator another patch run is needed.
remaining_updates_known: false means the client must not invent or persist a next-wave
list. If a final read-only search was performed, remaining_updates_known: true makes
pending authoritative for that observation only.
Render failed_updates[].reason/message/native_code_hex instead of parsing fatal text or
Windows event logs. install_not_allowed deliberately does not mean "reboot required" by
itself. If Core reports blocked_reason: preexisting_reboot_required, that is the separate
preflight observation. Never auto-enable reboot, post-reboot continuation, or automatic job
replay.