Understanding the CNCF Execution Model Through HelloWorld

ASAMI, Tomoharu Created: 2026-01-26

SimpleModeling is a development methodology based on component-oriented principles. To make component-oriented development viable, an execution system for components is required in addition to the definition of conceptual models. For this purpose, the Cloud Native Component Framework (CNCF) has been developed as a component framework for cloud applications that run on cloud platforms.

In this article, we will explore the execution model of the Cloud Native Component Framework through a HelloWorld example.

HelloWorld

The shortest path to understanding the Cloud Native Component Framework is to actually run it first.

In CNCF, differences in execution forms such as command, server, client, and script do not imply different applications. They all simply execute the same Component / Service / Operation through different invocation protocols.

In this HelloWorld demo, we will walk through the following steps to confirm this core philosophy of CNCF.

  • Define the HelloWorld component

  • Build and deploy the HelloWorld component

  • Observe how the same functionality is invoked from command, server, and client

Script

In 📄 Cloud Native Component Framework:HelloWorld, the following script is prepared to run a program on CNCF.

#!/usr/bin/env -S scala-cli shebang
//> using repository "https://www.simplemodeling.org/maven"
//> using dep "org.goldenport:goldenport-cncf_3:0.3.2"
import org.goldenport.cncf.dsl.script.*
@main def main(args: String*): Unit = run(args) { call =>
  "hello world"
}

This script is written using a DSL prepared specifically for script-oriented usage. At first glance, it may appear to simply describe a procedure that returns a string, but internally the following processes are performed.

  • The entire script is generated as a single component

  • That component has one service and one operation

  • The script’s processing body is registered as the implementation of that operation

  • It is executed on the CNCF runtime in the same way as a regular component

In other words, although this script is written using a simplified notation, formal component generation and execution are actually taking place.

The call passed to the run block is an object of type org.goldenport.cncf.action.ActionCall. Through this ActionCall, the following capabilities are available.

  • Retrieving arguments

  • Generating responses

  • Accessing the CNCF execution context

For very simple processing, the script feature is sufficient; however, when you want to make the structure explicit or define multiple services and operations, you should use a formal component definition, which is the main theme of this article.

Component

Below is an example that implements the same HelloWorld functionality as the script, but as a formal CNCF component.

Using this source file together with the build.sbt shown next, you can set up the build environment for the component.

package example
import org.goldenport.Consequence
import org.goldenport.protocol.*
import org.goldenport.protocol.operation.*
import org.goldenport.protocol.spec.*
import org.goldenport.cncf.component.*
import org.goldenport.cncf.action.*
class HelloWorldComponent extends Component {
}
object HelloWorldComponent {
  val name = "helloworld"
  val componentId = ComponentId(name)
  class Factory extends Component.Factory {
    protected def create_Components(params: ComponentCreate): Vector[Component] =
      Vector(HelloWorldComponent())
    protected def create_Core(
      params: ComponentCreate,
      comp: Component
    ): Component.Core = spec_create(
      name,
      componentId,
      GreetingService
    )
  }
}
object GreetingService extends ServiceDefinition {
  val specification = ServiceDefinition.Specification.Builder("greeting").
    operation(
      HelloOperation
    ).build()

  object HelloOperation extends OperationDefinition {
    val specification = OperationDefinition.Specification.Builder("hello").
      build()
    override def createOperationRequest(
      req: Request
    ): Consequence[HelloQuery] =
      Consequence.success(HelloQuery(req))
  }
}
final case class HelloQuery(
  request: Request
) extends Query() {
  override def createCall(core: ActionCall.Core): ActionCall =
    HelloActionCall(core, this)
}
final case class HelloActionCall(
  core: ActionCall.Core,
  query: HelloQuery,
) extends ActionCall {
  override def execute(): Consequence[OperationResponse] = {
    val greeting = args(0)
    response_string(s"Hello $greeting")
  }
}

build.sbt

The build.sbt for the Scala project is shown below.

The only direct library dependency is CNCF itself.

ThisBuild / scalaVersion := "3.3.7"
ThisBuild / organization := "org.example"
ThisBuild / version      := "0.1.0"
lazy val root = (project in file("."))
  .settings(
    name := "cncf-helloworld-sbt",
    libraryDependencies ++= Seq(
      // CNCF core runtime
      "org.goldenport" %% "goldenport-cncf" % "0.3.4"
    )
  )

Build

We create a standard Scala project structure. HelloWorldComponent.scala and build.sbt are arranged as shown below.

.
├── build.sbt
└── src
    └── main
        └── scala
            └── example
                └── HelloWorldComponent.scala

The build is completed using the sbt package command.

