diff --git a/README.md b/README.md
index cf73b9357b6a5d9bd18dfbd402db81aa95056eb7..011ba8374b52fba8d12bbd01aeb4adafb335a6f5 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,14 @@ lima_kilo_kind_binary_path: /usr/local/bin/kind
 
 # Set to false to prevent managing a shortcut in /etc/hosts for kind.
 lima_kilo_manage_etc_hosts_shortcut_for_kind: true
+
+# Set to false if you prefer to manage the helm binary installation on your own.
+lima_kilo_manage_helm_installation: true
+lima_kilo_helm_binary_path: /usr/local/bin/helm
+
+# Set to false if you prefer to manage the helmfile binary installation on your own.
+lima_kilo_manage_helmfile_installation: true
+lima_kilo_helmfile_binary_path: /usr/local/bin/helmfile
 ```
 Hint: you may use this mechanism to override any other internal lima-kilo variable.
 
diff --git a/playbooks/kind-install.yaml b/playbooks/kind-install.yaml
index 16066d7b16782b5aec0bafd9a9d54050a4411290..c066cd32d21eb894d4671a59e99b3d7997d8a6ed 100644
--- a/playbooks/kind-install.yaml
+++ b/playbooks/kind-install.yaml
@@ -9,9 +9,11 @@
     - vars/kubectl.yaml
     - vars/toolforge.yaml
     - vars/k8s.yaml
+    - vars/helm.yaml
   roles:
     - { role: userconfig }
     - { role: toolforge }
     - { role: kind }
     - { role: kubectl }
+    - { role: helm }
     - { role: k8s }
diff --git a/playbooks/kind-uninstall.yaml b/playbooks/kind-uninstall.yaml
index e9325f76282a5de6d8af457c2c33c3ff0cf3ee65..8796ea203bc86b6d8014c2dc53163e4ac63d1a36 100644
--- a/playbooks/kind-uninstall.yaml
+++ b/playbooks/kind-uninstall.yaml
@@ -12,4 +12,5 @@
     - { role: kind }
     - { role: toolforge }
     - { role: kubectl }
+    - { role: helm }
     - { role: k8s }
diff --git a/playbooks/vars/helm.yaml b/playbooks/vars/helm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3383fbf5b3100d0b491e18494d426785108bc2b4
--- /dev/null
+++ b/playbooks/vars/helm.yaml
@@ -0,0 +1,29 @@
+---
+helm:
+  # refresh versions from
+  # https://github.com/helm/helm/releases
+  version: 3.11.1
+  version_command: helm version --short
+  platform:
+    Linux:
+      url: https://get.helm.sh/helm-v3.11.1-linux-amd64.tar.gz
+      checksum: sha256:0b1be96b66fab4770526f136f5f1a385a47c41923d33aab0dcb500e0f6c1bf7c
+      unpack: true
+    Darwin:
+      url: https://get.helm.sh/helm-v3.11.1-darwin-amd64.tar.gz
+      checksum: sha256:2548a90e5cc957ccc5016b47060665a9d2cd4d5b4d61dcc32f5de3144d103826
+      unpack: true
+helmfile:
+  # refresh versions from
+  # https://github.com/helmfile/helmfile/releases
+  version: 0.151.0
+  version_command: helmfile -v | awk '{print $3}'
+  platform:
+    Linux:
+      url: https://github.com/helmfile/helmfile/releases/download/v0.151.0/helmfile_0.151.0_linux_amd64.tar.gz
+      checksum: sha256:f33bdad8c1c7081cc95a858c4d307baf419f03d77758fae26ac8625725b398d9
+      unpack: true
+    Darwin:
+      url: https://github.com/helmfile/helmfile/releases/download/v0.151.0/helmfile_0.151.0_darwin_amd64.tar.gz
+      checksum: sha256:55128a0fc18f8f9f864eb5eeb53f94751a8f273c767122820bb51a10f02dba82
+      unpack: true
diff --git a/playbooks/vars/kind.yaml b/playbooks/vars/kind.yaml
index b4f1537f28f5e63cbc9b07ec515070a145be8365..8a159dcbe1e75647610c34a86d34ca253691d733 100644
--- a/playbooks/vars/kind.yaml
+++ b/playbooks/vars/kind.yaml
@@ -8,9 +8,11 @@ kind:
     Linux:
       url: https://kind.sigs.k8s.io/dl/v0.17.0/kind-linux-amd64
       checksum: sha256:a8c045856db33f839908b6acb90dc8ec397253ffdaef7baf058f5a542e009b9c
+      unpack: false
     Darwin:
       url: https://kind.sigs.k8s.io/dl/v0.17.0/kind-darwin-amd64
       checksum: sha256:a4e9f4cf18ec762934f4acd68752fe085bcded3a736258de0367085525180342
+      unpack: false
   extra_forward_ports:
     - 30001  # jobs-api
     - 30002  # ingress-nginx
diff --git a/playbooks/vars/kubectl.yaml b/playbooks/vars/kubectl.yaml
index 35bce3f754bcca4279f2d760777c9ad00a19ec1b..57c1eb15fed41f74d65d47771a4fbb65b57e9692 100644
--- a/playbooks/vars/kubectl.yaml
+++ b/playbooks/vars/kubectl.yaml
@@ -8,6 +8,8 @@ kubectl:
     Linux:
       url: https://dl.k8s.io/release/v1.26.2/bin/linux/amd64/kubectl
       checksum: sha256:fcf86d21fb1a49b012bce7845cf00081d2dd7a59f424b28621799deceb5227b3
+      unpack: false
     Darwin:
       url: https://dl.k8s.io/release/v1.26.2/bin/darwin/amd64/kubectl
       checksum: sha256:f5cc3c01e9b87523c4f25353b8c9c8a57a0b2d6074b0f64cabc181280a4a1822
+      unpack: false
diff --git a/roles/helm/defaults/main.yaml b/roles/helm/defaults/main.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..93994baa0ce2973c1c03b56ad00a30e4d93ce99b
--- /dev/null
+++ b/roles/helm/defaults/main.yaml
@@ -0,0 +1,6 @@
+---
+lima_kilo_manage_helm_installation: true
+lima_kilo_helm_binary_path: /usr/local/bin/helm
+
+lima_kilo_manage_helmfile_installation: true
+lima_kilo_helmfile_binary_path: /usr/local/bin/helmfile
diff --git a/roles/helm/tasks/install.yaml b/roles/helm/tasks/install.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f4b11ae6e86f0ce3131b44cdda7796cd2b8e88e8
--- /dev/null
+++ b/roles/helm/tasks/install.yaml
@@ -0,0 +1,32 @@
+---
+- name: Install helm binary
+  ansible.builtin.include_tasks: "{{ role_path }}/../utils/tasks/install-binary-from-url.yaml"
+  when: lima_kilo_manage_helm_installation
+  vars:
+    binary:
+      name: "helm"
+      version: "{{ helm.version }}"
+      version_command: "{{ helm.version_command }}"
+      path: "{{ lima_kilo_helm_binary_path }}"
+      url: "{{ helm.platform[ansible_system].url }}"
+      checksum: "{{ helm.platform[ansible_system].checksum }}"
+      unpack: "{{ helm.platform[ansible_system].unpack }}"
+
+- name: Install helmfile binary
+  ansible.builtin.include_tasks: "{{ role_path }}/../utils/tasks/install-binary-from-url.yaml"
+  when: lima_kilo_manage_helmfile_installation
+  vars:
+    binary:
+      name: "helmfile"
+      version: "{{ helmfile.version }}"
+      version_command: "{{ helmfile.version_command }}"
+      path: "{{ lima_kilo_helmfile_binary_path }}"
+      url: "{{ helmfile.platform[ansible_system].url }}"
+      checksum: "{{ helmfile.platform[ansible_system].checksum }}"
+      unpack: "{{ helmfile.platform[ansible_system].unpack }}"
+
+# this install all helm plugin dependencies
+- name: Run helmfile init
+  ansible.builtin.command: helmfile init --force
+  register: init
+  changed_when: "'Installed plugin' in init.stderr"
diff --git a/roles/helm/tasks/main.yaml b/roles/helm/tasks/main.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d29b43ee2d7d35ed738e86b229e6b365bd45a42e
--- /dev/null
+++ b/roles/helm/tasks/main.yaml
@@ -0,0 +1,8 @@
+---
+- name: Target action -> install helm
+  ansible.builtin.include_tasks: install.yaml
+  when: target == 'install'
+
+- name: Target action -> uninstall helm
+  ansible.builtin.include_tasks: uninstall.yaml
+  when: target == 'uninstall'
diff --git a/roles/helm/tasks/uninstall.yaml b/roles/helm/tasks/uninstall.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3d1b0aa8f16e0ab613fe4b845be6cf7edea275ef
--- /dev/null
+++ b/roles/helm/tasks/uninstall.yaml
@@ -0,0 +1,14 @@
+---
+- name: Delete helm
+  become: true
+  ansible.builtin.file:
+    dest: "{{ lima_kilo_helm_binary_path }}"
+    state: absent
+  when: lima_kilo_manage_helm_installation
+
+- name: Delete helmfile
+  become: true
+  ansible.builtin.file:
+    dest: "{{ lima_kilo_helmfile_binary_path }}"
+    state: absent
+  when: lima_kilo_manage_helmfile_installation
diff --git a/roles/kind/tasks/install.yaml b/roles/kind/tasks/install.yaml
index 76dc9ca78352570baf7288b38faa6f8d6e3f1afb..70778cdbd5bb2ce1200ec8c11a8a92a8faa9efa3 100644
--- a/roles/kind/tasks/install.yaml
+++ b/roles/kind/tasks/install.yaml
@@ -10,6 +10,7 @@
       path: "{{ lima_kilo_kind_binary_path }}"
       url: "{{ kind.platform[ansible_system].url }}"
       checksum: "{{ kind.platform[ansible_system].checksum }}"
+      unpack: "{{ kind.platform[ansible_system].unpack }}"
 
 - name: Install kind configuration file
   ansible.builtin.template:
diff --git a/roles/kubectl/tasks/install.yaml b/roles/kubectl/tasks/install.yaml
index 13edacfd791e2dafab3b588d7619b6a63ab4451b..cf50d8c80fc6628e6e1c624727ddf3a7913df62e 100644
--- a/roles/kubectl/tasks/install.yaml
+++ b/roles/kubectl/tasks/install.yaml
@@ -10,3 +10,4 @@
       path: "{{ lima_kilo_kubectl_binary_path }}"
       url: "{{ kubectl.platform[ansible_system].url }}"
       checksum: "{{ kubectl.platform[ansible_system].checksum }}"
+      unpack: "{{ kubectl.platform[ansible_system].unpack }}"
diff --git a/roles/utils/tasks/install-binary-from-url.yaml b/roles/utils/tasks/install-binary-from-url.yaml
index bb66370b24a2af11c7e8a891481d88f1b9423271..91cbc072b8d771f9b36a47293a2c411701b24c37 100644
--- a/roles/utils/tasks/install-binary-from-url.yaml
+++ b/roles/utils/tasks/install-binary-from-url.yaml
@@ -6,6 +6,7 @@
 #   version_command: string
 #   path: string
 #   url: string
+#   unpack: bool
 
 - name: Verify binary file status for '{{ binary.name }}'
   ansible.builtin.stat:
@@ -27,6 +28,7 @@
   when: >
     filecheck.stat.executable is not defined or
     not filecheck.stat.executable or
+    filecheck.stat.mimetype != "application/x-executable" or
     version is not defined or
     version is defined and binary.version not in version.stdout
 
@@ -38,15 +40,41 @@
     mode: "0644"
   when: tempdir.path is defined
 
+- name: Unpack '{{ binary.name }}'
+  ansible.builtin.unarchive:
+    src: "{{ tempdir.path }}/{{ src }}"
+    dest: "{{ tempdir.path }}"
+    remote_src: true
+  vars:
+    src: "{{ binary.url.rsplit('/', 1)[-1] }}"
+  when: tempdir.path is defined and binary.unpack
+
+- name: Find the right file to install for '{{ binary.name }}'
+  # we don't really know where is the file we want to install,
+  # specially if inside an unpacked archive
+  # this search should work for both raw/unpacked binaries
+  ansible.builtin.find:
+    path: "{{ tempdir.path }}"
+    pattern: "*{{ binary.name }}*"
+    recurse: true
+    excludes:
+      - "*tar.gz"
+      - "*tar.bz2"
+      - "*tar"
+  register: find
+  when: tempdir.path is defined
+  # assert: something is really wrong if we couldn't find a file to install
+  failed_when: find.matched < 1
+
 - name: Install '{{ binary.name }}'
   become: true
   ansible.builtin.copy:
-    src: "{{ tempdir.path }}/{{ src }}"
+    src: "{{ src }}"
     dest: "{{ binary.path }}"
     mode: "0755"
     remote_src: true
   vars:
-    src: "{{ binary.url.rsplit('/', 1)[-1] }}"
+    src: "{{ find.files[0].path }}"
   when: tempdir.path is defined
 
 - name: Remove temp dir