Date: 2026-05-11
Time: 15:10
This page traces FTL2's development chronologically from February 5-11, covering the evolution from core architecture through modules, event streaming, the automation context API, gate-based remote execution, native modules, state management, dependency tracking, audit/replay, the policy engine, inventory formats, and Vault integration. It reveals the design motivations and performance rationale behind each subsystem.
ansible-playbookcommunity.general.slack) to locate actual module filescopy, template, fetch, shell, swap, ping, wait_for) skip Ansible module machinery entirely for maximum speed.ftl2-state.json) tracks dynamically provisioned hosts/resources; loaded on context enter for crash recovery and idempotent provisioningPolicyDeniedError; evaluated on both local and remote execution pathspath#field references; reads grouped by path to minimize API calls; hvac is optional (pip install ftl2[vault])load_inventory() handles executable scripts, JSON (Ansible --list format), or YAML transparentlyAutomation context:
async with automation(inventory="hosts.yml", secret_bindings={...}) as ftl:
await ftl.file(path="/tmp/test", state="directory")
await ftl.run_on("webservers", "dnf", name="nginx", state="present")
Host-scoped access: ftl["hostname"].module() — bracket notation supports host names with dashes
Dynamic hosts: add_host() persists to state immediately
Event listening: await ftl.listen() for persistent monitoring (inotify, metrics)
Audit/replay:
record="audit.json"replay="audit.json" — skips successful actions, resumes from first failureVault secrets: vaultsecrets parameter maps names to path#field; uses VAULTADDR/VAULT_TOKEN env vars; accessed via ftl.secrets["NAME"]
Dependency files: .ftl2-deps.txt (Python requirements), .ftl2-modules.txt (module names for gate building)
Gate cache location: ~/.ftl per user
add_host() writes to state; state reloaded on context enter enables crash recoveryexecute() (local) and executeon_host() (remote) paths.ftl2-modules.txt feeds the gate builder to know which modules to bake inansible-inventory --list output directly, bridging existing dynamic inventory plugins~/.ftl per user.ftl2-state.json; dependency file is .ftl2-deps.txt; module list is .ftl2-modules.txtload_inventory() auto-detects three formats: executable scripts, JSON, YAMLmodule, host, environment, param.<name>PolicyDeniedError — it's first-match, not most-specificpip install ftl2[vault] (hvac is optional)add_host() persists to state immediately (not at context exit)Policy.empty() exists for backward compatibility