diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0af4aa2..c9591c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,13 @@
 
 [Unreleased]: https://github.com/chaostoolkit/chaostoolkit-lib/compare/0.13.1...HEAD
 
+### Changed
+
+-   Do not fail the discovery when an extension is missing the `__all__`
+    attribute [#28][28]
+
+[28]: https://github.com/chaostoolkit/chaostoolkit-lib/issues/28
+
 ## [0.13.1][] - 2018-01-30
 
 [0.13.1]: https://github.com/chaostoolkit/chaostoolkit-lib/compare/0.13.0...0.13.1
diff --git a/chaoslib/discovery/discover.py b/chaoslib/discovery/discover.py
index 73fe118..20ad862 100644
--- a/chaoslib/discovery/discover.py
+++ b/chaoslib/discovery/discover.py
@@ -10,6 +10,7 @@ from logzero import logger
 from chaoslib import __version__
 from chaoslib.discovery.package import get_discover_function, install,\
     load_package
+from chaoslib.exceptions import DiscoveryFailed
 from chaoslib.types import Discovery, DiscoveredActivities
 
 
@@ -88,11 +89,18 @@ def discover_activities(extension_mod_name: str,
         mod = importlib.import_module(extension_mod_name)
     except ImportError:
         raise DiscoveryFailed(
-            "could not import Python module '{m}'".format(
+            "could not import extension module '{m}'".format(
                 m=extension_mod_name))
 
     activities = []
-    exported = getattr(mod, "__all__")
+    try:
+        exported = getattr(mod, "__all__")
+    except AttributeError as e:
+        logger.warn("'{m}' does not expose the __all__ attribute. "
+                    "It is required to determine what functions are actually "
+                    "exported as activities.".format(m=extension_mod_name))
+        return activities
+
     funcs = inspect.getmembers(mod, inspect.isfunction)
     for (name, func) in funcs:
         if exported and name not in exported:

Do not fail on discovery of module which don't export __all__
Right now the discovery mechanism expects module to have a `__all__` attribute. Do not fail when it is missing.
diff --git a/tests/fixtures/fakeext.py b/tests/fixtures/fakeext.py
new file mode 100644
index 0000000..ed72c69
--- /dev/null
+++ b/tests/fixtures/fakeext.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+
+__all__ = ["many_args", "no_args_docstring", "no_args", "one_arg",
+           "one_untyped_arg", "one_arg_with_default",
+           "one_untyped_arg_with_default"]
+
+
+def no_args_docstring():
+    pass
+
+
+def no_args():
+    """
+    No arguments.
+    """
+    pass
+
+
+def one_arg(message: str):
+    """
+    One typed argument.
+    """
+    pass
+
+
+def one_arg_with_default(message: str="hello"):
+    """
+    One typed argument with a default value.
+    """
+    pass
+
+
+def one_untyped_arg(message):
+    """
+    One untyped argument.
+    """
+    pass
+
+
+def one_untyped_arg_with_default(message = "hello"):
+    """
+    One untyped argument with a default value.
+    """
+    pass
+
+
+def many_args(message: str, colour: str="blue"):
+    """
+    Many arguments.
+    """
+    pass
diff --git a/tests/fixtures/keepempty.py b/tests/fixtures/keepempty.py
new file mode 100644
index 0000000..db5dc66
--- /dev/null
+++ b/tests/fixtures/keepempty.py
@@ -0,0 +1,5 @@
+# just keep this as-is
+
+
+def not_an_activity():
+    print("boom")
diff --git a/tests/test_discover.py b/tests/test_discover.py
index 216d379..13bf346 100644
--- a/tests/test_discover.py
+++ b/tests/test_discover.py
@@ -5,5 +5,98 @@ import pytest
 
 from chaoslib.exceptions import DiscoveryFailed
 from chaoslib.discovery import discover, initialize_discovery_result
+from chaoslib.discovery.discover import discover_activities
 from chaoslib.types import Discovery, DiscoveredActivities, \
     DiscoveredSystemInfo
+
+
+def test_fail_discovery_when_module_cannot_be_loaded():
+    with pytest.raises(DiscoveryFailed) as exc:
+        discover_activities("fixtures.burp", "probe")
+    assert "could not import extension module" in str(exc)
+
+
+def test_do_not_fail_when_extension_mod_has_not_all():
+    activities = discover_activities("fixtures.keepempty", "probe")
+    assert len(activities) == 0
+
+
+def test_discover_all_activities():
+    mod = "fixtures.fakeext"
+    activities = discover_activities(mod, "probe")
+    assert len(activities) == 7
+
+    activity = activities[0]
+    assert activity["name"] == "many_args"
+    assert activity["type"] == "probe"
+    assert activity["mod"] == mod
+    assert activity["doc"] == "Many arguments."
+    assert activity["arguments"] == [
+        {
+            "name": "message"
+        },
+        {
+            "name": "colour",
+            "default": "blue"
+        }
+    ]
+
+    activity = activities[1]
+    assert activity["name"] == "no_args"
+    assert activity["type"] == "probe"
+    assert activity["mod"] == mod
+    assert activity["doc"] == "No arguments."
+    assert activity["arguments"] == []
+
+    activity = activities[2]
+    assert activity["name"] == "no_args_docstring"
+    assert activity["type"] == "probe"
+    assert activity["mod"] == mod
+    assert activity["doc"] == None
+    assert activity["arguments"] == []
+
+    activity = activities[3]
+    assert activity["name"] == "one_arg"
+    assert activity["type"] == "probe"
+    assert activity["mod"] == mod
+    assert activity["doc"] == "One typed argument."
+    assert activity["arguments"] == [
+        {
+            "name": "message"
+        }
+    ]
+
+    activity = activities[4]
+    assert activity["name"] == "one_arg_with_default"
+    assert activity["type"] == "probe"
+    assert activity["mod"] == mod
+    assert activity["doc"] == "One typed argument with a default value."
+    assert activity["arguments"] == [
+        {
+            "name": "message",
+            "default": "hello"
+        }
+    ]
+
+    activity = activities[5]
+    assert activity["name"] == "one_untyped_arg"
+    assert activity["type"] == "probe"
+    assert activity["mod"] == mod
+    assert activity["doc"] == "One untyped argument."
+    assert activity["arguments"] == [
+        {
+            "name": "message"
+        }
+    ]
+
+    activity = activities[6]
+    assert activity["name"] == "one_untyped_arg_with_default"
+    assert activity["type"] == "probe"
+    assert activity["mod"] == mod
+    assert activity["doc"] == "One untyped argument with a default value."
+    assert activity["arguments"] == [
+        {
+            "name": "message",
+            "default": "hello"
+        }
+    ]

pip install -e .[vault]
parse_log_pytest
requirements.txt
3.6
requirements.txt requirements-dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
-e git+https://github.com/chaostoolkit/chaostoolkit-lib.git@3656c8ec9185318d16f6ee7e0815bd9da52cad44#egg=chaostoolkit_lib
charset-normalizer==2.0.12
coverage==6.2
hvac==0.11.2
idna==3.10
importlib-metadata==4.8.3
iniconfig==1.1.1
logzero==1.7.0
packaging==21.3
pluggy==1.0.0
ply==3.4
py==1.11.0
pycodestyle==2.10.0
pyhcl==0.2.3
pyparsing==3.1.4
pytest==7.0.1
pytest-cov==4.0.0
pytest-sugar==0.9.6
requests==2.27.1
requests-mock==1.12.1
six==1.17.0
termcolor==1.1.0
tomli==1.2.3
typing_extensions==4.1.1
urllib3==1.26.20
zipp==3.6.0

name: chaostoolkit-lib
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - coverage==6.2
      - hvac==0.11.2
      - idna==3.10
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - logzero==1.7.0
      - packaging==21.3
      - pluggy==1.0.0
      - ply==3.4
      - py==1.11.0
      - pycodestyle==2.10.0
      - pyhcl==0.2.3
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pytest-sugar==0.9.6
      - requests==2.27.1
      - requests-mock==1.12.1
      - six==1.17.0
      - termcolor==1.1.0
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - zipp==3.6.0
prefix: /opt/conda/envs/chaostoolkit-lib

tests/test_discover.py::test_fail_discovery_when_module_cannot_be_loaded tests/test_discover.py::test_do_not_fail_when_extension_mod_has_not_all
tests/test_discover.py::test_discover_all_activities
CHANGELOG.md chaoslib/discovery/discover.py
CHANGELOG.md chaoslib/discovery/discover.py