diff --git a/CHANGELOG.md b/CHANGELOG.md
index 10cc6d337..89e5e4f11 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,8 +31,8 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s
 - Added `fields` option to the project 2d to support scalar rendering of specific fields.
 - Added `dataset_bounds` option to the project 2d, which can be used instead of a full 3D camera specification
 - Added support for triggers to execute actions from multiple files via an `actions_files` option that takes a list of actions files.
-- Added an `external_surfaces` transform filter, that can be used to reduce memory requriments in pipelines where you plan to only process the external faces of a data set. 
-
+- Added an `external_surfaces` transform filter, that can be used to reduce memory requirements in pipelines where you plan to only process the external faces of a data set. 
+- Added a `declare_fields` action, that allows users to explicitly list the fields to return for field filtering. This option avoids complex field parsing logic.
 
 ### Changed
 - Changed the replay utility's binary names such that `replay_ser` is now `ascent_replay` and `raplay_mpi` is now `ascent_replay_mpi`. This will help prevent potential name collisions with other tools that also have replay utilities. 
diff --git a/src/docs/sphinx/Actions/Scenes.rst b/src/docs/sphinx/Actions/Scenes.rst
index 5bb86eee8..99a03528e 100644
--- a/src/docs/sphinx/Actions/Scenes.rst
+++ b/src/docs/sphinx/Actions/Scenes.rst
@@ -15,7 +15,7 @@ A scene defined in this way uses the default data source, which is all of the da
 
 Default Images
 --------------
-When creating a scene, Ascent will set up camera and color table defualts.
+When creating a scene, Ascent will set up camera and color table defaults.
 The only requirement is that either a ``image_name`` or ``image_prefix``
 be provided. Minimally, a scene consists of one plot and a parameter
 to specify the output file name. Default images images have a resolution
@@ -45,7 +45,7 @@ within the image prefix. Assuming the cycle is ``10``, here are some examples:
 
 Image Name
 ^^^^^^^^^^
-The ``image_name`` parameter speficies the excact file name of the of the output
+The ``image_name`` parameter specifies the exact file name of the of the output
 image, and Ascent will append the ``.png`` to the image file name. If not changed,
 the image file will be overwritten.
 
@@ -58,13 +58,11 @@ Plots optionally consume the result of a pipeline, but if none is specified, the
 Each scene can contain one or more plots.
 The plot interface is simply:
 
-.. code-block:: json
+.. code-block:: yaml
 
-  {
-    "type"   : "plot_name",
-    "pipeline" : "pipeline_name",
-    "field" : "field_name"
-  }
+    type: "plot_name"
+    pipeline: "pipeline_name"
+    field: "field_name"
 
 In c++, the equivalent declarations would be as follows:
 
@@ -384,33 +382,25 @@ Now we add a second render to the same example using every available parameter:
   scenes["s1/renders/r2/camera/near_plane"] = 0.1;
   scenes["s1/renders/r2/camera/far_plane"] = 33.1;
 
-.. code-block:: json
-
-  {
-  "renders":
-  {
-    "r1":
-    {
-      "image_width": 300,
-      "image_height": 400,
-      "image_name": "some_image",
-      "camera":
-      {
-        "look_at": [1.0, 1.0, 1.0],
-        "position": [0.0, 25.0, 15.0],
-        "up": [0.0, -1.0, 0.0],
-        "fov": 60.0,
-        "xpan": 0.0,
-        "ypan": 0.0,
-        "elevation": 10.0,
-        "azimuth": -10.0,
-        "zoom": 0.0,
-        "near_plane": 0.1,
-        "far_plane": 100.1
-      }
-    }
-  }
-  }
+.. code-block:: yaml
+
+  renders:
+    r1:
+      image_width: 300
+      image_height: 400
+      image_name: "some_image"
+      camera:
+        look_at: [1.0, 1.0, 1.0]
+        position: [0.0, 25.0, 15.0]
+        up: [0.0, -1.0, 0.0]
+        fov: 60.0
+        xpan: 0.0
+        ypan: 0.0
+        elevation: 10.0,
+        azimuth: -10.0,
+        zoom: 0.0
+        near_plane: 0.1
+        far_plane: 100.1
 
 
 Additional Render Options