$ sbt package

The JAR file that serves as the physical artifact of the component, target/scala-3.3.7/cncf-helloworld-sbt_3-0.1.0.jar, is generated.

Deployment

In this example, we deploy and use the created component with CNCF distributed via Docker.

When a component.d directory exists under the directory where CNCF is launched, CNCF recognizes it as a component repository and performs component deployment and startup.

Here, the /tmp/cncf-demo directory is used as the demo directory.

In this setup, the generated JAR file is copied into the component.d directory under the demo directory. With this, the deployment is complete.

$ cp target/scala-3.3.7/cncf-helloworld-sbt_3-0.1.0.jar /tmp/cncf-demo/component.d

Explanation

In the previous section, we showed the entire source code that implements the component. From here, we will explain its internal structure.

Component Declaration

A component is a class that extends org.goldenport.cncf.Component. By doing so, the responsibilities of a Component are automatically applied.

Below, we define the HelloWorldComponent.

class HelloWorldComponent extends Component {
}

Component Initialization

Components are created and initialized by a factory class that extends org.goldenport.cncf.Component.Factory.

Factory classes are automatically discovered from among the classes bundled in the JAR file.

Here, the factory for HelloWorldComponent is defined within its companion object.

object HelloWorldComponent {
  val name = "helloworld"
  val componentId = ComponentId(name)
  object Factory extends Component.Factory {
    protected def create_Components(params: ComponentCreate): Vector[Component] =
      Vector(HelloWorldComponent())
    protected def create_Core(
      params: ComponentCreate,
      comp: Component
    ): Component.Core = spec_create(
      name,
      componentId,
      GreetingService
    )
  }
}

The Factory performs the following tasks.

  • Creating the component

  • Assigning the component ID

  • Registering the provided service definition (GreetingService)

Through the factory’s operation, a component named helloworld is created.

Service Definition

The greeting service of the helloworld component is defined as GreetingService.

Within the GreetingService object, the greeting service is defined, and the hello operation is defined by HelloOperation.

object GreetingService extends ServiceDefinition {
  val specification = ServiceDefinition.Specification.Builder("greeting").
    operation(
      HelloOperation
    ).build()

  object HelloOperation extends OperationDefinition {
    val specification = OperationDefinition.Specification.Builder("hello").
      build()
    override def createOperationRequest(
      req: Request
    ): Consequence[HelloQuery] =
      Consequence.success(HelloQuery(req))
  }
}

HelloOperation provides the createOperationRequest method. In the createOperationRequest method, a HelloQuery—an action of HelloWorldComponent—is constructed from the Request.

With this definition, the following hierarchical structure is established.

  • Component: helloworld

  • Service: greeting

  • Operation: hello

In CNCF, command names, HTTP paths, OpenAPI operationIds, and similar identifiers are consistently derived from this structure.

Command and Query

In CNCF, org.goldenport.cncf.action.Action represents an execution instruction directed at a component. There are two kinds of Action—Command and Query—and each behaves according to its role within the CQRS architecture.

Here, a Query called HelloQuery is defined.

final case class HelloQuery(
  request: Request
) extends Query() {
  override def createCall(core: ActionCall.Core): ActionCall =
    HelloActionCall(core, this)
}

When an Operation is invoked, a Query is generated from the Request. The Query is responsible for creating an ActionCall that actually executes the processing.

An ActionCall is the object that performs the execution, and at creation time various required objects—such as the execution context—are bound to it.

Execution

We define HelloActionCall as the ActionCall that performs the processing of the hello operation in the greeting service of the helloworld component.

final case class HelloActionCall(
  core: ActionCall.Core,
  query: HelloQuery,
) extends ActionCall {
  override def execute(): Consequence[OperationResponse] = {
    val greeting = args(0)
    response_string(s"Hello $greeting")
  }
}

The execute method of ActionCall is the actual processing body. Here, it retrieves arguments and returns a string response.

Component Execution Environment

As the component execution environment, we use Docker and Coursier in this example.

Docker

By using Docker, CNCF can be executed even in environments without a Scala development setup. Docker is assumed to be used in typical production environments.

Using Docker, we start the CNCF Docker image.

$ docker run --rm \
  -v ./component.d:/app/component.d \
  goldenport-cncf:0.3.4 \
  {CNCF Parameters}

In the CNCF Docker image, Components deployed under /app/component.d are automatically loaded and started inside the container. Here, the ./component.d directory in the execution directory is mounted to /app/component.d.

Crousier

Crousier is a package manager in the Scala ecosystem. You can launch Scala programs using the launch command. In this example, we use the launch command.

