let's update concept:

1. We remove the environment. All variables stay in context.
2. Playbook config should be valid yaml where some items can have valid jinja2 references or expressions.
3. We remove actions. 
4. workload is a embeded library of tasks. Task is the only unit block to be executed. If task has type default - and nor other attributes defined it's a placeholder of subtasks and possibly loop. Any task make have run attribute - which is a list of subtasks to be executed when the task is executed itself. It will pass result to subtasks especially if loop is defined.
5. Workflow is a conditional flow control of execution of the playbook. It has a list of steps. Each step has an optional attribute "when" that validates if step can be run if it was called. The first step in the list called first. It can have no reference to tasks, but just attribute "next" that can have a list of "when" conditions , each when has attribute "then" that routes flow to another step or steps - if it's a arrays of steps they called in parallel like a fork.
6. Each step may have a "run" attribute that is a sequence of tasks to execute. If task has name only, then the task name have to be looked up in workload in the workload's root level task list and be executed with subtasks if the task has any subtask.
7. Task or step may have a loop attribute that may have reference to the list that can be generated by jinja2 expression. loop has "in" attribute aht is a reference to the iterable item. and "iterator" attribute that defines variable name that task can refer to and subtask can use as well. 
8. Step can have a loop part as well-then what is defined in the "run" attribute of "step" will be executed in the order of loop items.
9. "until" attribute, I am not sure if we can put it to the loop, or outside of the loop. But the purpose of it is to break execution if condition that is defined in expression of "until" is matched.
10. "context", when we run a workflow, the context will be generated for the entire workflow. When we enter to steps—each step will generate it's own context based on input parameters and inhereted variable from the higher level of scope's context. When we enter to task - the new scope context will be created. When we enter to loop item new scope will be created for that level of scope of the task or step. 
11. A result will be generated of each of the scope level, and it can be referred by context scope or passed somehow. Let's think how we can describe it.
12. The config should be validated by ebnf and json schema that we will create.

here is an example of playbook:

```
apiVersion: noetl.io/v1
kind: Playbook
name: process_orders
path: workflows/orders/noetl_spec_example

context:
  jobId: "{{ job.uuid }}"
  state: pending
  region: us-west
  api_url: https://api.example.com/orders
  validation_url: https://api.example.com/validate
  audit_url: https://api.example.com/audit

workbook:
  - task: fetch_orders
    type: default
    loop:
      in: customers
      iterator: customer
    run:
      - task: "fetchData_{{ customer }}"
        type: http
        loop:
          in: result
          iterator: order
        method: GET
        desc: "Fetch orders for {{ customer }}"
        endpoint: "{{ environment.api_url }}/{{ customer }}"
        params:
          token: "{{ context.token }}"
        run:
          - task: "fetchOrder_{{ order }}"
            type: http
            loop:
              in: result
              iterator: order
            method: GET
            desc: "Fetch order details for {{ customer }}"
            endpoint: "{{ environment.api_url }}/{{ customer }}/orders/{{ order }}"
            params:
              token: "{{ context.token }}"

  - task: validate Data
    type: http
    method: POST
    desc: Validate the fetched orders
    endpoint: "{{ environment.validation_url }}"
    params:
      schema: orderSchema
      payload: "{{ results.fetch_orders }}"

workflow:
  - step: start
    next:
      - when: "{% results.fetch_orders is not none %}"
        then: [validate_data, validate_data2]
      - when: "{% results.fetch_orders is none %}"
        then: [validate_data2]
  - step: fetch_data
    when: "{% status == 'READY' %}"
    loop: 
      in: ['storeA', 'storeB']
      iterator: store
    until: "{% results.fetch_orders is not none %}"
    run:
      - task: fetch_orders
    next:
      - when: "{% results.fetch_orders is not none %}"
        then: [validate_data, validate_data2]
      - when: "{% results.fetch_orders is none  %}"
        then: [validate_data2]

  - step: validate_data
    when: "{% results.fetch_orders is not none %}"
    run:
      - task: validate_orders
      - task: audit_log
        type: http
        method: POST
        desc: Log validation results
        endpoint: "{{ environment.audit_url }}"
        params:
          step: validate_data

  - step: validate_data2
    when: "{% results.fetch_orders is not none %}"
    run:
      - task: validate_orders
      - task: audit_log
        type: http
        method: POST
        desc: Log validation results
        endpoint: "{{ environment.audit_url }}"
        params:
          step: validate_data
```    