diff --git a/src/docs/sphinx/AscentAPI.rst b/src/docs/sphinx/AscentAPI.rst
index c39667c47..15124377c 100644
--- a/src/docs/sphinx/AscentAPI.rst
+++ b/src/docs/sphinx/AscentAPI.rst
@@ -21,16 +21,16 @@ open
 Open provides the initial setup of Ascent from a Conduit Node.
 Options include runtime type (e.g., ascent, flow, or empty) and associated backend if available.
 If running in parallel (i.e., MPI), then a MPI comm handle must be supplied.
-Ascent will always check the file system for a file called ``ascent_options.json`` that will override compiled in options, and for obvious reasons, a MPI communicator cannot be specified in the file.
+Ascent will always check the file system for a file called ``ascent_options.yaml`` that will override compiled in options, and for obvious reasons, a MPI communicator cannot be specified in the file.
 Here is a file that would set the runtime to the main ascent runtime using a OpenMP backend (inside VTK-m):
 
 
-.. code-block:: json
+.. code-block:: yaml
 
-  {
-    "runtime/type"    : "ascent",
-    "runtime/vtkm/backend" : "openmp"
-  }
+  runtime:
+    type: "ascent"
+    vtkm:
+      backend: "openmp"
 
 Example Options
 """""""""""""""
@@ -53,19 +53,18 @@ A typical integration will include the following code:
 Default Directory
 """""""""""""""""
 By default, Ascent will output files in the current working directory.
-This can be overrided by specifying the ``default_dir``. This directory
+This can be overridden by specifying the ``default_dir``. This directory
 must be a valid directory, i.e., Ascent will not create this director for
 you. Many Ascent filters have parameters that specify output files, and Ascent
-will only place files that do not have an absolue path specified.
+will only place files that do not have an absolute path specified.
 For example, the ``my_image`` would be written to the default directory, but
 ``/some/other/path/my_image`` would be written in the directory
 ``/some/other/path/``.
 
-.. code-block:: json
+.. code-block:: yaml
+
+  default_dir: "/path/to/output/dir"
 
-  {
-    "default_dir" : "/path/to/output/dir"
-  }
 
 High Order Mesh Refinement
 """"""""""""""""""""""""""
@@ -76,13 +75,12 @@ high-order elements are discretized into many linear elements. The minimum value
 is ``1``, i.e., no refinement. There is a memory-accuracy trade-off when using refinement.
 The higher the value,
 the more accurate the low-order representation is, but more discretization means more memory
-usage and more time tp process the additional elements.
+usage and more time to process the additional elements.
+
+.. code-block:: yaml
 
-.. code-block:: json
+  refinement_level: 4
 