When using CNCF with Crousier, you need to configure the repository where CNCF is registered. Here, we register it using environment variables.

$ export COURSIER_REPOSITORIES="ivy2local|central|https://www.simplemodeling.org/maven"

When running CNCF with Crousier, it looks as follows using the cs command.

$ cs launch org.goldenport:goldenport-cncf_3:0.3.4 -- \
  {CNCF Parameters}

Command Execution

When the command command is specified, CNCF starts in command mode and executes the specified operation.

Docker

The hello operation of the greeting service in the helloworld component is invoked with the argument world. As a result, the string “hello world” is output.

$ docker run --rm \
  -v ./component.d:/app/component.d \
  goldenport-cncf:0.3.4 \
  command helloworld.greeting.hello world
Hello world

Crousier

The behavior is the same when using Coursier.

$ cs launch org.goldenport:goldenport-cncf_3:0.3.4 -- \
  command helloworld.greeting.hello world
Hello world

Server Execution

We run CNCF as a server.

Docker

When starting a CNCF container with Docker and specifying the server command, CNCF starts up as a server.

$ docker run --rm \
  -p 8080:8080 \
  goldenport-cncf:0.3.4 \
  server
event=info scope=Subsystem name=cncf started [traceId=test-runtime-trace-2026012303353640+0000-4Lvl93R0LMlX7niKgXfbup correlationId=test-runtime-correlation-2026012303353640+0000-6RzUJdp4Xsz1giTcu39f57]
[io-compute-4] INFO org.http4s.ember.server.EmberServerBuilderCompanionPlatform - Ember-Server service bound to address: [::]:8080

Crousier

The behavior is the same when using Coursier.

When using cs, specifying the server command also starts CNCF as a server.

$ cs launch org.goldenport:goldenport-cncf_3:0.3.4 -- server
event=info scope=Subsystem name=Bootstrap [component-dir] initialized component=helloworld class=example.HelloWorldComponent [traceId=Bootstrap-Subsystem-trace-2026012303361455+0000-Ax1FoLKpMqlMIl5pVoXzc]
event=info scope=Subsystem name=cncf started [traceId=test-runtime-trace-2026012303361456+0000-5SlbZLKLXywlYUOdSGoye0 correlationId=test-runtime-correlation-2026012303361456+0000-4f4UKRnWCGdB1ZbrGPNwG9]
[io-compute-3] INFO org.http4s.ember.server.EmberServerBuilderCompanionPlatform - Ember-Server service bound to address: [::]:8080

Verification

In all cases, you can verify the REST behavior using the curl command.

$ curl http://localhost:8080/helloworld/greeting/hello?arg1=world
Hello world

OpenAPI

An OpenAPI specification is also automatically generated from the component definition.

