diff --git a/examples/_misc/01walk/main.py b/examples/_misc/01walk/main.py
deleted file mode 100644
index e22cdcd..0000000
--- a/examples/_misc/01walk/main.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from __future__ import annotations
-import typing as t
-
-
-class Team:
-    name: str
-    members: t.List[Member]
-
-
-class Member:
-    name: str
-    team: Team
-
-
-def walk(w):
-    defs = {}
-    for cls in w.walk():
-        defs[cls.__name__] = {
-            name: str(typeinfo.raw) for name, typeinfo, _ in w.walk_fields(cls)
-        }
-    return defs
-
-
-if __name__ == "__main__":
-    import json
-    from metashape import runtime
-
-    print(
-        json.dumps(
-            {
-                "one": walk(runtime.get_walker(Team)),
-                "list": walk(runtime.get_walker([Team, Member])),
-                "with-recursive": walk(
-                    runtime.get_walker(
-                        [Team],
-                        config=runtime.Config(
-                            option=runtime.Config.Option(recursive=True)
-                        ),
-                    )
-                ),
-            },
-            indent=2,
-        )
-    )
diff --git a/examples/_misc/01walk/output.json b/examples/_misc/01walk/output.json
deleted file mode 100644
index 4af033a..0000000
--- a/examples/_misc/01walk/output.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "one": {
-    "Team": {
-      "name": "<class 'str'>",
-      "members": "typing.List[__main__.Member]"
-    }
-  },
-  "list": {
-    "Team": {
-      "name": "<class 'str'>",
-      "members": "typing.List[__main__.Member]"
-    },
-    "Member": {
-      "name": "<class 'str'>",
-      "team": "<class '__main__.Team'>"
-    }
-  },
-  "with-recursive": {
-    "Team": {
-      "name": "<class 'str'>",
-      "members": "typing.List[__main__.Member]"
-    },
-    "Member": {
-      "name": "<class 'str'>",
-      "team": "<class '__main__.Team'>"
-    }
-  }
-}
diff --git a/examples/_misc/Makefile b/examples/_misc/Makefile
index 55d553a..9b3eeff 100644
--- a/examples/_misc/Makefile
+++ b/examples/_misc/Makefile
@@ -1,6 +1,7 @@
-default: 00 01
+default: 00
 
 SHELL := $(shell which bash)
+
 # dataclasses support
 00:
 	# use class
@@ -10,7 +11,3 @@ SHELL := $(shell which bash)
 	# use dataclasses as member
 	python $@*/usedataclass/main.py > $$(echo $@*/)usedataclass/got.yaml 2>&1
 	dictknife diff $@*/want.yaml $@*/usedataclass/got.yaml > $$(echo $@*/)want-usedataclass.diff 2>&1
-
-# walk classes
-01:
-	python $(shell echo $@*/)main.py > $$(echo $@*/)output.json 2>&1
diff --git a/metashape/runtime.py b/metashape/runtime.py
index be8b2c2..eac7510 100644
--- a/metashape/runtime.py
+++ b/metashape/runtime.py
@@ -25,6 +25,8 @@ def get_walker(
     *,
     config: t.Optional[Config] = None,
     aggressive: bool = False,
+    recursive: bool = False,
+    sort: bool = False,
     only: t.Optional[t.List[str]] = None,
     _depth: int = 1,  # xxx: for black magic
 ) -> Walker:
@@ -75,8 +77,8 @@ def get_walker(
                     v.__name__ = name  # xxx TODO: use tx.Annotated
                 mark(v, kind=kind)
 
-    recursive = config.option.recursive
-    sort = config.option.sort
+    recursive = recursive or config.option.recursive
+    sort = sort or config.option.sort
 
     itr = sorted(d.items()) if sort else d.items()
     members = [v for _, v in itr if is_marked(v)]

get_walker with recursive and sort option
diff --git a/metashape/tests/test_walk.py b/metashape/tests/test_walk.py
new file mode 100644
index 0000000..954ef46
--- /dev/null
+++ b/metashape/tests/test_walk.py
@@ -0,0 +1,56 @@
+# type:ignore
+from __future__ import annotations
+import typing as t
+from metashape.runtime import get_walker
+
+
+class Team:
+    name: str
+    members: t.List[Member]
+
+
+class Member:
+    name: str
+    team: Team
+
+
+def _walk(w):
+    defs = {}
+    for cls in w.walk():
+        defs[cls.__name__] = {
+            name: str(typeinfo.raw) for name, typeinfo, _ in w.walk_fields(cls)
+        }
+    return defs
+
+
+def test_walk_one():
+    got = _walk(get_walker(Team))
+    want = {"Team": {"name": str(str), "members": str(t.List[Member])}}
+    assert want == got
+
+
+def test_walk_list():
+    got = _walk(get_walker([Team, Member]))
+    want = {
+        "Team": {"name": str(str), "members": str(t.List[Member])},
+        "Member": {"name": str(str), "team": str(Team)},
+    }
+    assert want == got
+
+
+def test_walk_one__with_recursive():
+    got = _walk(get_walker(Team, recursive=True))
+    want = {
+        "Team": {"name": str(str), "members": str(t.List[Member])},
+        "Member": {"name": str(str), "team": str(Team)},
+    }
+    assert want == got
+
+
+def test_walk_one__with_recursive2():
+    got = _walk(get_walker(Member, recursive=True))
+    want = {
+        "Team": {"name": str(str), "members": str(t.List[Member])},
+        "Member": {"name": str(str), "team": str(Team)},
+    }
+    assert want == got

pip install -e .[cli]
parse_log_pytest
pytest
pytest flake8 mypy
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
dictknife==0.14.1
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
flake8==7.2.0
inflection==0.5.1
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
Jinja2==3.1.6
json2python-models==0.3.1
magicalimport==0.9.1
MarkupSafe==3.0.2
mccabe==0.7.0
-e git+https://github.com/podhmo/metashape.git@8ba7e4c43b6a33aeaa15e34138a2728a5b340ca5#egg=metashape
mypy==1.15.0
mypy-extensions==1.0.0
ordered-set==4.1.0
packaging @ file:///croot/packaging_1734472117206/work
pluggy @ file:///croot/pluggy_1733169602837/work
prestring==0.9.0
pycodestyle==2.13.0
pyflakes==3.3.1
pytest @ file:///croot/pytest_1738938843180/work
python-dateutil==2.9.0.post0
six==1.17.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typing_extensions==4.13.0
Unidecode==1.3.8

name: metashape
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
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - 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=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - dictknife==0.14.1
      - flake8==7.2.0
      - inflection==0.5.1
      - jinja2==3.1.6
      - json2python-models==0.3.1
      - magicalimport==0.9.1
      - markupsafe==3.0.2
      - mccabe==0.7.0
      - mypy==1.15.0
      - mypy-extensions==1.0.0
      - ordered-set==4.1.0
      - prestring==0.9.0
      - pycodestyle==2.13.0
      - pyflakes==3.3.1
      - python-dateutil==2.9.0.post0
      - six==1.17.0
      - typing-extensions==4.13.0
      - unidecode==1.3.8
prefix: /opt/conda/envs/metashape

metashape/tests/test_walk.py::test_walk_one__with_recursive metashape/tests/test_walk.py::test_walk_one__with_recursive2
metashape/tests/test_walk.py::test_walk_one metashape/tests/test_walk.py::test_walk_list
examples/_misc/01walk/output.json examples/_misc/Makefile metashape/runtime.py examples/_misc/01walk/main.py
examples/_misc/01walk/output.json examples/_misc/Makefile metashape/runtime.py examples/_misc/01walk/main.py