-  {
-    "refinement_level" : 4
-  }
 
 Runtime Options
 """""""""""""""
@@ -125,7 +123,7 @@ There are often warnings and other information that can indicate potential issue
     -  ``catch`` Catches conduit::Error exceptions at the Ascent interface and prints info about the error to standard out.
        This case this provides an easy way to prevent host program crashes when something goes wrong in Ascent.
 
-By default, Ascent looks for a file called ``ascent_actions.json`` that can append additional actions at runtime.
+By default, Ascent looks for a file called ``ascent_actions.yaml`` that can append additional actions at runtime.
 This default file name can be overridden in the Ascent options:
 
 .. code-block:: c++
@@ -147,11 +145,10 @@ Filter Timings
 Ascent has internal timings for filters. The timings output is one csv file
 per MPI rank.
 
-.. code-block:: json
+.. code-block:: yaml
+
+  timings : "true"
 
-  {
-    "timings" : "true"
-  }
 
 
 Field Filtering
@@ -162,19 +159,23 @@ publish 100s of variables to Ascent. In this case, its undesirable to
 use all fields when the actions only need a single variable. This reduces
 the memory overhead Ascent uses.
 
+
+.. code-block:: yaml
+
+  field_filtering : "true"
+
+
 Field filtering scans the user's actions to identify what fields are required,
 only passing the required fields into Ascent. However, there are several
-actions where the required fields cannot be resolved. For example, saving simulation
-data to the file system saves all fields, and in this case, it is not possible to resolve
-the required fields. If field filtering encounters this case, then an error is generated.
-Alternatively, if the actions specify which fields to save, then this field filtering
-can resolve the fields.
+actions where the required fields cannot be resolved. To support field filtering
+for all cases, we added support for action ``declare_fields`` that allows a user
+to explicitly control the list of active fields.
 
-.. code-block:: json
+.. code-block:: yaml
 
-  {
-    "field_filtering" : "true"
-  }
+  -
+   action: "declare_fields"
+   fields: ["my_field", "my_other_field", ...]
 
 
 
@@ -263,7 +264,7 @@ Here is a simple example of adding a plot using the C++ API:
 
 info
 ----
-Info populates a conduit Node with infomation about Ascent including runtime execution and outputted results.
+Info populates a conduit Node with information about Ascent including runtime execution and outputted results.
 This information can be used to return data back to the simulation and for debugging purposes.
 
 .. code-block:: c++
diff --git a/src/docs/sphinx/developer_docs/Flow_Filter.rst b/src/docs/sphinx/developer_docs/Flow_Filter.rst
index cf5795f9a..af22fc8b9 100644
--- a/src/docs/sphinx/developer_docs/Flow_Filter.rst
+++ b/src/docs/sphinx/developer_docs/Flow_Filter.rst
@@ -103,18 +103,15 @@ interface looks like this in c++:
     filter["params/double_param"] = 2.0;
 
 
-or equivalently in json:
+or equivalently in yaml:
 
-.. code-block:: json
+.. code-block:: yaml
+
+  type: "filter_name"
+  params:
+    string_param: "string"
+    double_param: 2.0
 
-    {
-      "type"   : "filter_name",
-      "params":
-      {
-        "string_param" : "string",
-        "double_param" : 2.0
-      }
-    }
 
 The Ascent runtime looks for the ``params`` node and passes it to the filter
 upon creation. Parameters are verified when the filter is created during execution.
@@ -288,17 +285,17 @@ is where all builtin filter are registered. Following the NoOp example:
 
 Filter registration is templated on the filter type and takes two arguments.
 
-* arg1: the type of the fitler. Valid values are ``transforms`` and ``extracts``
+* arg1: the type of the filter. Valid values are ``transforms`` and ``extracts``
 * arg2: the front-facing API name of the filter. This is what a user would declare in an actions file.
 
 Accessing Metadata
 ------------------
-We currently populate a limited set of metadata that is accessable to flow filters.
+We currently populate a limited set of metadata that is accessible to flow filters.
 We place a Conduit node containing the metadata inside the registry which can be
 accessed in the following manner:
 
 .. code-block:: c++
-    :caption: Accessing the regsitry metadata inside a flow filter
+    :caption: Accessing the registry metadata inside a flow filter
 
     conduit::Node * meta = graph().workspace().registry().fetch<Node>("metadata");
     int cycle = -1;
diff --git a/src/libs/ascent/runtimes/ascent_main_runtime.cpp b/src/libs/ascent/runtimes/ascent_main_runtime.cpp
index 0e445cea1..7076d1395 100644
--- a/src/libs/ascent/runtimes/ascent_main_runtime.cpp
+++ b/src/libs/ascent/runtimes/ascent_main_runtime.cpp
@@ -1946,6 +1946,11 @@ AscentRuntime::BuildGraph(const conduit::Node &actions)
         // the workspace executes.
         m_save_info_actions.append() = action;
       }
+      else if(action_name == "declare_fields")
+      {
+        // Used with field filtering, we don't need
+        // to process as part of exec
+      }
       else if(action_name == "open_log")
       {
         // Open Ascent Logging Stream
diff --git a/src/libs/ascent/utils/ascent_actions_utils.cpp b/src/libs/ascent/utils/ascent_actions_utils.cpp
index 3f326f6e6..f78455489 100644
--- a/src/libs/ascent/utils/ascent_actions_utils.cpp
+++ b/src/libs/ascent/utils/ascent_actions_utils.cpp
@@ -174,11 +174,36 @@ void filter_fields(const conduit::Node &node,
                    std::set<std::string> &fields,
                    conduit::Node &info)
 {
+
   const int num_children = node.number_of_children();
   const std::vector<std::string> names = node.child_names();
   for(int i = 0; i < num_children; ++i)
   {
     const conduit::Node &child = node.child(i);
+
+    // to avoid complex parsing, we added a shortcut case
+    // action: `declare_fields`
+    // fields: ["field1", "field2", .... "fieldN-1"]
+
+    if(child.has_child("action") && child.has_child("fields"))
+    {
+        if(child["action"].as_string() == "declare_fields")
+        {
+            const Node fields_list = child["fields"];
+            const int num_entries = child.number_of_children();
+            for(int e = 0; e < num_entries;  e++)
+            {
+                const conduit::Node &item = child.child(e);
+                if(item.dtype().is_string())
+                {
+                    fields.insert(item.as_string());
+                }
+            } // for list  entries
+            // early return, user needs to provide a definitive list
+            return;
+        }
+    }
+
     bool is_leaf = child.number_of_children() == 0;
     if(is_leaf)
     {
diff --git a/src/tests/ascent/t_ascent_runtime_options.cpp b/src/tests/ascent/t_ascent_runtime_options.cpp
index 501f0a53d..56b48438f 100644
--- a/src/tests/ascent/t_ascent_runtime_options.cpp
+++ b/src/tests/ascent/t_ascent_runtime_options.cpp
@@ -743,9 +743,9 @@ TEST(ascent_runtime_options, test_field_filtering_ghosts)
                                               EXAMPLE_MESH_SIDE_DIM,
                                               data);
 
-    // add a ghost field 
+    // add a ghost field
     data["fields/ascent_ghosts"].set(data["fields/radial"]);
-    
+
     float64_array gvals = data["fields/ascent_ghosts/values"].value();
     for(int i=0; i < gvals.number_of_elements(); i++)
     {
@@ -1101,7 +1101,7 @@ TEST(ascent_runtime_options, test_field_filtering_binning_filter)
     ascent.open(ascent_opts);
     ascent.publish(data);
     ascent.execute(actions);
-    
+
     EXPECT_TRUE(check_test_image(output_file, 0.1));
 }
 
@@ -1166,3 +1166,66 @@ TEST(ascent_runtime_options, test_field_filtering_lineout)
     ascent.publish(data);
     ascent.execute(actions);
 }
+
+
+
+//-----------------------------------------------------------------------------
+TEST(ascent_runtime_options, test_field_filtering_new)
+{
+    Node n;
+    ascent::about(n);
+    // only run this test if ascent was built with vtkm support
+    if(n["runtimes/ascent/vtkm/status"].as_string() == "disabled")
+    {
+        ASCENT_INFO("Ascent vtkm support disabled, skipping test");
+        return;
+    }
+
+    //
+    // Create an example mesh.
+    //
+    Node data, verify_info;
+    conduit::blueprint::mesh::examples::braid("hexs",
+                                              EXAMPLE_MESH_SIDE_DIM,
+                                              EXAMPLE_MESH_SIDE_DIM,
+                                              EXAMPLE_MESH_SIDE_DIM,
+                                              data);
+    EXPECT_TRUE(conduit::blueprint::mesh::verify(data,verify_info));
+
+    string output_path = prepare_output_dir();
+    std::string output_base =
+      conduit::utils::join_file_path(output_path, "tout_ascent_field_filtering_new_style");
+
+    remove_test_image(output_base);
+
+    ASCENT_INFO("Testing field filtering new style");
+
+    // test option to pre-declare field names
+
+    std::string acts_str = R"xyzxyz(
+    -
+      action: "declare_fields"
+      fields: ["braid","radial"]
+    -
+      action: "add_extracts"
+      extracts:
+        e1:
+          type: "relay"
+          params:
+            protocol: "blueprint/mesh/hdf5"
+)xyzxyz";
+    conduit::Node actions;
+    actions.parse(acts_str,"yaml");
+    actions[1]["extracts/e1/params/path"] = output_base;
+
+    Ascent ascent;
+    Node ascent_opts;
+    ascent_opts["runtime/type"] = "ascent";
+    ascent_opts["field_filtering"] = "true";
+    ascent_opts["exceptions"] = "forward";
+    ascent.open(ascent_opts);
+    ascent.publish(data);
+    ascent.execute(actions);
+    ascent.close();
+
+}