$ curl http://localhost:8080/openapi.json | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  5200  100  5200    0     0   551k      0 --:--:-- --:--:-- --:--:--  564k
{
  "openapi": "3.0.0",
  "info": {
    "title": "CNCF API",
    "version": "0.1.0"
  },
  "paths": {
    "/admin/component/list": {
      "GET": {
        "tags": [
          "experimental:admin.component"
        ],
        "summary": "admin.component.list",
        "description": "Component: admin\nService: component\nOperation: list\n(experimental; subject to change in Phase 2.8)",
        "operationId": "admin.component.list",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/admin/config/show": {
      "GET": {
        "tags": [
          "experimental:admin.config"
        ],
        "summary": "admin.config.show",
        "description": "Component: admin\nService: config\nOperation: show\n(experimental; subject to change in Phase 2.8)",
        "operationId": "admin.config.show",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/admin/extension/list": {
      "GET": {
        "tags": [
          "experimental:admin.extension"
        ],
        "summary": "admin.extension.list",
        "description": "Component: admin\nService: extension\nOperation: list\n(experimental; subject to change in Phase 2.8)",
        "operationId": "admin.extension.list",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/admin/system/ping": {
      "GET": {
        "tags": [
          "experimental:admin.system"
        ],
        "summary": "admin.system.ping",
        "description": "Component: admin\nService: system\nOperation: ping\n(experimental; subject to change in Phase 2.8)",
        "operationId": "admin.system.ping",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/admin/variation/list": {
      "GET": {
        "tags": [
          "experimental:admin.variation"
        ],
        "summary": "admin.variation.list",
        "description": "Component: admin\nService: variation\nOperation: list\n(experimental; subject to change in Phase 2.8)",
        "operationId": "admin.variation.list",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/client/http/get": {
      "GET": {
        "tags": [
          "experimental:client.http"
        ],
        "summary": "client.http.get",
        "description": "Component: client\nService: http\nOperation: get\n(experimental; subject to change in Phase 2.8)",
        "operationId": "client.http.get",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/client/http/post": {
      "POST": {
        "tags": [
          "experimental:client.http"
        ],
        "summary": "client.http.post",
        "description": "Component: client\nService: http\nOperation: post\n(experimental; subject to change in Phase 2.8)",
        "operationId": "client.http.post",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/debug/http/delete": {
      "GET": {
        "tags": [
          "experimental:debug.http"
        ],
        "summary": "debug.http.delete",
        "description": "Component: debug\nService: http\nOperation: delete\n(experimental; subject to change in Phase 2.8)",
        "operationId": "debug.http.delete",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/debug/http/echo": {
      "GET": {
        "tags": [
          "experimental:debug.http"
        ],
        "summary": "debug.http.echo",
        "description": "Component: debug\nService: http\nOperation: echo\n(experimental; subject to change in Phase 2.8)",
        "operationId": "debug.http.echo",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/debug/http/get": {
      "GET": {
        "tags": [
          "experimental:debug.http"
        ],
        "summary": "debug.http.get",
        "description": "Component: debug\nService: http\nOperation: get\n(experimental; subject to change in Phase 2.8)",
        "operationId": "debug.http.get",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/debug/http/post": {
      "POST": {
        "tags": [
          "experimental:debug.http"
        ],
        "summary": "debug.http.post",
        "description": "Component: debug\nService: http\nOperation: post\n(experimental; subject to change in Phase 2.8)",
        "operationId": "debug.http.post",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/debug/http/put": {
      "PUT": {
        "tags": [
          "experimental:debug.http"
        ],
        "summary": "debug.http.put",
        "description": "Component: debug\nService: http\nOperation: put\n(experimental; subject to change in Phase 2.8)",
        "operationId": "debug.http.put",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/helloworld/greeting/hello": {
      "GET": {
        "tags": [
          "experimental:helloworld.greeting"
        ],
        "summary": "helloworld.greeting.hello",
        "description": "Component: helloworld\nService: greeting\nOperation: hello\n(experimental; subject to change in Phase 2.8)",
        "operationId": "helloworld.greeting.hello",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/spec/export/openapi": {
      "GET": {
        "tags": [
          "experimental:spec.export"
        ],
        "summary": "spec.export.openapi",
        "description": "Component: spec\nService: export\nOperation: openapi\n(experimental; subject to change in Phase 2.8)",
        "operationId": "spec.export.openapi",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  }
}

This includes all operations provided by CNCF, including the HelloWorld endpoint.

Client Execution

When the client command is specified, CNCF starts in command mode, sends the specified operation to the server, receives the execution result from the server, and outputs it.

Docker

Below, the hello operation of the greeting service in the helloworld component is invoked with the argument world. As a result, the string “hello world” is output.

$ docker run --rm \
  -v ./component.d:/app/component.d \
  goldenport-cncf:0.3.4 \
  command helloworld.greeting.hello world
Hello world

Crousier

The behavior is the same when using Coursier.

$ cs launch org.goldenport:goldenport-cncf_3:0.3.4 -- \
  client helloworld.greeting.hello world
Hello world

Summary

Even in a very small example like HelloWorld, CNCF always executes it

as a component that has this three-layer structure.

Differences in execution forms such as script, command, server, and client are not differences in the essence of the processing, but merely differences in which entry point is used to invoke the same operation.

With this structure, features such as OpenAPI generation, CLI execution, and HTTP API provisioning are all provided from a single, consistent model.

HelloWorld is the minimal example, but the structure confirmed here can be directly extended to production-level component design.

References

Glossary

Cloud Native Component Framework (CNCF)

Cloud Native Component Framework (CNCF) is a framework for executing cloud application components using a single, consistent execution model. Centered on the structure of Component, Service, and Operation, it enables the same Operation to be reused across different execution forms such as command, server (REST / OpenAPI), client, and script. By centralizing quality attributes required for cloud applications—such as logging, error handling, configuration, and deployment—within the framework, components can focus on implementing domain logic. CNCF is designed as an execution foundation for literate model-driven development and AI-assisted development, separating what is executed from how it is invoked.

Component

A software construct that encapsulates well-defined responsibilities, contracts, and dependencies as a reusable and replaceable unit. In the logical model, it serves as an abstract structural unit; in the physical model, it corresponds to an implementation or deployment unit.

DSL (Domain Specific Language)

A DSL (Domain-Specific Language) is a language designed for a particular domain, enabling direct and concise expression of the domain’s concepts and structures. Compared to general-purpose programming languages (GPLs), DSLs offer a higher level of abstraction tailored for domain-specific problem solving and automation.